2 * Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
4 * (c) Copyright 1996 - 2001 Gary Henderson (gary.henderson@ntlworld.com) and
5 * Jerremy Koot (jkoot@snes9x.com)
7 * Super FX C emulator code
8 * (c) Copyright 1997 - 1999 Ivar (ivar@snes9x.com) and
10 * Super FX assembler emulator code (c) Copyright 1998 zsKnight and _Demo_.
12 * DSP1 emulator code (c) Copyright 1998 Ivar, _Demo_ and Gary Henderson.
13 * C4 asm and some C emulation code (c) Copyright 2000 zsKnight and _Demo_.
14 * C4 C code (c) Copyright 2001 Gary Henderson (gary.henderson@ntlworld.com).
16 * DOS port code contains the works of other authors. See headers in
19 * Snes9x homepage: http://www.snes9x.com
21 * Permission to use, copy, modify and distribute Snes9x in both binary and
22 * source form, for non-commercial purposes, is hereby granted without fee,
23 * providing that this license information and copyright notice appear with
24 * all copies and any derived work.
26 * This software is provided 'as-is', without any express or implied
27 * warranty. In no event shall the authors be held liable for any damages
28 * arising from the use of this software.
30 * Snes9x is freeware for PERSONAL USE only. Commercial users should
31 * seek permission of the copyright holders first. Commercial use includes
32 * charging money for Snes9x or software derived from Snes9x.
34 * The copyright holders request that bug fixes and improvements to the code
35 * should be forwarded to them so everyone can benefit from the modifications
38 * Super NES and Super Nintendo Entertainment System are trademarks of
39 * Nintendo Co., Limited and its subsidiary companies.
49 //#define __memcheck__
52 extern uint16 mem_check;
54 INLINE uint8 S9xGetByte (uint32 Address)
58 sprintf(str,"rd @ %04X",Address);
63 mem_check+=(Address>>16)+Address;
65 #if defined(VAR_CYCLES) || defined(CPU_SHUTDOWN)
67 uint8 *GetAddress = Memory.Map [block = (Address >> MEMMAP_SHIFT) & MEMMAP_MASK];
69 uint8 *GetAddress = Memory.Map [(Address >> MEMMAP_SHIFT) & MEMMAP_MASK];
71 if (GetAddress >= (uint8 *) CMemory::MAP_LAST)
74 CPU.Cycles += Memory.MemorySpeed [block];
77 if (Memory.BlockIsRAM [block])
78 CPU.WaitAddress = CPU.PCAtOpcodeStart;
80 return (*(GetAddress + (Address & 0xffff)));
83 switch ((int) GetAddress)
85 case CMemory::MAP_PPU:
88 CPU.Cycles += ONE_CYCLE;
90 return (S9xGetPPU (Address & 0xffff));
91 case CMemory::MAP_CPU:
93 CPU.Cycles += ONE_CYCLE;
95 return (S9xGetCPU (Address & 0xffff));
96 case CMemory::MAP_DSP:
98 CPU.Cycles += SLOW_ONE_CYCLE;
100 return (S9xGetDSP (Address & 0xffff));
101 case CMemory::MAP_SA1RAM:
102 case CMemory::MAP_LOROM_SRAM:
104 CPU.Cycles += SLOW_ONE_CYCLE;
106 return (*(Memory.SRAM + ((Address & CPU.Memory_SRAMMask))));
108 case CMemory::MAP_HIROM_SRAM:
110 CPU.Cycles += SLOW_ONE_CYCLE;
112 return (*(Memory.SRAM + (((Address & 0x7fff) - 0x6000 +
113 ((Address & 0xf0000) >> 3)) & CPU.Memory_SRAMMask)));
115 case CMemory::MAP_DEBUG:
117 printf ("R(B) %06x\n", Address);
120 case CMemory::MAP_BWRAM:
122 CPU.Cycles += SLOW_ONE_CYCLE;
124 return (*(Memory.BWRAM + ((Address & 0x7fff) - 0x6000)));
126 case CMemory::MAP_C4:
127 return (S9xGetC4 (Address & 0xffff));
130 case CMemory::MAP_NONE:
132 CPU.Cycles += SLOW_ONE_CYCLE;
135 printf ("R(B) %06x\n", Address);
137 return ((Address >> 8) & 0xff);
141 INLINE uint16 S9xGetWord (uint32 Address)
145 sprintf(str,"rd @ %04X",Address);
150 mem_check+=(Address>>16)+Address;
152 if ((Address & 0x1fff) == 0x1fff)
154 return (S9xGetByte (Address) | (S9xGetByte (Address + 1) << 8));
156 #if defined(VAR_CYCLES) || defined(CPU_SHUTDOWN)
158 uint8 *GetAddress = Memory.Map [block = (Address >> MEMMAP_SHIFT) & MEMMAP_MASK];
160 uint8 *GetAddress = Memory.Map [(Address >> MEMMAP_SHIFT) & MEMMAP_MASK];
162 if (GetAddress >= (uint8 *) CMemory::MAP_LAST)
165 CPU.Cycles += Memory.MemorySpeed [block] << 1;
168 if (Memory.BlockIsRAM [block])
169 CPU.WaitAddress = CPU.PCAtOpcodeStart;
171 #ifdef FAST_LSB_WORD_ACCESS
172 return (*(uint16 *) (GetAddress + (Address & 0xffff)));
174 return (*(GetAddress + (Address & 0xffff)) |
175 (*(GetAddress + (Address & 0xffff) + 1) << 8));
179 switch ((int) GetAddress)
181 case CMemory::MAP_PPU:
184 CPU.Cycles += TWO_CYCLES;
186 return (S9xGetPPU (Address & 0xffff) |
187 (S9xGetPPU ((Address + 1) & 0xffff) << 8));
188 case CMemory::MAP_CPU:
190 CPU.Cycles += TWO_CYCLES;
192 return (S9xGetCPU (Address & 0xffff) |
193 (S9xGetCPU ((Address + 1) & 0xffff) << 8));
194 case CMemory::MAP_DSP:
196 CPU.Cycles += SLOW_ONE_CYCLE * 2;
198 return (S9xGetDSP (Address & 0xffff) |
199 (S9xGetDSP ((Address + 1) & 0xffff) << 8));
200 case CMemory::MAP_SA1RAM:
201 case CMemory::MAP_LOROM_SRAM:
203 CPU.Cycles += SLOW_ONE_CYCLE * 2;
205 return (*(Memory.SRAM + (Address & CPU.Memory_SRAMMask)) |
206 (*(Memory.SRAM + ((Address + 1) & CPU.Memory_SRAMMask)) << 8));
208 case CMemory::MAP_HIROM_SRAM:
210 CPU.Cycles += SLOW_ONE_CYCLE * 2;
212 return (*(Memory.SRAM +
213 (((Address & 0x7fff) - 0x6000 +
214 ((Address & 0xf0000) >> 3)) & CPU.Memory_SRAMMask)) |
216 ((((Address + 1) & 0x7fff) - 0x6000 +
217 (((Address + 1) & 0xf0000) >> 3)) & CPU.Memory_SRAMMask)) << 8));
219 case CMemory::MAP_BWRAM:
221 CPU.Cycles += SLOW_ONE_CYCLE * 2;
223 return (*(Memory.BWRAM + ((Address & 0x7fff) - 0x6000)) |
224 (*(Memory.BWRAM + (((Address + 1) & 0x7fff) - 0x6000)) << 8));
226 case CMemory::MAP_DEBUG:
228 printf ("R(W) %06x\n", Address);
232 case CMemory::MAP_C4:
233 return (S9xGetC4 (Address & 0xffff) |
234 (S9xGetC4 ((Address + 1) & 0xffff) << 8));
237 case CMemory::MAP_NONE:
239 CPU.Cycles += SLOW_ONE_CYCLE * 2;
242 printf ("R(W) %06x\n", Address);
244 return (((Address >> 8) | (Address & 0xff00)) & 0xffff);
248 INLINE void S9xSetByte (uint8 Byte, uint32 Address)
252 sprintf(str,"wr @ %04X %02X",Address,Byte);
260 #if defined(CPU_SHUTDOWN)
261 CPU.WaitAddress = NULL;
263 #if defined(VAR_CYCLES)
265 uint8 *SetAddress = Memory.WriteMap [block = ((Address >> MEMMAP_SHIFT) & MEMMAP_MASK)];
267 uint8 *SetAddress = Memory.WriteMap [(Address >> MEMMAP_SHIFT) & MEMMAP_MASK];
270 if (SetAddress >= (uint8 *) CMemory::MAP_LAST)
273 CPU.Cycles += Memory.MemorySpeed [block];
276 SetAddress += Address & 0xffff;
278 if (SetAddress == SA1.WaitByteAddress1 ||
279 SetAddress == SA1.WaitByteAddress2)
281 SA1.Executing = SA1.S9xOpcodes != NULL;
287 *(SetAddress + (Address & 0xffff)) = Byte;
292 switch ((int) SetAddress)
294 case CMemory::MAP_PPU:
297 CPU.Cycles += ONE_CYCLE;
299 S9xSetPPU (Byte, Address & 0xffff);
302 case CMemory::MAP_CPU:
304 CPU.Cycles += ONE_CYCLE;
306 S9xSetCPU (Byte, Address & 0xffff);
309 case CMemory::MAP_DSP:
311 CPU.Cycles += SLOW_ONE_CYCLE;
313 S9xSetDSP (Byte, Address & 0xffff);
316 case CMemory::MAP_LOROM_SRAM:
318 CPU.Cycles += SLOW_ONE_CYCLE;
320 if (CPU.Memory_SRAMMask)
322 *(Memory.SRAM + (Address & CPU.Memory_SRAMMask)) = Byte;
323 CPU.SRAMModified = TRUE;
327 case CMemory::MAP_HIROM_SRAM:
329 CPU.Cycles += SLOW_ONE_CYCLE;
331 if (CPU.Memory_SRAMMask)
333 *(Memory.SRAM + (((Address & 0x7fff) - 0x6000 +
334 ((Address & 0xf0000) >> 3)) & CPU.Memory_SRAMMask)) = Byte;
335 CPU.SRAMModified = TRUE;
339 case CMemory::MAP_BWRAM:
341 CPU.Cycles += SLOW_ONE_CYCLE;
343 *(Memory.BWRAM + ((Address & 0x7fff) - 0x6000)) = Byte;
344 CPU.SRAMModified = TRUE;
347 case CMemory::MAP_DEBUG:
349 printf ("W(B) %06x\n", Address);
352 case CMemory::MAP_SA1RAM:
354 CPU.Cycles += SLOW_ONE_CYCLE;
356 *(Memory.SRAM + (Address & 0xffff)) = Byte;
357 SA1.Executing = !SA1.Waiting;
360 case CMemory::MAP_C4:
361 S9xSetC4 (Byte, Address & 0xffff);
365 case CMemory::MAP_NONE:
367 CPU.Cycles += SLOW_ONE_CYCLE;
370 printf ("W(B) %06x\n", Address);
376 INLINE void S9xSetWord (uint16 Word, uint32 Address)
380 sprintf(str,"wr @ %04X %04X",Address,Word);
387 #if defined(CPU_SHUTDOWN)
388 CPU.WaitAddress = NULL;
390 #if defined (VAR_CYCLES)
392 uint8 *SetAddress = Memory.WriteMap [block = ((Address >> MEMMAP_SHIFT) & MEMMAP_MASK)];
394 uint8 *SetAddress = Memory.WriteMap [(Address >> MEMMAP_SHIFT) & MEMMAP_MASK];
397 if (SetAddress >= (uint8 *) CMemory::MAP_LAST)
400 CPU.Cycles += Memory.MemorySpeed [block] << 1;
402 #if defined(CPU_SHUTDOWN) && defined(USE_SA1)
403 uint8 *SetAddressSA1 += Address & 0xffff;
404 if (SetAddressSA1 == SA1.WaitByteAddress1 ||
405 SetAddressSA1 == SA1.WaitByteAddress2)
407 SA1.Executing = SA1.S9xOpcodes != NULL;
411 #ifdef FAST_LSB_WORD_ACCESS
412 *(uint16 *) (SetAddress + (Address & 0xffff)) = Word;
414 *(SetAddress + (Address & 0xffff)) = (uint8) Word;
415 *(SetAddress + ((Address + 1) & 0xffff)) = Word >> 8;
420 switch ((int) SetAddress)
422 case CMemory::MAP_PPU:
425 CPU.Cycles += TWO_CYCLES;
427 S9xSetPPU ((uint8) Word, Address & 0xffff);
428 S9xSetPPU (Word >> 8, (Address & 0xffff) + 1);
431 case CMemory::MAP_CPU:
433 CPU.Cycles += TWO_CYCLES;
435 S9xSetCPU ((uint8) Word, (Address & 0xffff));
436 S9xSetCPU (Word >> 8, (Address & 0xffff) + 1);
439 case CMemory::MAP_DSP:
441 CPU.Cycles += SLOW_ONE_CYCLE * 2;
443 S9xSetDSP ((uint8) Word, (Address & 0xffff));
444 S9xSetDSP (Word >> 8, (Address & 0xffff) + 1);
447 case CMemory::MAP_LOROM_SRAM:
449 CPU.Cycles += SLOW_ONE_CYCLE * 2;
451 if (CPU.Memory_SRAMMask)
453 *(Memory.SRAM + (Address & CPU.Memory_SRAMMask)) = (uint8) Word;
454 *(Memory.SRAM + ((Address + 1) & CPU.Memory_SRAMMask)) = Word >> 8;
455 CPU.SRAMModified = TRUE;
459 case CMemory::MAP_HIROM_SRAM:
461 CPU.Cycles += SLOW_ONE_CYCLE * 2;
463 if (CPU.Memory_SRAMMask)
466 (((Address & 0x7fff) - 0x6000 +
467 ((Address & 0xf0000) >> MEMMAP_SHIFT) & CPU.Memory_SRAMMask))) = (uint8) Word;
469 ((((Address + 1) & 0x7fff) - 0x6000 +
470 (((Address + 1) & 0xf0000) >> MEMMAP_SHIFT) & CPU.Memory_SRAMMask))) = (uint8) (Word >> 8);
471 CPU.SRAMModified = TRUE;
475 case CMemory::MAP_BWRAM:
477 CPU.Cycles += SLOW_ONE_CYCLE * 2;
479 *(Memory.BWRAM + ((Address & 0x7fff) - 0x6000)) = (uint8) Word;
480 *(Memory.BWRAM + (((Address + 1) & 0x7fff) - 0x6000)) = (uint8) (Word >> 8);
481 CPU.SRAMModified = TRUE;
484 case CMemory::MAP_DEBUG:
486 printf ("W(W) %06x\n", Address);
489 case CMemory::MAP_SA1RAM:
491 CPU.Cycles += SLOW_ONE_CYCLE;
493 *(Memory.SRAM + (Address & 0xffff)) = (uint8) Word;
494 *(Memory.SRAM + ((Address + 1) & 0xffff)) = (uint8) (Word >> 8);
495 SA1.Executing = !SA1.Waiting;
498 case CMemory::MAP_C4:
499 S9xSetC4 (Word & 0xff, Address & 0xffff);
500 S9xSetC4 ((uint8) (Word >> 8), (Address + 1) & 0xffff);
504 case CMemory::MAP_NONE:
506 CPU.Cycles += SLOW_ONE_CYCLE * 2;
509 printf ("W(W) %06x\n", Address);
515 INLINE uint8 *GetBasePointer (uint32 Address)
517 uint8 *GetAddress = Memory.Map [(Address >> MEMMAP_SHIFT) & MEMMAP_MASK];
518 if (GetAddress >= (uint8 *) CMemory::MAP_LAST)
521 switch ((int) GetAddress)
523 case CMemory::MAP_PPU:
524 return (Memory.FillRAM - 0x2000);
525 case CMemory::MAP_CPU:
526 return (Memory.FillRAM - 0x4000);
527 case CMemory::MAP_DSP:
528 return (Memory.FillRAM - 0x6000);
529 case CMemory::MAP_SA1RAM:
530 case CMemory::MAP_LOROM_SRAM:
531 return (Memory.SRAM);
532 case CMemory::MAP_BWRAM:
533 return (Memory.BWRAM - 0x6000);
534 case CMemory::MAP_HIROM_SRAM:
535 return (Memory.SRAM - 0x6000);
537 case CMemory::MAP_C4:
538 return (Memory.C4RAM - 0x6000);
540 case CMemory::MAP_DEBUG:
542 printf ("GBP %06x\n", Address);
546 case CMemory::MAP_NONE:
548 printf ("GBP %06x\n", Address);
554 INLINE uint8 *S9xGetMemPointer (uint32 Address)
556 uint8 *GetAddress = Memory.Map [(Address >> MEMMAP_SHIFT) & MEMMAP_MASK];
557 if (GetAddress >= (uint8 *) CMemory::MAP_LAST)
558 return (GetAddress + (Address & 0xffff));
560 switch ((int) GetAddress)
562 case CMemory::MAP_PPU:
563 return (Memory.FillRAM - 0x2000 + (Address & 0xffff));
564 case CMemory::MAP_CPU:
565 return (Memory.FillRAM - 0x4000 + (Address & 0xffff));
566 case CMemory::MAP_DSP:
567 return (Memory.FillRAM - 0x6000 + (Address & 0xffff));
568 case CMemory::MAP_SA1RAM:
569 case CMemory::MAP_LOROM_SRAM:
570 return (Memory.SRAM + (Address & 0xffff));
571 case CMemory::MAP_BWRAM:
572 return (Memory.BWRAM - 0x6000 + (Address & 0xffff));
573 case CMemory::MAP_HIROM_SRAM:
574 return (Memory.SRAM - 0x6000 + (Address & 0xffff));
576 case CMemory::MAP_C4:
577 return (Memory.C4RAM - 0x6000 + (Address & 0xffff));
579 case CMemory::MAP_DEBUG:
581 printf ("GMP %06x\n", Address);
584 case CMemory::MAP_NONE:
586 printf ("GMP %06x\n", Address);
592 INLINE void S9xSetPCBase (uint32 Address)
596 uint8 *GetAddress = Memory.Map [block = (Address >> MEMMAP_SHIFT) & MEMMAP_MASK];
598 uint8 *GetAddress = Memory.Map [(Address >> MEMMAP_SHIFT) & MEMMAP_MASK];
600 if (GetAddress >= (uint8 *) CMemory::MAP_LAST)
603 CPU.MemSpeed = Memory.MemorySpeed [block];
604 CPU.MemSpeedx2 = CPU.MemSpeed << 1;
606 CPU.PCBase = GetAddress;
607 CPU.PC = GetAddress + (Address & 0xffff);
611 switch ((int) GetAddress)
613 case CMemory::MAP_PPU:
615 CPU.MemSpeed = ONE_CYCLE;
616 CPU.MemSpeedx2 = TWO_CYCLES;
618 CPU.PCBase = Memory.FillRAM - 0x2000;
619 CPU.PC = CPU.PCBase + (Address & 0xffff);
622 case CMemory::MAP_CPU:
624 CPU.MemSpeed = ONE_CYCLE;
625 CPU.MemSpeedx2 = TWO_CYCLES;
627 CPU.PCBase = Memory.FillRAM - 0x4000;
628 CPU.PC = CPU.PCBase + (Address & 0xffff);
631 case CMemory::MAP_DSP:
633 CPU.MemSpeed = SLOW_ONE_CYCLE;
634 CPU.MemSpeedx2 = SLOW_ONE_CYCLE * 2;
636 CPU.PCBase = Memory.FillRAM - 0x6000;
637 CPU.PC = CPU.PCBase + (Address & 0xffff);
640 case CMemory::MAP_SA1RAM:
641 case CMemory::MAP_LOROM_SRAM:
643 CPU.MemSpeed = SLOW_ONE_CYCLE;
644 CPU.MemSpeedx2 = SLOW_ONE_CYCLE * 2;
646 CPU.PCBase = Memory.SRAM;
647 CPU.PC = CPU.PCBase + (Address & 0xffff);
650 case CMemory::MAP_BWRAM:
652 CPU.MemSpeed = SLOW_ONE_CYCLE;
653 CPU.MemSpeedx2 = SLOW_ONE_CYCLE * 2;
655 CPU.PCBase = Memory.BWRAM - 0x6000;
656 CPU.PC = CPU.PCBase + (Address & 0xffff);
658 case CMemory::MAP_HIROM_SRAM:
660 CPU.MemSpeed = SLOW_ONE_CYCLE;
661 CPU.MemSpeedx2 = SLOW_ONE_CYCLE * 2;
663 CPU.PCBase = Memory.SRAM - 0x6000;
664 CPU.PC = CPU.PCBase + (Address & 0xffff);
667 case CMemory::MAP_C4:
669 CPU.MemSpeed = SLOW_ONE_CYCLE;
670 CPU.MemSpeedx2 = SLOW_ONE_CYCLE * 2;
672 CPU.PCBase = Memory.C4RAM - 0x6000;
673 CPU.PC = CPU.PCBase + (Address & 0xffff);
676 case CMemory::MAP_DEBUG:
678 printf ("SBP %06x\n", Address);
682 case CMemory::MAP_NONE:
684 CPU.MemSpeed = SLOW_ONE_CYCLE;
685 CPU.MemSpeedx2 = SLOW_ONE_CYCLE * 2;
688 printf ("SBP %06x\n", Address);
690 CPU.PCBase = Memory.SRAM;
691 CPU.PC = Memory.SRAM + (Address & 0xffff);