@@ -74,110 +74,26 @@ export class Lcd {
74
74
75
75
if ( wasLcdEnabled && ! Lcd . enabled ) {
76
76
// Disable the LCD
77
- resetLcd ( true ) ;
77
+ _resetLcd ( true ) ;
78
78
}
79
79
80
80
if ( ! wasLcdEnabled && Lcd . enabled ) {
81
81
// Re-enable the LCD
82
- resetLcd ( false ) ;
82
+ _resetLcd ( false ) ;
83
83
}
84
84
}
85
85
86
- // Cycle getters for scanlines
87
- // (NOTE: One scanline is 456 cycles. Thus, they should add to 456)
88
- // TODO: Optimize this, so that double speed updates all cycle constants
89
- // Rather than re-calculating every time
90
-
91
- // Hblank
92
- static MODE_0_CYCLES ( ) : i32 {
93
- return 204 << ( < i32 > Cpu . GBCDoubleSpeed ) ;
94
- }
95
-
96
- // OAM Search
97
- static MODE_2_CYCLES ( ) : i32 {
98
- return 80 << ( < i32 > Cpu . GBCDoubleSpeed ) ;
99
- }
100
-
101
- // Pixel Transfer
102
- static MODE_3_CYCLES ( ) : i32 {
103
- return 172 << ( < i32 > Cpu . GBCDoubleSpeed ) ;
104
- }
105
-
106
- static ;
107
- }
108
-
109
- function resetLcd ( shouldBlankScreen : boolean ) : void {
110
- // Reset scanline cycle counter
111
- Graphics . scanlineCycles = 0 ;
112
- Graphics . scanlineRegister = 0 ;
113
- eightBitStoreIntoGBMemory ( Graphics . memoryLocationScanlineRegister , 0 ) ;
114
-
115
- // Set to mode 0
116
- // https://www.reddit.com/r/EmuDev/comments/4w6479/gb_dr_mario_level_generation_issues/
117
- let lcdStatus : i32 = eightBitLoadFromGBMemory ( Lcd . memoryLocationLcdStatus ) ;
118
- lcdStatus = resetBitOnByte ( 1 , lcdStatus ) ;
119
- lcdStatus = resetBitOnByte ( 0 , lcdStatus ) ;
120
- Lcd . mode = 0 ;
121
-
122
- // Store the status in memory
123
- eightBitStoreIntoGBMemory ( Lcd . memoryLocationLcdStatus , lcdStatus ) ;
124
-
125
- // Blank the screen
126
- if ( shouldBlankScreen ) {
127
- for ( let i = 0 ; i < FRAME_SIZE ; ++ i ) {
128
- store < u8 > ( FRAME_LOCATION + i , 255 ) ;
129
- }
130
- }
131
- }
132
-
133
- function checkCoincidence ( lcdMode : i32 , lcdStatus : i32 ) : i32 {
134
- // Check for the coincidence flag
135
- // Need to check on every mode, and not just HBLANK, as checking on hblank breaks shantae, which checks on vblank
136
- if ( ( lcdMode === 0 || lcdMode === 1 ) && Graphics . scanlineRegister === Lcd . coincidenceCompare ) {
137
- lcdStatus = setBitOnByte ( 2 , lcdStatus ) ;
138
- if ( checkBitOnByte ( 6 , lcdStatus ) ) {
139
- requestLcdInterrupt ( ) ;
140
- }
141
- } else {
142
- lcdStatus = resetBitOnByte ( 2 , lcdStatus ) ;
143
- }
144
-
145
- return lcdStatus ;
146
- }
147
-
148
- export function updateLcd ( ) : void {
149
- // Get our current scanline, and lcd mode
150
- let scanlineRegister : i32 = Graphics . scanlineRegister ;
151
- let scanlineCycles : i32 = Graphics . scanlineCycles ;
152
- let lcdMode : i32 = Lcd . mode ;
153
-
154
- // Get our new LCD mode (if it is new)
155
- let newLcdMode : i32 = 0 ;
156
-
157
- // First check if we are in V-Blank
158
- if ( scanlineRegister >= 144 ) {
159
- // VBlank mode
160
- newLcdMode = 1 ;
161
- } else {
162
- // We are drawing scanlines
163
- // Get all of our cycles
164
- let mode2Cycles = Lcd . MODE_2_CYCLES ( ) ;
165
- let mode3Cycles = Lcd . MODE_3_CYCLES ( ) ;
166
- let mode0Cycles = Lcd . MODE_0_CYCLES ( ) ;
167
-
168
- if ( scanlineCycles > mode2Cycles + mode3Cycles ) {
169
- // We are in mode 0 Hblank
170
- newLcdMode = 0 ;
171
- } else if ( scanlineCycles > mode2Cycles ) {
172
- // We are in mode 3 Pixel Transfer
173
- newLcdMode = 3 ;
174
- } else {
175
- // We are in mode 2, OAM Search
176
- newLcdMode = 2 ;
86
+ // Function to set the LCD Mode, and do all the neccessary checks
87
+ // Modes:
88
+ // 0 or 00: H-Blank
89
+ // 1 or 01: V-Blank
90
+ // 2 or 10: Searching Sprites Atts
91
+ // 3 or 11: Transfering Data to LCD Driver
92
+ static setMode ( newLcdMode : i32 ) : void {
93
+ if ( Lcd . mode === newLcdMode ) {
94
+ return ;
177
95
}
178
- }
179
96
180
- if ( lcdMode !== newLcdMode ) {
181
97
// Get our lcd status
182
98
let lcdStatus : i32 = eightBitLoadFromGBMemory ( Lcd . memoryLocationLcdStatus ) ;
183
99
@@ -221,17 +137,55 @@ export function updateLcd(): void {
221
137
if ( shouldRequestInterrupt ) {
222
138
requestLcdInterrupt ( ) ;
223
139
}
140
+ }
141
+
142
+ // Function to check the coincidence flag for every scanline
143
+ // NOTE: Need to check on every mode, and not just HBLANK, as checking on hblank breaks shantae, which checks on vblank
144
+ // NOTE: Games like Pokemon crystal want the vblank right as it turns to the value, and not have it increment after
145
+ // It will break and lead to an infinite loop in crystal
146
+ // Therefore, we want to be checking/Setting our LCD status after the scanline updates
147
+ // NOTE: Special Case, need to check LYC
148
+ // Fix prehistorik man freeze
149
+ static checkCoincidence ( ) : void {
150
+ // Get our Lcd Mode and status
151
+ let lcdMode : i32 = Lcd . mode ;
152
+ let lcdStatus : i32 = eightBitLoadFromGBMemory ( Lcd . memoryLocationLcdStatus ) ;
224
153
225
154
// Check for the coincidence
226
- lcdStatus = checkCoincidence ( newLcdMode , lcdStatus ) ;
155
+ if ( Graphics . scanlineRegister === Lcd . coincidenceCompare ) {
156
+ lcdStatus = setBitOnByte ( 2 , lcdStatus ) ;
157
+ if ( checkBitOnByte ( 6 , lcdStatus ) ) {
158
+ requestLcdInterrupt ( ) ;
159
+ }
160
+ } else {
161
+ lcdStatus = resetBitOnByte ( 2 , lcdStatus ) ;
162
+ }
227
163
228
- // Finally, save our status
229
- eightBitStoreIntoGBMemory ( Lcd . memoryLocationLcdStatus , lcdStatus ) ;
230
- } else if ( scanlineRegister === 153 ) {
231
- // Special Case, need to check LYC
232
- // Fix prehistorik man freeze
233
- let lcdStatus : i32 = eightBitLoadFromGBMemory ( Lcd . memoryLocationLcdStatus ) ;
234
- lcdStatus = checkCoincidence ( newLcdMode , lcdStatus ) ;
164
+ // Store our LCD status after the check
235
165
eightBitStoreIntoGBMemory ( Lcd . memoryLocationLcdStatus , lcdStatus ) ;
236
166
}
237
167
}
168
+
169
+ function _resetLcd ( shouldBlankScreen : boolean ) : void {
170
+ // Reset scanline cycle counter
171
+ Graphics . scanlineCycles = 0 ;
172
+ Graphics . scanlineRegister = 0 ;
173
+ eightBitStoreIntoGBMemory ( Graphics . memoryLocationScanlineRegister , 0 ) ;
174
+
175
+ // Set to mode 0
176
+ // https://www.reddit.com/r/EmuDev/comments/4w6479/gb_dr_mario_level_generation_issues/
177
+ let lcdStatus : i32 = eightBitLoadFromGBMemory ( Lcd . memoryLocationLcdStatus ) ;
178
+ lcdStatus = resetBitOnByte ( 1 , lcdStatus ) ;
179
+ lcdStatus = resetBitOnByte ( 0 , lcdStatus ) ;
180
+ Lcd . mode = 0 ;
181
+
182
+ // Store the status in memory
183
+ eightBitStoreIntoGBMemory ( Lcd . memoryLocationLcdStatus , lcdStatus ) ;
184
+
185
+ // Blank the screen
186
+ if ( shouldBlankScreen ) {
187
+ for ( let i = 0 ; i < FRAME_SIZE ; ++ i ) {
188
+ store < u8 > ( FRAME_LOCATION + i , 255 ) ;
189
+ }
190
+ }
191
+ }
0 commit comments