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);
62 mem_check+=(Address>>16)+Address;
64 const int block = (Address >> MEMMAP_SHIFT) & MEMMAP_MASK;
65 uint8 *GetAddress = Memory.Map[block];
67 if (GetAddress >= (uint8 *) CMemory::MAP_LAST)
70 CPU.Cycles += Memory.MemorySpeed [block];
73 if (Memory.BlockIsRAM [block])
74 CPU.WaitAddress = CPU.PCAtOpcodeStart;
76 return (*(GetAddress + (Address & 0xffff)));
79 switch ((CMemory::Types)(intptr_t) GetAddress)
81 case CMemory::MAP_PPU:
84 CPU.Cycles += ONE_CYCLE;
86 return (S9xGetPPU (Address & 0xffff));
87 case CMemory::MAP_CPU:
89 CPU.Cycles += ONE_CYCLE;
91 return (S9xGetCPU (Address & 0xffff));
92 case CMemory::MAP_DSP:
94 CPU.Cycles += SLOW_ONE_CYCLE;
96 return (S9xGetDSP (Address & 0xffff));
97 case CMemory::MAP_SA1RAM:
98 case CMemory::MAP_LOROM_SRAM:
100 CPU.Cycles += SLOW_ONE_CYCLE;
102 return (*(Memory.SRAM + ((Address & CPU.Memory_SRAMMask))));
104 case CMemory::MAP_HIROM_SRAM:
106 CPU.Cycles += SLOW_ONE_CYCLE;
108 return (*(Memory.SRAM + (((Address & 0x7fff) - 0x6000 +
109 ((Address & 0xf0000) >> 3)) & CPU.Memory_SRAMMask)));
111 case CMemory::MAP_DEBUG:
113 printf ("R(B) %06x\n", Address);
116 case CMemory::MAP_BWRAM:
118 CPU.Cycles += SLOW_ONE_CYCLE;
120 return (*(Memory.BWRAM + ((Address & 0x7fff) - 0x6000)));
122 case CMemory::MAP_C4:
123 return (S9xGetC4 (Address & 0xffff));
126 case CMemory::MAP_NONE:
128 CPU.Cycles += SLOW_ONE_CYCLE;
131 printf ("R(B) %06x\n", Address);
133 return ((Address >> 8) & 0xff);
137 INLINE uint16 S9xGetWord (uint32 Address)
141 sprintf(str,"rd @ %04X",Address);
145 mem_check+=(Address>>16)+Address;
147 if ((Address & 0x1fff) == 0x1fff)
149 return (S9xGetByte (Address) | (S9xGetByte (Address + 1) << 8));
152 const int block = (Address >> MEMMAP_SHIFT) & MEMMAP_MASK;
153 uint8 *GetAddress = Memory.Map[block];
155 if (GetAddress >= (uint8 *) CMemory::MAP_LAST)
158 CPU.Cycles += Memory.MemorySpeed [block] << 1;
161 if (Memory.BlockIsRAM [block])
162 CPU.WaitAddress = CPU.PCAtOpcodeStart;
164 #ifdef FAST_LSB_WORD_ACCESS
165 return (*(uint16 *) (GetAddress + (Address & 0xffff)));
167 return (*(GetAddress + (Address & 0xffff)) |
168 (*(GetAddress + (Address & 0xffff) + 1) << 8));
172 switch ((CMemory::Types)(intptr_t) GetAddress)
174 case CMemory::MAP_PPU:
177 CPU.Cycles += TWO_CYCLES;
179 return (S9xGetPPU (Address & 0xffff) |
180 (S9xGetPPU ((Address + 1) & 0xffff) << 8));
181 case CMemory::MAP_CPU:
183 CPU.Cycles += TWO_CYCLES;
185 return (S9xGetCPU (Address & 0xffff) |
186 (S9xGetCPU ((Address + 1) & 0xffff) << 8));
187 case CMemory::MAP_DSP:
189 CPU.Cycles += SLOW_ONE_CYCLE * 2;
191 return (S9xGetDSP (Address & 0xffff) |
192 (S9xGetDSP ((Address + 1) & 0xffff) << 8));
193 case CMemory::MAP_SA1RAM:
194 case CMemory::MAP_LOROM_SRAM:
196 CPU.Cycles += SLOW_ONE_CYCLE * 2;
198 return (*(Memory.SRAM + (Address & CPU.Memory_SRAMMask)) |
199 (*(Memory.SRAM + ((Address + 1) & CPU.Memory_SRAMMask)) << 8));
201 case CMemory::MAP_HIROM_SRAM:
203 CPU.Cycles += SLOW_ONE_CYCLE * 2;
205 return (*(Memory.SRAM +
206 (((Address & 0x7fff) - 0x6000 +
207 ((Address & 0xf0000) >> 3)) & CPU.Memory_SRAMMask)) |
209 ((((Address + 1) & 0x7fff) - 0x6000 +
210 (((Address + 1) & 0xf0000) >> 3)) & CPU.Memory_SRAMMask)) << 8));
212 case CMemory::MAP_BWRAM:
214 CPU.Cycles += SLOW_ONE_CYCLE * 2;
216 return (*(Memory.BWRAM + ((Address & 0x7fff) - 0x6000)) |
217 (*(Memory.BWRAM + (((Address + 1) & 0x7fff) - 0x6000)) << 8));
219 case CMemory::MAP_DEBUG:
221 printf ("R(W) %06x\n", Address);
224 case CMemory::MAP_C4:
225 return (S9xGetC4 (Address & 0xffff) |
226 (S9xGetC4 ((Address + 1) & 0xffff) << 8));
229 case CMemory::MAP_NONE:
231 CPU.Cycles += SLOW_ONE_CYCLE * 2;
234 printf ("R(W) %06x\n", Address);
236 return (((Address >> 8) | (Address & 0xff00)) & 0xffff);
240 INLINE void S9xSetByte (uint8 Byte, uint32 Address)
244 sprintf(str,"wr @ %04X %02X",Address,Byte);
251 #if defined(CPU_SHUTDOWN)
252 CPU.WaitAddress = NULL;
254 const int block = (Address >> MEMMAP_SHIFT) & MEMMAP_MASK;
255 uint8 *SetAddress = Memory.WriteMap[block];
257 if (SetAddress >= (uint8 *) CMemory::MAP_LAST)
260 CPU.Cycles += Memory.MemorySpeed [block];
263 SetAddress += Address & 0xffff;
265 if (SetAddress == SA1.WaitByteAddress1 ||
266 SetAddress == SA1.WaitByteAddress2)
268 SA1.Executing = SA1.S9xOpcodes != NULL;
274 *(SetAddress + (Address & 0xffff)) = Byte;
279 switch ((CMemory::Types)(intptr_t) SetAddress)
281 case CMemory::MAP_PPU:
284 CPU.Cycles += ONE_CYCLE;
286 S9xSetPPU (Byte, Address & 0xffff);
289 case CMemory::MAP_CPU:
291 CPU.Cycles += ONE_CYCLE;
293 S9xSetCPU (Byte, Address & 0xffff);
296 case CMemory::MAP_DSP:
298 CPU.Cycles += SLOW_ONE_CYCLE;
300 S9xSetDSP (Byte, Address & 0xffff);
303 case CMemory::MAP_LOROM_SRAM:
305 CPU.Cycles += SLOW_ONE_CYCLE;
307 if (CPU.Memory_SRAMMask)
309 *(Memory.SRAM + (Address & CPU.Memory_SRAMMask)) = Byte;
310 CPU.SRAMModified = TRUE;
314 case CMemory::MAP_HIROM_SRAM:
316 CPU.Cycles += SLOW_ONE_CYCLE;
318 if (CPU.Memory_SRAMMask)
320 *(Memory.SRAM + (((Address & 0x7fff) - 0x6000 +
321 ((Address & 0xf0000) >> 3)) & CPU.Memory_SRAMMask)) = Byte;
322 CPU.SRAMModified = TRUE;
326 case CMemory::MAP_BWRAM:
328 CPU.Cycles += SLOW_ONE_CYCLE;
330 *(Memory.BWRAM + ((Address & 0x7fff) - 0x6000)) = Byte;
331 CPU.SRAMModified = TRUE;
334 case CMemory::MAP_DEBUG:
336 printf ("W(B) %06x\n", Address);
339 case CMemory::MAP_SA1RAM:
341 CPU.Cycles += SLOW_ONE_CYCLE;
343 *(Memory.SRAM + (Address & 0xffff)) = Byte;
344 SA1.Executing = !SA1.Waiting;
347 case CMemory::MAP_C4:
348 S9xSetC4 (Byte, Address & 0xffff);
352 case CMemory::MAP_NONE:
354 CPU.Cycles += SLOW_ONE_CYCLE;
357 printf ("W(B) %06x\n", Address);
363 INLINE void S9xSetWord (uint16 Word, uint32 Address)
367 sprintf(str,"wr @ %04X %04X",Address,Word);
373 #if defined(CPU_SHUTDOWN)
374 CPU.WaitAddress = NULL;
376 const int block = (Address >> MEMMAP_SHIFT) & MEMMAP_MASK;
377 uint8 *SetAddress = Memory.WriteMap[block];
379 if (SetAddress >= (uint8 *) CMemory::MAP_LAST)
382 CPU.Cycles += Memory.MemorySpeed [block] << 1;
384 #if defined(CPU_SHUTDOWN) && defined(USE_SA1)
385 uint8 *SetAddressSA1 = SetAddress + (Address & 0xffff);
386 if (SetAddressSA1 == SA1.WaitByteAddress1 ||
387 SetAddressSA1 == SA1.WaitByteAddress2)
389 SA1.Executing = SA1.S9xOpcodes != NULL;
393 #ifdef FAST_LSB_WORD_ACCESS
394 *(uint16 *) (SetAddress + (Address & 0xffff)) = Word;
396 *(SetAddress + (Address & 0xffff)) = (uint8) Word;
397 *(SetAddress + ((Address + 1) & 0xffff)) = Word >> 8;
402 switch ((CMemory::Types)(intptr_t) SetAddress)
404 case CMemory::MAP_PPU:
407 CPU.Cycles += TWO_CYCLES;
409 S9xSetPPU ((uint8) Word, Address & 0xffff);
410 S9xSetPPU (Word >> 8, (Address & 0xffff) + 1);
413 case CMemory::MAP_CPU:
415 CPU.Cycles += TWO_CYCLES;
417 S9xSetCPU ((uint8) Word, (Address & 0xffff));
418 S9xSetCPU (Word >> 8, (Address & 0xffff) + 1);
421 case CMemory::MAP_DSP:
423 CPU.Cycles += SLOW_ONE_CYCLE * 2;
425 S9xSetDSP ((uint8) Word, (Address & 0xffff));
426 S9xSetDSP (Word >> 8, (Address & 0xffff) + 1);
429 case CMemory::MAP_LOROM_SRAM:
431 CPU.Cycles += SLOW_ONE_CYCLE * 2;
433 if (CPU.Memory_SRAMMask)
435 *(Memory.SRAM + (Address & CPU.Memory_SRAMMask)) = (uint8) Word;
436 *(Memory.SRAM + ((Address + 1) & CPU.Memory_SRAMMask)) = Word >> 8;
437 CPU.SRAMModified = TRUE;
441 case CMemory::MAP_HIROM_SRAM:
443 CPU.Cycles += SLOW_ONE_CYCLE * 2;
445 if (CPU.Memory_SRAMMask)
448 ((Address & 0x7fff) - 0x6000) +
449 (((Address & 0xf0000) >> MEMMAP_SHIFT) & CPU.Memory_SRAMMask)
453 (((Address + 1) & 0x7fff) - 0x6000) +
454 ((((Address + 1) & 0xf0000) >> MEMMAP_SHIFT) & CPU.Memory_SRAMMask)
455 ) = (uint8) (Word >> 8);
457 CPU.SRAMModified = TRUE;
461 case CMemory::MAP_BWRAM:
463 CPU.Cycles += SLOW_ONE_CYCLE * 2;
465 *(Memory.BWRAM + ((Address & 0x7fff) - 0x6000)) = (uint8) Word;
466 *(Memory.BWRAM + (((Address + 1) & 0x7fff) - 0x6000)) = (uint8) (Word >> 8);
467 CPU.SRAMModified = TRUE;
470 case CMemory::MAP_DEBUG:
472 printf ("W(W) %06x\n", Address);
475 case CMemory::MAP_SA1RAM:
477 CPU.Cycles += SLOW_ONE_CYCLE;
479 *(Memory.SRAM + (Address & 0xffff)) = (uint8) Word;
480 *(Memory.SRAM + ((Address + 1) & 0xffff)) = (uint8) (Word >> 8);
481 SA1.Executing = !SA1.Waiting;
484 case CMemory::MAP_C4:
485 S9xSetC4 (Word & 0xff, Address & 0xffff);
486 S9xSetC4 ((uint8) (Word >> 8), (Address + 1) & 0xffff);
490 case CMemory::MAP_NONE:
492 CPU.Cycles += SLOW_ONE_CYCLE * 2;
495 printf ("W(W) %06x\n", Address);
501 INLINE uint8 *GetBasePointer (uint32 Address)
503 uint8 *GetAddress = Memory.Map [(Address >> MEMMAP_SHIFT) & MEMMAP_MASK];
504 if (GetAddress >= (uint8 *) CMemory::MAP_LAST)
507 switch ((CMemory::Types)(intptr_t) GetAddress)
509 case CMemory::MAP_PPU:
510 return (Memory.FillRAM - 0x2000);
511 case CMemory::MAP_CPU:
512 return (Memory.FillRAM - 0x4000);
513 case CMemory::MAP_DSP:
514 return (Memory.FillRAM - 0x6000);
515 case CMemory::MAP_SA1RAM:
516 case CMemory::MAP_LOROM_SRAM:
517 return (Memory.SRAM);
518 case CMemory::MAP_BWRAM:
519 return (Memory.BWRAM - 0x6000);
520 case CMemory::MAP_HIROM_SRAM:
521 return (Memory.SRAM - 0x6000);
522 case CMemory::MAP_C4:
523 return (Memory.C4RAM - 0x6000);
524 case CMemory::MAP_DEBUG:
526 printf ("GBP %06x\n", Address);
529 case CMemory::MAP_NONE:
531 printf ("GBP %06x\n", Address);
537 INLINE uint8 *S9xGetMemPointer (uint32 Address)
539 uint8 *GetAddress = Memory.Map [(Address >> MEMMAP_SHIFT) & MEMMAP_MASK];
540 if (GetAddress >= (uint8 *) CMemory::MAP_LAST)
541 return (GetAddress + (Address & 0xffff));
543 switch ((CMemory::Types)(intptr_t) GetAddress)
545 case CMemory::MAP_PPU:
546 return (Memory.FillRAM - 0x2000 + (Address & 0xffff));
547 case CMemory::MAP_CPU:
548 return (Memory.FillRAM - 0x4000 + (Address & 0xffff));
549 case CMemory::MAP_DSP:
550 return (Memory.FillRAM - 0x6000 + (Address & 0xffff));
551 case CMemory::MAP_SA1RAM:
552 case CMemory::MAP_LOROM_SRAM:
553 return (Memory.SRAM + (Address & 0xffff));
554 case CMemory::MAP_BWRAM:
555 return (Memory.BWRAM - 0x6000 + (Address & 0xffff));
556 case CMemory::MAP_HIROM_SRAM:
557 return (Memory.SRAM - 0x6000 + (Address & 0xffff));
559 case CMemory::MAP_C4:
560 return (Memory.C4RAM - 0x6000 + (Address & 0xffff));
562 case CMemory::MAP_DEBUG:
564 printf ("GMP %06x\n", Address);
567 case CMemory::MAP_NONE:
569 printf ("GMP %06x\n", Address);
575 INLINE void S9xSetPCBase (uint32 Address)
579 uint8 *GetAddress = Memory.Map [block = (Address >> MEMMAP_SHIFT) & MEMMAP_MASK];
581 uint8 *GetAddress = Memory.Map [(Address >> MEMMAP_SHIFT) & MEMMAP_MASK];
583 if (GetAddress >= (uint8 *) CMemory::MAP_LAST)
586 CPU.MemSpeed = Memory.MemorySpeed [block];
587 CPU.MemSpeedx2 = CPU.MemSpeed << 1;
589 CPU.PCBase = GetAddress;
590 CPU.PC = GetAddress + (Address & 0xffff);
594 switch ((CMemory::Types)(intptr_t) GetAddress)
596 case CMemory::MAP_PPU:
598 CPU.MemSpeed = ONE_CYCLE;
599 CPU.MemSpeedx2 = TWO_CYCLES;
601 CPU.PCBase = Memory.FillRAM - 0x2000;
602 CPU.PC = CPU.PCBase + (Address & 0xffff);
605 case CMemory::MAP_CPU:
607 CPU.MemSpeed = ONE_CYCLE;
608 CPU.MemSpeedx2 = TWO_CYCLES;
610 CPU.PCBase = Memory.FillRAM - 0x4000;
611 CPU.PC = CPU.PCBase + (Address & 0xffff);
614 case CMemory::MAP_DSP:
616 CPU.MemSpeed = SLOW_ONE_CYCLE;
617 CPU.MemSpeedx2 = SLOW_ONE_CYCLE * 2;
619 CPU.PCBase = Memory.FillRAM - 0x6000;
620 CPU.PC = CPU.PCBase + (Address & 0xffff);
623 case CMemory::MAP_SA1RAM:
624 case CMemory::MAP_LOROM_SRAM:
626 CPU.MemSpeed = SLOW_ONE_CYCLE;
627 CPU.MemSpeedx2 = SLOW_ONE_CYCLE * 2;
629 CPU.PCBase = Memory.SRAM;
630 CPU.PC = CPU.PCBase + (Address & 0xffff);
633 case CMemory::MAP_BWRAM:
635 CPU.MemSpeed = SLOW_ONE_CYCLE;
636 CPU.MemSpeedx2 = SLOW_ONE_CYCLE * 2;
638 CPU.PCBase = Memory.BWRAM - 0x6000;
639 CPU.PC = CPU.PCBase + (Address & 0xffff);
641 case CMemory::MAP_HIROM_SRAM:
643 CPU.MemSpeed = SLOW_ONE_CYCLE;
644 CPU.MemSpeedx2 = SLOW_ONE_CYCLE * 2;
646 CPU.PCBase = Memory.SRAM - 0x6000;
647 CPU.PC = CPU.PCBase + (Address & 0xffff);
650 case CMemory::MAP_C4:
652 CPU.MemSpeed = SLOW_ONE_CYCLE;
653 CPU.MemSpeedx2 = SLOW_ONE_CYCLE * 2;
655 CPU.PCBase = Memory.C4RAM - 0x6000;
656 CPU.PC = CPU.PCBase + (Address & 0xffff);
659 case CMemory::MAP_DEBUG:
661 printf ("SBP %06x\n", Address);
665 case CMemory::MAP_NONE:
667 CPU.MemSpeed = SLOW_ONE_CYCLE;
668 CPU.MemSpeedx2 = SLOW_ONE_CYCLE * 2;
671 printf ("SBP %06x\n", Address);
673 CPU.PCBase = Memory.SRAM;
674 CPU.PC = Memory.SRAM + (Address & 0xffff);