Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
RishiRecon
GitHub Repository: RishiRecon/exploits
Path: blob/main/misc/emulator/xnes/snes9x/cpuexec.cpp
28515 views
1
/***********************************************************************************
2
Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
3
4
(c) Copyright 1996 - 2002 Gary Henderson ([email protected]),
5
Jerremy Koot ([email protected])
6
7
(c) Copyright 2002 - 2004 Matthew Kendora
8
9
(c) Copyright 2002 - 2005 Peter Bortas ([email protected])
10
11
(c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/)
12
13
(c) Copyright 2001 - 2006 John Weidman ([email protected])
14
15
(c) Copyright 2002 - 2006 funkyass ([email protected]),
16
Kris Bleakley ([email protected])
17
18
(c) Copyright 2002 - 2010 Brad Jorsch ([email protected]),
19
Nach ([email protected]),
20
21
(c) Copyright 2002 - 2011 zones ([email protected])
22
23
(c) Copyright 2006 - 2007 nitsuja
24
25
(c) Copyright 2009 - 2011 BearOso,
26
OV2
27
28
29
BS-X C emulator code
30
(c) Copyright 2005 - 2006 Dreamer Nom,
31
zones
32
33
C4 x86 assembler and some C emulation code
34
(c) Copyright 2000 - 2003 _Demo_ ([email protected]),
35
Nach,
36
zsKnight ([email protected])
37
38
C4 C++ code
39
(c) Copyright 2003 - 2006 Brad Jorsch,
40
Nach
41
42
DSP-1 emulator code
43
(c) Copyright 1998 - 2006 _Demo_,
44
Andreas Naive ([email protected]),
45
Gary Henderson,
46
Ivar ([email protected]),
47
John Weidman,
48
Kris Bleakley,
49
Matthew Kendora,
50
Nach,
51
neviksti ([email protected])
52
53
DSP-2 emulator code
54
(c) Copyright 2003 John Weidman,
55
Kris Bleakley,
56
Lord Nightmare ([email protected]),
57
Matthew Kendora,
58
neviksti
59
60
DSP-3 emulator code
61
(c) Copyright 2003 - 2006 John Weidman,
62
Kris Bleakley,
63
Lancer,
64
z80 gaiden
65
66
DSP-4 emulator code
67
(c) Copyright 2004 - 2006 Dreamer Nom,
68
John Weidman,
69
Kris Bleakley,
70
Nach,
71
z80 gaiden
72
73
OBC1 emulator code
74
(c) Copyright 2001 - 2004 zsKnight,
75
pagefault ([email protected]),
76
Kris Bleakley
77
Ported from x86 assembler to C by sanmaiwashi
78
79
SPC7110 and RTC C++ emulator code used in 1.39-1.51
80
(c) Copyright 2002 Matthew Kendora with research by
81
zsKnight,
82
John Weidman,
83
Dark Force
84
85
SPC7110 and RTC C++ emulator code used in 1.52+
86
(c) Copyright 2009 byuu,
87
neviksti
88
89
S-DD1 C emulator code
90
(c) Copyright 2003 Brad Jorsch with research by
91
Andreas Naive,
92
John Weidman
93
94
S-RTC C emulator code
95
(c) Copyright 2001 - 2006 byuu,
96
John Weidman
97
98
ST010 C++ emulator code
99
(c) Copyright 2003 Feather,
100
John Weidman,
101
Kris Bleakley,
102
Matthew Kendora
103
104
Super FX x86 assembler emulator code
105
(c) Copyright 1998 - 2003 _Demo_,
106
pagefault,
107
zsKnight
108
109
Super FX C emulator code
110
(c) Copyright 1997 - 1999 Ivar,
111
Gary Henderson,
112
John Weidman
113
114
Sound emulator code used in 1.5-1.51
115
(c) Copyright 1998 - 2003 Brad Martin
116
(c) Copyright 1998 - 2006 Charles Bilyue'
117
118
Sound emulator code used in 1.52+
119
(c) Copyright 2004 - 2007 Shay Green ([email protected])
120
121
SH assembler code partly based on x86 assembler code
122
(c) Copyright 2002 - 2004 Marcus Comstedt ([email protected])
123
124
2xSaI filter
125
(c) Copyright 1999 - 2001 Derek Liauw Kie Fa
126
127
HQ2x, HQ3x, HQ4x filters
128
(c) Copyright 2003 Maxim Stepin ([email protected])
129
130
NTSC filter
131
(c) Copyright 2006 - 2007 Shay Green
132
133
GTK+ GUI code
134
(c) Copyright 2004 - 2011 BearOso
135
136
Win32 GUI code
137
(c) Copyright 2003 - 2006 blip,
138
funkyass,
139
Matthew Kendora,
140
Nach,
141
nitsuja
142
(c) Copyright 2009 - 2011 OV2
143
144
Mac OS GUI code
145
(c) Copyright 1998 - 2001 John Stiles
146
(c) Copyright 2001 - 2011 zones
147
148
149
Specific ports contains the works of other authors. See headers in
150
individual files.
151
152
153
Snes9x homepage: http://www.snes9x.com/
154
155
Permission to use, copy, modify and/or distribute Snes9x in both binary
156
and source form, for non-commercial purposes, is hereby granted without
157
fee, providing that this license information and copyright notice appear
158
with all copies and any derived work.
159
160
This software is provided 'as-is', without any express or implied
161
warranty. In no event shall the authors be held liable for any damages
162
arising from the use of this software or it's derivatives.
163
164
Snes9x is freeware for PERSONAL USE only. Commercial users should
165
seek permission of the copyright holders first. Commercial use includes,
166
but is not limited to, charging money for Snes9x or software derived from
167
Snes9x, including Snes9x or derivatives in commercial game bundles, and/or
168
using Snes9x as a promotion for your commercial product.
169
170
The copyright holders request that bug fixes and improvements to the code
171
should be forwarded to them so everyone can benefit from the modifications
172
in future versions.
173
174
Super NES and Super Nintendo Entertainment System are trademarks of
175
Nintendo Co., Limited and its subsidiary companies.
176
***********************************************************************************/
177
178
179
#include "snes9x.h"
180
#include "memmap.h"
181
#include "cpuops.h"
182
#include "dma.h"
183
#include "apu/apu.h"
184
#include "fxemu.h"
185
#include "snapshot.h"
186
#ifdef DEBUGGER
187
#include "debug.h"
188
#include "missing.h"
189
#endif
190
191
static inline void S9xReschedule (void);
192
193
194
void S9xMainLoop (void)
195
{
196
// debugging variable?
197
// static int loop_times=0;
198
int loops2=0;
199
//printf("Enter S9xMainLoop %d %x\n", loop_times, Registers.PCw);
200
for (;;)
201
{
202
loops2++;
203
//printf("S9xMainLoop %d for loop %d flags=%d\n", loop_times, loops2, CPU.Flags);
204
if (CPU.NMILine)
205
{
206
//printf("case 1\n");
207
if (Timings.NMITriggerPos <= CPU.Cycles)
208
{
209
CPU.NMILine = FALSE;
210
Timings.NMITriggerPos = 0xffff;
211
if (CPU.WaitingForInterrupt)
212
{
213
CPU.WaitingForInterrupt = FALSE;
214
Registers.PCw++;
215
}
216
217
S9xOpcode_NMI();
218
}
219
}
220
221
if (CPU.IRQTransition || CPU.IRQExternal)
222
{
223
//printf("case 2\n");
224
if (CPU.IRQPending)
225
CPU.IRQPending--;
226
else
227
{
228
if (CPU.WaitingForInterrupt)
229
{
230
CPU.WaitingForInterrupt = FALSE;
231
Registers.PCw++;
232
}
233
234
CPU.IRQTransition = FALSE;
235
CPU.IRQPending = Timings.IRQPendCount;
236
237
if (!CheckFlag(IRQ))
238
S9xOpcode_IRQ();
239
}
240
}
241
242
#ifdef DEBUGGER
243
if ((CPU.Flags & BREAK_FLAG) && !(CPU.Flags & SINGLE_STEP_FLAG))
244
{
245
for (int Break = 0; Break != 6; Break++)
246
{
247
if (S9xBreakpoint[Break].Enabled &&
248
S9xBreakpoint[Break].Bank == Registers.PB &&
249
S9xBreakpoint[Break].Address == Registers.PCw)
250
{
251
if (S9xBreakpoint[Break].Enabled == 2)
252
S9xBreakpoint[Break].Enabled = TRUE;
253
else
254
CPU.Flags |= DEBUG_MODE_FLAG;
255
}
256
}
257
}
258
259
if (CPU.Flags & DEBUG_MODE_FLAG)
260
break;
261
262
if (CPU.Flags & TRACE_FLAG)
263
S9xTrace();
264
265
if (CPU.Flags & SINGLE_STEP_FLAG)
266
{
267
CPU.Flags &= ~SINGLE_STEP_FLAG;
268
CPU.Flags |= DEBUG_MODE_FLAG;
269
}
270
#endif
271
272
if (CPU.Flags & SCAN_KEYS_FLAG)
273
break;
274
275
register uint8 Op;
276
register Opcode *Opcodes;
277
278
if (CPU.PCBase)
279
{
280
Op = CPU.PCBase[Registers.PCw];
281
282
CPU.PrevCycles = CPU.Cycles;
283
CPU.Cycles += CPU.MemSpeed;
284
S9xCheckInterrupts();
285
Opcodes = ICPU.S9xOpcodes;
286
//printf("case 3 %x %x %d %d\n", Registers.PCw, Op, CPU.PrevCycles, CPU.Cycles);
287
}
288
else
289
{
290
//printf("case 4\n");
291
Op = S9xGetByte(Registers.PBPC);
292
OpenBus = Op;
293
Opcodes = S9xOpcodesSlow;
294
}
295
296
if ((Registers.PCw & MEMMAP_MASK) + ICPU.S9xOpLengths[Op] >= MEMMAP_BLOCK_SIZE)
297
{
298
uint8 *oldPCBase = CPU.PCBase;
299
//printf("case 5\n");
300
301
CPU.PCBase = S9xGetBasePointer(ICPU.ShiftedPB + ((uint16) (Registers.PCw + 4)));
302
if (oldPCBase != CPU.PCBase || (Registers.PCw & ~MEMMAP_MASK) == (0xffff & ~MEMMAP_MASK))
303
Opcodes = S9xOpcodesSlow;
304
}
305
//printf("case 3.1 %d\n", CPU.Cycles);
306
Registers.PCw++;
307
Opcodes[Op]();
308
//printf("case 3.2 %d\n", CPU.Cycles);
309
310
if (Settings.SA1){
311
//printf("case 6\n");
312
S9xSA1MainLoop();
313
}
314
}
315
316
S9xPackStatus();
317
318
if (CPU.Flags & SCAN_KEYS_FLAG)
319
{
320
//printf("case 7\n");
321
#ifdef DEBUGGER
322
if (!(CPU.Flags & FRAME_ADVANCE_FLAG))
323
#endif
324
S9xSyncSpeed();
325
CPU.Flags &= ~SCAN_KEYS_FLAG;
326
}
327
//printf("Exit S9xMainLoop %d loops2=%d\n", loop_times++, loops2);
328
}
329
330
static inline void S9xReschedule (void)
331
{
332
switch (CPU.WhichEvent)
333
{
334
case HC_HBLANK_START_EVENT:
335
CPU.WhichEvent = HC_HDMA_START_EVENT;
336
CPU.NextEvent = Timings.HDMAStart;
337
break;
338
339
case HC_HDMA_START_EVENT:
340
CPU.WhichEvent = HC_HCOUNTER_MAX_EVENT;
341
CPU.NextEvent = Timings.H_Max;
342
break;
343
344
case HC_HCOUNTER_MAX_EVENT:
345
CPU.WhichEvent = HC_HDMA_INIT_EVENT;
346
CPU.NextEvent = Timings.HDMAInit;
347
break;
348
349
case HC_HDMA_INIT_EVENT:
350
CPU.WhichEvent = HC_RENDER_EVENT;
351
CPU.NextEvent = Timings.RenderPos;
352
break;
353
354
case HC_RENDER_EVENT:
355
CPU.WhichEvent = HC_WRAM_REFRESH_EVENT;
356
CPU.NextEvent = Timings.WRAMRefreshPos;
357
break;
358
359
case HC_WRAM_REFRESH_EVENT:
360
CPU.WhichEvent = HC_HBLANK_START_EVENT;
361
CPU.NextEvent = Timings.HBlankStart;
362
break;
363
}
364
}
365
366
void S9xDoHEventProcessing (void)
367
{
368
#ifdef DEBUGGER
369
static char eventname[7][32] =
370
{
371
"",
372
"HC_HBLANK_START_EVENT",
373
"HC_HDMA_START_EVENT ",
374
"HC_HCOUNTER_MAX_EVENT",
375
"HC_HDMA_INIT_EVENT ",
376
"HC_RENDER_EVENT ",
377
"HC_WRAM_REFRESH_EVENT"
378
};
379
#endif
380
381
#ifdef DEBUGGER
382
if (Settings.TraceHCEvent)
383
S9xTraceFormattedMessage("--- HC event processing (%s) expected HC:%04d executed HC:%04d",
384
eventname[CPU.WhichEvent], CPU.NextEvent, CPU.Cycles);
385
#endif
386
387
switch (CPU.WhichEvent)
388
{
389
case HC_HBLANK_START_EVENT:
390
S9xReschedule();
391
break;
392
393
case HC_HDMA_START_EVENT:
394
S9xReschedule();
395
396
if (PPU.HDMA && CPU.V_Counter <= PPU.ScreenHeight)
397
{
398
#ifdef DEBUGGER
399
S9xTraceFormattedMessage("*** HDMA Transfer HC:%04d, Channel:%02x", CPU.Cycles, PPU.HDMA);
400
#endif
401
PPU.HDMA = S9xDoHDMA(PPU.HDMA);
402
}
403
404
break;
405
406
case HC_HCOUNTER_MAX_EVENT:
407
if (Settings.SuperFX)
408
{
409
if (!SuperFX.oneLineDone)
410
S9xSuperFXExec();
411
SuperFX.oneLineDone = FALSE;
412
}
413
414
S9xAPUEndScanline();
415
CPU.Cycles -= Timings.H_Max;
416
CPU.PrevCycles -= Timings.H_Max;
417
S9xAPUSetReferenceTime(CPU.Cycles);
418
419
if ((Timings.NMITriggerPos != 0xffff) && (Timings.NMITriggerPos >= Timings.H_Max))
420
Timings.NMITriggerPos -= Timings.H_Max;
421
422
CPU.V_Counter++;
423
if (CPU.V_Counter >= Timings.V_Max) // V ranges from 0 to Timings.V_Max - 1
424
{
425
CPU.V_Counter = 0;
426
Timings.InterlaceField ^= 1;
427
428
// From byuu:
429
// [NTSC]
430
// interlace mode has 525 scanlines: 263 on the even frame, and 262 on the odd.
431
// non-interlace mode has 524 scanlines: 262 scanlines on both even and odd frames.
432
// [PAL] <PAL info is unverified on hardware>
433
// interlace mode has 625 scanlines: 313 on the even frame, and 312 on the odd.
434
// non-interlace mode has 624 scanlines: 312 scanlines on both even and odd frames.
435
if (IPPU.Interlace && !Timings.InterlaceField)
436
Timings.V_Max = Timings.V_Max_Master + 1; // 263 (NTSC), 313?(PAL)
437
else
438
Timings.V_Max = Timings.V_Max_Master; // 262 (NTSC), 312?(PAL)
439
440
Memory.FillRAM[0x213F] ^= 0x80;
441
PPU.RangeTimeOver = 0;
442
443
// FIXME: reading $4210 will wait 2 cycles, then perform reading, then wait 4 more cycles.
444
Memory.FillRAM[0x4210] = Model->_5A22;
445
CPU.NMILine = FALSE;
446
Timings.NMITriggerPos = 0xffff;
447
448
ICPU.Frame++;
449
PPU.HVBeamCounterLatched = 0;
450
CPU.Flags |= SCAN_KEYS_FLAG;
451
}
452
453
// From byuu:
454
// In non-interlace mode, there are 341 dots per scanline, and 262 scanlines per frame.
455
// On odd frames, scanline 240 is one dot short.
456
// In interlace mode, there are always 341 dots per scanline. Even frames have 263 scanlines,
457
// and odd frames have 262 scanlines.
458
// Interlace mode scanline 240 on odd frames is not missing a dot.
459
if (CPU.V_Counter == 240 && !IPPU.Interlace && Timings.InterlaceField) // V=240
460
Timings.H_Max = Timings.H_Max_Master - ONE_DOT_CYCLE; // HC=1360
461
else
462
Timings.H_Max = Timings.H_Max_Master; // HC=1364
463
464
if (Model->_5A22 == 2)
465
{
466
if (CPU.V_Counter != 240 || IPPU.Interlace || !Timings.InterlaceField) // V=240
467
{
468
if (Timings.WRAMRefreshPos == SNES_WRAM_REFRESH_HC_v2 - ONE_DOT_CYCLE) // HC=534
469
Timings.WRAMRefreshPos = SNES_WRAM_REFRESH_HC_v2; // HC=538
470
else
471
Timings.WRAMRefreshPos = SNES_WRAM_REFRESH_HC_v2 - ONE_DOT_CYCLE; // HC=534
472
}
473
}
474
else
475
Timings.WRAMRefreshPos = SNES_WRAM_REFRESH_HC_v1;
476
477
if (CPU.V_Counter == PPU.ScreenHeight + FIRST_VISIBLE_LINE) // VBlank starts from V=225(240).
478
{
479
S9xEndScreenRefresh();
480
PPU.HDMA = 0;
481
// Bits 7 and 6 of $4212 are computed when read in S9xGetPPU.
482
#ifdef DEBUGGER
483
missing.dma_this_frame = 0;
484
#endif
485
IPPU.MaxBrightness = PPU.Brightness;
486
PPU.ForcedBlanking = (Memory.FillRAM[0x2100] >> 7) & 1;
487
488
if (!PPU.ForcedBlanking)
489
{
490
PPU.OAMAddr = PPU.SavedOAMAddr;
491
492
uint8 tmp = 0;
493
494
if (PPU.OAMPriorityRotation)
495
tmp = (PPU.OAMAddr & 0xFE) >> 1;
496
if ((PPU.OAMFlip & 1) || PPU.FirstSprite != tmp)
497
{
498
PPU.FirstSprite = tmp;
499
IPPU.OBJChanged = TRUE;
500
}
501
502
PPU.OAMFlip = 0;
503
}
504
505
// FIXME: writing to $4210 will wait 6 cycles.
506
Memory.FillRAM[0x4210] = 0x80 | Model->_5A22;
507
if (Memory.FillRAM[0x4200] & 0x80)
508
{
509
// FIXME: triggered at HC=6, checked just before the final CPU cycle,
510
// then, when to call S9xOpcode_NMI()?
511
CPU.NMILine = TRUE;
512
Timings.NMITriggerPos = 6 + 6;
513
}
514
515
}
516
517
if (CPU.V_Counter == PPU.ScreenHeight + 3) // FIXME: not true
518
{
519
if (Memory.FillRAM[0x4200] & 1)
520
S9xDoAutoJoypad();
521
}
522
523
if (CPU.V_Counter == FIRST_VISIBLE_LINE) // V=1
524
S9xStartScreenRefresh();
525
526
S9xReschedule();
527
528
break;
529
530
case HC_HDMA_INIT_EVENT:
531
S9xReschedule();
532
533
if (CPU.V_Counter == 0)
534
{
535
#ifdef DEBUGGER
536
S9xTraceFormattedMessage("*** HDMA Init HC:%04d, Channel:%02x", CPU.Cycles, PPU.HDMA);
537
#endif
538
S9xStartHDMA();
539
}
540
541
break;
542
543
case HC_RENDER_EVENT:
544
if (CPU.V_Counter >= FIRST_VISIBLE_LINE && CPU.V_Counter <= PPU.ScreenHeight)
545
RenderLine((uint8) (CPU.V_Counter - FIRST_VISIBLE_LINE));
546
547
S9xReschedule();
548
549
break;
550
551
case HC_WRAM_REFRESH_EVENT:
552
#ifdef DEBUGGER
553
S9xTraceFormattedMessage("*** WRAM Refresh HC:%04d", CPU.Cycles);
554
#endif
555
556
CPU.PrevCycles = CPU.Cycles;
557
CPU.Cycles += SNES_WRAM_REFRESH_CYCLES;
558
S9xCheckInterrupts();
559
560
S9xReschedule();
561
562
break;
563
}
564
565
#ifdef DEBUGGER
566
if (Settings.TraceHCEvent)
567
S9xTraceFormattedMessage("--- HC event rescheduled (%s) expected HC:%04d current HC:%04d",
568
eventname[CPU.WhichEvent], CPU.NextEvent, CPU.Cycles);
569
#endif
570
}
571
572