1
1
// Imports
2
- import { WASMBOY_STATE_LOCATION } from './constants' ;
3
- import { Cpu , initializeCpu , executeOpcode } from './cpu/index' ;
4
- import { Graphics , initializeGraphics , initializePalette , updateGraphics , batchProcessGraphics } from './graphics/index' ;
5
- import { Interrupts , checkInterrupts } from './interrupts/index' ;
2
+ import { WASMBOY_WASM_PAGES , WASMBOY_STATE_LOCATION } from './constants' ;
3
+ import { Config } from './config' ;
4
+ import { resetCycles } from './cycles' ;
5
+ import { resetSteps } from './execute' ;
6
+ import { Cpu , initializeCpu } from './cpu/index' ;
7
+ import { Graphics , initializeGraphics , initializePalette } from './graphics/index' ;
8
+ import { Interrupts , initializeInterrupts } from './interrupts/index' ;
6
9
import { Joypad } from './joypad/index' ;
7
10
import { Memory , initializeCartridge , initializeDma , eightBitStoreIntoGBMemory , eightBitLoadFromGBMemory } from './memory/index' ;
8
- import { Timers , initializeTimers , updateTimers , batchProcessTimers } from './timers/index' ;
9
- import {
10
- Sound ,
11
- initializeSound ,
12
- Channel1 ,
13
- Channel2 ,
14
- Channel3 ,
15
- Channel4 ,
16
- updateSound ,
17
- getNumberOfSamplesInAudioBuffer
18
- } from './sound/index' ;
19
- import { WASMBOY_WASM_PAGES } from './constants' ;
20
- import { Config } from './config' ;
11
+ import { Timers , initializeTimers } from './timers/index' ;
12
+ import { Sound , initializeSound , Channel1 , Channel2 , Channel3 , Channel4 } from './sound/index' ;
21
13
import { hexLog , log } from './helpers/index' ;
22
14
import { u16Portable } from './portable/portable' ;
23
15
@@ -28,6 +20,9 @@ if (memory.size() < WASMBOY_WASM_PAGES) {
28
20
29
21
// Function to track if the core has started
30
22
let hasStarted : boolean = false ;
23
+ export function setHasCoreStarted ( value : boolean ) : void {
24
+ hasStarted = value ;
25
+ }
31
26
export function hasCoreStarted ( ) : i32 {
32
27
if ( hasStarted ) {
33
28
return 1 ;
@@ -133,6 +128,7 @@ function initialize(): void {
133
128
initializeGraphics ( ) ;
134
129
initializePalette ( ) ;
135
130
initializeSound ( ) ;
131
+ initializeInterrupts ( ) ;
136
132
initializeTimers ( ) ;
137
133
138
134
// Various Other Registers
@@ -164,214 +160,11 @@ function initialize(): void {
164
160
}
165
161
166
162
// Reset hasStarted, since we are now reset
167
- hasStarted = false ;
168
- }
169
-
170
- // Public funciton to run opcodes until,
171
- // a frame is ready, or error.
172
- // Return values:
173
- // -1 = error
174
- // 0 = render a frame
175
- export function executeFrame ( ) : i32 {
176
- let error : boolean = false ;
177
- let numberOfCycles : i32 = - 1 ;
178
-
179
- while ( ! error && Cpu . currentCycles < Cpu . MAX_CYCLES_PER_FRAME ( ) ) {
180
- numberOfCycles = executeStep ( ) ;
181
- if ( numberOfCycles < 0 ) {
182
- error = true ;
183
- }
184
- }
185
-
186
- // Find our exit reason
187
- if ( Cpu . currentCycles >= Cpu . MAX_CYCLES_PER_FRAME ( ) ) {
188
- // Render a frame
189
-
190
- // Reset our currentCycles
191
- Cpu . currentCycles -= Cpu . MAX_CYCLES_PER_FRAME ( ) ;
192
-
193
- return 0 ;
194
- }
195
- // TODO: Boot ROM handling
196
-
197
- // There was an error, return -1, and push the program counter back to grab the error opcode
198
- Cpu . programCounter = u16Portable ( Cpu . programCounter - 1 ) ;
199
- return - 1 ;
200
- }
201
-
202
- // Public Function to run opcodes until,
203
- // a frame is ready, audio bufer is filled, or error
204
- // -1 = error
205
- // 0 = render a frame
206
- // 1 = output audio
207
- export function executeFrameAndCheckAudio ( maxAudioBuffer : i32 ) : i32 {
208
- let error : boolean = false ;
209
- let numberOfCycles : i32 = - 1 ;
210
- let audioBufferSize : i32 = 1024 ;
211
-
212
- if ( maxAudioBuffer && maxAudioBuffer > 0 ) {
213
- audioBufferSize = maxAudioBuffer ;
214
- }
163
+ setHasCoreStarted ( false ) ;
215
164
216
- while ( ! error && Cpu . currentCycles < Cpu . MAX_CYCLES_PER_FRAME ( ) && getNumberOfSamplesInAudioBuffer ( ) < audioBufferSize ) {
217
- numberOfCycles = executeStep ( ) ;
218
- if ( numberOfCycles < 0 ) {
219
- error = true ;
220
- }
221
- }
222
-
223
- // Find our exit reason
224
- if ( Cpu . currentCycles >= Cpu . MAX_CYCLES_PER_FRAME ( ) ) {
225
- // Render a frame
226
-
227
- // Reset our currentCycles
228
- Cpu . currentCycles -= Cpu . MAX_CYCLES_PER_FRAME ( ) ;
229
-
230
- return 0 ;
231
- }
232
- if ( getNumberOfSamplesInAudioBuffer ( ) >= audioBufferSize ) {
233
- // Output Audio
234
- return 1 ;
235
- }
236
-
237
- // TODO: Boot ROM handling
238
-
239
- // There was an error, return -1, and push the program counter back to grab the error opcode
240
- Cpu . programCounter = u16Portable ( Cpu . programCounter - 1 ) ;
241
- return - 1 ;
242
- }
243
-
244
- // Public function to run opcodes until,
245
- // a breakpoint is reached
246
- // -1 = error
247
- // 0 = frame executed
248
- // 1 = reached breakpoint
249
- export function executeFrameUntilBreakpoint ( breakpoint : i32 ) : i32 {
250
- let error : boolean = false ;
251
- let numberOfCycles : i32 = - 1 ;
252
-
253
- while ( ! error && Cpu . currentCycles < Cpu . MAX_CYCLES_PER_FRAME ( ) && Cpu . programCounter !== breakpoint ) {
254
- numberOfCycles = executeStep ( ) ;
255
- if ( numberOfCycles < 0 ) {
256
- error = true ;
257
- }
258
- }
259
-
260
- // Find our exit reason
261
- if ( Cpu . currentCycles >= Cpu . MAX_CYCLES_PER_FRAME ( ) ) {
262
- // Render a frame
263
-
264
- // Reset our currentCycles
265
- Cpu . currentCycles -= Cpu . MAX_CYCLES_PER_FRAME ( ) ;
266
-
267
- return 0 ;
268
- }
269
- if ( Cpu . programCounter === breakpoint ) {
270
- // breakpoint
271
- return 1 ;
272
- }
273
-
274
- // TODO: Boot ROM handling
275
-
276
- // There was an error, return -1, and push the program counter back to grab the error opcode
277
- Cpu . programCounter = u16Portable ( Cpu . programCounter - 1 ) ;
278
- return - 1 ;
279
- }
280
-
281
- // Function to execute an opcode, and update other gameboy hardware.
282
- // http://www.codeslinger.co.uk/pages/projects/gameboy/beginning.html
283
- export function executeStep ( ) : i32 {
284
- // Set has started to 1 since we ran a emulation step
285
- hasStarted = true ;
286
-
287
- // Get the opcode, and additional bytes to be handled
288
- // Number of cycles defaults to 4, because while we're halted, we run 4 cycles (according to matt :))
289
- let numberOfCycles : i32 = 4 ;
290
- let opcode : i32 = 0 ;
291
-
292
- // Cpu Halting best explained: https://www.reddit.com/r/EmuDev/comments/5ie3k7/infinite_loop_trying_to_pass_blarggs_interrupt/db7xnbe/
293
- if ( ! Cpu . isHalted && ! Cpu . isStopped ) {
294
- opcode = < u8 > eightBitLoadFromGBMemory ( Cpu . programCounter ) ;
295
- numberOfCycles = executeOpcode ( opcode ) ;
296
- } else {
297
- // if we were halted, and interrupts were disabled but interrupts are pending, stop waiting
298
- if ( Cpu . isHalted && ! Interrupts . masterInterruptSwitch && Interrupts . areInterruptsPending ( ) ) {
299
- Cpu . isHalted = false ;
300
- Cpu . isStopped = false ;
301
-
302
- // Need to run the next opcode twice, it's a bug menitoned in
303
- // The reddit comment mentioned above
304
-
305
- // CTRL+F "low-power" on gameboy cpu manual
306
- // http://marc.rawer.de/Gameboy/Docs/GBCPUman.pdf
307
- // E.g
308
- // 0x76 - halt
309
- // FA 34 12 - ld a,(1234)
310
- // Becomes
311
- // FA FA 34 ld a,(34FA)
312
- // 12 ld (de),a
313
- opcode = < u8 > eightBitLoadFromGBMemory ( Cpu . programCounter ) ;
314
- numberOfCycles = executeOpcode ( opcode ) ;
315
- Cpu . programCounter = u16Portable ( Cpu . programCounter - 1 ) ;
316
- }
317
- }
318
-
319
- // blarggFixes, don't allow register F to have the bottom nibble
320
- Cpu . registerF = Cpu . registerF & 0xf0 ;
321
-
322
- // Check if there was an error decoding the opcode
323
- if ( numberOfCycles <= 0 ) {
324
- return numberOfCycles ;
325
- }
326
-
327
- // Interrupt Handling requires 20 cycles
328
- // https://github.com/Gekkio/mooneye-gb/blob/master/docs/accuracy.markdown#what-is-the-exact-timing-of-cpu-servicing-an-interrupt
329
- // Only check interrupts after an opcode is executed
330
- // Since we don't want to mess up our PC as we are executing
331
- numberOfCycles += checkInterrupts ( ) ;
332
-
333
- // Sync other GB Components with the number of cycles
334
- syncCycles ( numberOfCycles ) ;
335
-
336
- return numberOfCycles ;
337
- }
338
-
339
- // Sync other GB Components with the number of cycles
340
- export function syncCycles ( numberOfCycles : i32 ) : void {
341
- // Check if we did a DMA TRansfer, if we did add the cycles
342
- if ( Memory . DMACycles > 0 ) {
343
- numberOfCycles += Memory . DMACycles ;
344
- Memory . DMACycles = 0 ;
345
- }
346
-
347
- // Finally, Add our number of cycles to the CPU Cycles
348
- Cpu . currentCycles += numberOfCycles ;
349
-
350
- // Check other Gameboy components
351
- if ( ! Cpu . isStopped ) {
352
- if ( Config . graphicsBatchProcessing ) {
353
- // Need to do this, since a lot of things depend on the scanline
354
- // Batch processing will simply return if the number of cycles is too low
355
- Graphics . currentCycles += numberOfCycles ;
356
- batchProcessGraphics ( ) ;
357
- } else {
358
- updateGraphics ( numberOfCycles ) ;
359
- }
360
-
361
- if ( Config . audioBatchProcessing ) {
362
- Sound . currentCycles += numberOfCycles ;
363
- } else {
364
- updateSound ( numberOfCycles ) ;
365
- }
366
- }
367
-
368
- if ( Config . timersBatchProcessing ) {
369
- // Batch processing will simply return if the number of cycles is too low
370
- Timers . currentCycles += numberOfCycles ;
371
- batchProcessTimers ( ) ;
372
- } else {
373
- updateTimers ( numberOfCycles ) ;
374
- }
165
+ // Reset our cycles ran
166
+ resetCycles ( ) ;
167
+ resetSteps ( ) ;
375
168
}
376
169
377
170
// Function to return an address to store into save state memory
@@ -397,7 +190,9 @@ export function saveState(): void {
397
190
Channel4 . saveState ( ) ;
398
191
399
192
// Reset hasStarted, since we are now reset
400
- hasStarted = false ;
193
+ setHasCoreStarted ( false ) ;
194
+
195
+ // Don't want to reset cycles here, as this does not reset the emulator
401
196
}
402
197
403
198
// Function to load state from memory for all of our classes
@@ -415,5 +210,9 @@ export function loadState(): void {
415
210
Channel4 . loadState ( ) ;
416
211
417
212
// Reset hasStarted, since we are now reset
418
- hasStarted = false ;
213
+ setHasCoreStarted ( false ) ;
214
+
215
+ // Reset our cycles ran
216
+ resetCycles ( ) ;
217
+ resetSteps ( ) ;
419
218
}
0 commit comments