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.
56 uint8 buffer[0x10000];
59 extern int HDMA_ModeByteCounts [8];
60 extern uint8 *HDMAMemPointers [8];
61 extern uint8 *HDMABasePointers [8];
63 #if defined(__linux__) || defined(__WIN32__) || defined(__GP2X__) || defined(__GIZ__)
64 static int S9xCompareSDD1IndexEntries (const void *p1, const void *p2)
66 return (*(uint32 *) p1 - *(uint32 *) p2);
70 /**********************************************************************************************/
72 /* This function preforms the general dma transfer */
73 /**********************************************************************************************/
74 void S9xDoDMA (uint8 Channel)
78 if (Channel > 7 || CPU.InDMA)
82 bool8 in_sa1_dma = FALSE;
83 uint8 *in_sdd1_dma = NULL;
84 SDMA *d = &DMA[Channel];
86 int count = d->TransferBytes;
91 int inc = d->AAddressFixed ? 0 : (!d->AAddressDecrement ? 1 : -1);
97 if (IPPU.RenderThisFrame)
104 if (d->AAddressFixed && Memory.FillRAM [0x4801] > 0)
106 // Hacky support for pre-decompressed S-DD1 data
107 inc = !d->AAddressDecrement ? 1 : -1;
108 uint32 address = (((d->ABank << 16) | d->AAddress) & 0xfffff) << 4;
110 address |= Memory.FillRAM [0x4804 + ((d->ABank - 0xc0) >> 4)];
111 if(Settings.SDD1Pack)
113 uint8* in_ptr=GetBasePointer(((d->ABank << 16) | d->AAddress));
116 SDD1_decompress(buffer,in_ptr,d->TransferBytes);
121 #if defined (__linux__)
122 void *ptr = bsearch (&address, Memory.SDD1Index,
123 Memory.SDD1Entries, 12, S9xCompareSDD1IndexEntries);
125 in_sdd1_dma = *(uint32 *) ((uint8 *) ptr + 4) + Memory.SDD1Data;
127 uint8 *ptr = Memory.SDD1Index;
129 for (uint32 e = 0; e < Memory.SDD1Entries; e++, ptr += 12)
131 if (address == *(uint32 *) ptr)
133 in_sdd1_dma = *(uint32 *) (ptr + 4) + Memory.SDD1Data;
141 // No matching decompressed data found. Must be some new
142 // graphics not encountered before. Log it if it hasn't been
144 uint8 *p = Memory.SDD1LoggedData;
146 uint8 SDD1Bank = Memory.FillRAM [0x4804 + ((d->ABank - 0xc0) >> 4)] | 0xf0;
148 for (uint32 i = 0; i < Memory.SDD1LoggedDataCount; i++, p += 8)
150 if (*p == d->ABank ||
151 *(p + 1) == (d->AAddress >> 8) &&
152 *(p + 2) == (d->AAddress & 0xff) &&
153 *(p + 3) == (count >> 8) &&
154 *(p + 4) == (count & 0xff) &&
155 *(p + 7) == SDD1Bank)
161 if (!found && Memory.SDD1LoggedDataCount < MEMMAP_MAX_SDD1_LOGGED_ENTRIES)
164 *(p + 1) = d->AAddress >> 8;
165 *(p + 2) = d->AAddress & 0xff;
166 *(p + 3) = count >> 8;
167 *(p + 4) = count & 0xff;
169 Memory.SDD1LoggedDataCount += 1;
174 Memory.FillRAM [0x4801] = 0;
178 if (d->BAddress == 0x18 && SA1.in_char_dma && (d->ABank & 0xf0) == 0x40)
180 if (d->BAddress == 0x18 && (d->ABank & 0xf0) == 0x40)
183 // Perform packed bitmap to PPU character format conversion on the
184 // data before transmitting it to V-RAM via-DMA.
185 int num_chars = 1 << ((Memory.FillRAM [0x2231] >> 2) & 7);
186 int depth = (Memory.FillRAM [0x2231] & 3) == 0 ? 8 :
187 (Memory.FillRAM [0x2231] & 3) == 1 ? 4 : 2;
189 int bytes_per_char = 8 * depth;
190 int bytes_per_line = depth * num_chars;
191 int char_line_bytes = bytes_per_char * num_chars;
192 uint32 addr = (d->AAddress / char_line_bytes) * char_line_bytes;
193 uint8 *base = GetBasePointer ((d->ABank << 16) + addr) + addr;
194 uint8 *buffer = &Memory.ROM [CMemory::MAX_ROM_SIZE - 0x10000];
196 uint32 inc = char_line_bytes - (d->AAddress % char_line_bytes);
197 uint32 char_count = inc / bytes_per_char;
201 //printf ("%08x,", base); fflush (stdout);
202 //printf ("depth = %d, count = %d, bytes_per_char = %d, bytes_per_line = %d, num_chars = %d, char_line_bytes = %d\n",
203 //depth, count, bytes_per_char, bytes_per_line, num_chars, char_line_bytes);
209 for (i = 0; i < count; i += inc, base += char_line_bytes,
210 inc = char_line_bytes, char_count = num_chars)
212 uint8 *line = base + (num_chars - char_count) * 2;
213 for (uint32 j = 0; j < char_count && p - buffer < count;
217 for (int l = 0; l < 8; l++, q += bytes_per_line)
219 for (int b = 0; b < 2; b++)
222 *(p + 0) = (*(p + 0) << 1) | ((r >> 0) & 1);
223 *(p + 1) = (*(p + 1) << 1) | ((r >> 1) & 1);
224 *(p + 0) = (*(p + 0) << 1) | ((r >> 2) & 1);
225 *(p + 1) = (*(p + 1) << 1) | ((r >> 3) & 1);
226 *(p + 0) = (*(p + 0) << 1) | ((r >> 4) & 1);
227 *(p + 1) = (*(p + 1) << 1) | ((r >> 5) & 1);
228 *(p + 0) = (*(p + 0) << 1) | ((r >> 6) & 1);
229 *(p + 1) = (*(p + 1) << 1) | ((r >> 7) & 1);
237 for (i = 0; i < count; i += inc, base += char_line_bytes,
238 inc = char_line_bytes, char_count = num_chars)
240 uint8 *line = base + (num_chars - char_count) * 4;
241 for (uint32 j = 0; j < char_count && p - buffer < count;
245 for (int l = 0; l < 8; l++, q += bytes_per_line)
247 for (int b = 0; b < 4; b++)
250 *(p + 0) = (*(p + 0) << 1) | ((r >> 0) & 1);
251 *(p + 1) = (*(p + 1) << 1) | ((r >> 1) & 1);
252 *(p + 16) = (*(p + 16) << 1) | ((r >> 2) & 1);
253 *(p + 17) = (*(p + 17) << 1) | ((r >> 3) & 1);
254 *(p + 0) = (*(p + 0) << 1) | ((r >> 4) & 1);
255 *(p + 1) = (*(p + 1) << 1) | ((r >> 5) & 1);
256 *(p + 16) = (*(p + 16) << 1) | ((r >> 6) & 1);
257 *(p + 17) = (*(p + 17) << 1) | ((r >> 7) & 1);
266 for (i = 0; i < count; i += inc, base += char_line_bytes,
267 inc = char_line_bytes, char_count = num_chars)
269 uint8 *line = base + (num_chars - char_count) * 8;
270 for (uint32 j = 0; j < char_count && p - buffer < count;
274 for (int l = 0; l < 8; l++, q += bytes_per_line)
276 for (int b = 0; b < 8; b++)
279 *(p + 0) = (*(p + 0) << 1) | ((r >> 0) & 1);
280 *(p + 1) = (*(p + 1) << 1) | ((r >> 1) & 1);
281 *(p + 16) = (*(p + 16) << 1) | ((r >> 2) & 1);
282 *(p + 17) = (*(p + 17) << 1) | ((r >> 3) & 1);
283 *(p + 32) = (*(p + 32) << 1) | ((r >> 4) & 1);
284 *(p + 33) = (*(p + 33) << 1) | ((r >> 5) & 1);
285 *(p + 48) = (*(p + 48) << 1) | ((r >> 6) & 1);
286 *(p + 49) = (*(p + 49) << 1) | ((r >> 7) & 1);
298 if (Settings.TraceDMA)
300 sprintf (String, "DMA[%d]: %s Mode: %d 0x%02X%04X->0x21%02X Bytes: %d (%s) V-Line:%ld",
301 Channel, d->TransferDirection ? "read" : "write",
302 d->TransferMode, d->ABank, d->AAddress,
303 d->BAddress, d->TransferBytes,
304 d->AAddressFixed ? "fixed" :
305 (d->AAddressDecrement ? "dec" : "inc"),
307 if (d->BAddress == 0x18 || d->BAddress == 0x19)
308 sprintf (String, "%s VRAM: %04X (%d,%d) %s", String,
310 PPU.VMA.Increment, PPU.VMA.FullGraphicCount,
311 PPU.VMA.High ? "word" : "byte");
313 if (d->BAddress == 0x22)
314 sprintf (String, "%s CGRAM: %02X (%x)", String, PPU.CGADD,
317 if (d->BAddress == 0x04)
318 sprintf (String, "%s OBJADDR: %04X", String, PPU.OAMAddr);
319 S9xMessage (S9X_TRACE, S9X_DMA_TRACE, String);
323 if (!d->TransferDirection)
326 CPU.Cycles += 8 * count;
328 CPU.Cycles += count + (count >> 2);
330 uint8 *base = GetBasePointer ((d->ABank << 16) + d->AAddress);
331 uint16 p = d->AAddress;
338 base = &Memory.ROM [CMemory::MAX_ROM_SIZE - 0x10000];
349 d->AAddress += count;
352 d->AAddress -= count;
354 if (d->TransferMode == 0 || d->TransferMode == 2)
365 } while (--count > 0);
368 IPPU.FirstVRAMRead = TRUE;
369 if (!PPU.VMA.FullGraphicCount)
374 REGISTER_2118_linear(Work);
377 } while (--count > 0);
384 REGISTER_2118_tile(Work);
387 } while (--count > 0);
391 IPPU.FirstVRAMRead = TRUE;
392 if (!PPU.VMA.FullGraphicCount)
397 REGISTER_2119_linear(Work);
400 } while (--count > 0);
407 REGISTER_2119_tile(Work);
410 } while (--count > 0);
420 } while (--count > 0);
429 } while (--count > 0);
435 S9xSetPPU (Work, 0x2100 + d->BAddress);
438 } while (--count > 0);
443 if (d->TransferMode == 1 || d->TransferMode == 5)
445 if (d->BAddress == 0x18)
448 IPPU.FirstVRAMRead = TRUE;
449 if (!PPU.VMA.FullGraphicCount)
454 REGISTER_2118_linear(Work);
458 REGISTER_2119_linear(Work);
466 REGISTER_2118_linear(Work);
475 REGISTER_2118_tile(Work);
479 REGISTER_2119_tile(Work);
487 REGISTER_2118_tile(Work);
494 // DMA mode 1 general case
498 S9xSetPPU (Work, 0x2100 + d->BAddress);
502 S9xSetPPU (Work, 0x2101 + d->BAddress);
510 S9xSetPPU (Work, 0x2100 + d->BAddress);
516 if (d->TransferMode == 3)
521 S9xSetPPU (Work, 0x2100 + d->BAddress);
527 S9xSetPPU (Work, 0x2100 + d->BAddress);
533 S9xSetPPU (Work, 0x2101 + d->BAddress);
539 S9xSetPPU (Work, 0x2101 + d->BAddress);
546 if (d->TransferMode == 4)
551 S9xSetPPU (Work, 0x2100 + d->BAddress);
557 S9xSetPPU (Work, 0x2101 + d->BAddress);
563 S9xSetPPU (Work, 0x2102 + d->BAddress);
569 S9xSetPPU (Work, 0x2103 + d->BAddress);
578 // if (Settings.TraceDMA)
580 sprintf (String, "Unknown DMA transfer mode: %d on channel %d\n",
581 d->TransferMode, Channel);
582 S9xMessage (S9X_TRACE, S9X_DMA_TRACE, String);
591 switch (d->TransferMode)
598 Work = S9xGetPPU (0x2100 + d->BAddress);
599 S9xSetByte (Work, (d->ABank << 16) + d->AAddress);
609 Work = S9xGetPPU (0x2100 + d->BAddress);
610 S9xSetByte (Work, (d->ABank << 16) + d->AAddress);
615 Work = S9xGetPPU (0x2101 + d->BAddress);
616 S9xSetByte (Work, (d->ABank << 16) + d->AAddress);
625 Work = S9xGetPPU (0x2100 + d->BAddress);
626 S9xSetByte (Work, (d->ABank << 16) + d->AAddress);
631 Work = S9xGetPPU (0x2100 + d->BAddress);
632 S9xSetByte (Work, (d->ABank << 16) + d->AAddress);
637 Work = S9xGetPPU (0x2101 + d->BAddress);
638 S9xSetByte (Work, (d->ABank << 16) + d->AAddress);
643 Work = S9xGetPPU (0x2101 + d->BAddress);
644 S9xSetByte (Work, (d->ABank << 16) + d->AAddress);
653 Work = S9xGetPPU (0x2100 + d->BAddress);
654 S9xSetByte (Work, (d->ABank << 16) + d->AAddress);
659 Work = S9xGetPPU (0x2101 + d->BAddress);
660 S9xSetByte (Work, (d->ABank << 16) + d->AAddress);
665 Work = S9xGetPPU (0x2102 + d->BAddress);
666 S9xSetByte (Work, (d->ABank << 16) + d->AAddress);
671 Work = S9xGetPPU (0x2103 + d->BAddress);
672 S9xSetByte (Work, (d->ABank << 16) + d->AAddress);
679 if (1) //Settings.TraceDMA)
681 sprintf (String, "Unknown DMA transfer mode: %d on channel %d\n",
682 d->TransferMode, Channel);
683 S9xMessage (S9X_TRACE, S9X_DMA_TRACE, String);
694 #ifdef SPC700_SHUTDOWN
695 CPU.APU_APUExecuting = Settings.APUEnabled;
697 APU_EXECUTE(1); // execute but only in normal mode
699 while (CPU.Cycles > CPU.NextEvent)
700 S9xDoHBlankProcessing ();
702 // Super Punch-Out requires that the A-BUS address be updated after the
704 Memory.FillRAM[0x4302 + (Channel << 4)] = (uint8) d->AAddress;
705 Memory.FillRAM[0x4303 + (Channel << 4)] = d->AAddress >> 8;
707 // Secret of the Mana requires that the DMA bytes transfer count be set to
708 // zero when DMA has completed.
709 Memory.FillRAM [0x4305 + (Channel << 4)] = 0;
710 Memory.FillRAM [0x4306 + (Channel << 4)] = 0;
712 DMA[Channel].IndirectAddress = 0;
713 d->TransferBytes = 0;
720 if (Settings.DisableHDMA)
723 missing.hdma_this_frame = IPPU.HDMA = Memory.FillRAM [0x420c];
725 IPPU.HDMAStarted = TRUE;
727 for (uint8 i = 0; i < 8; i++)
729 if (IPPU.HDMA & (1 << i))
731 DMA [i].LineCount = 0;
732 DMA [i].FirstLine = TRUE;
733 DMA [i].Address = DMA [i].AAddress;
735 HDMAMemPointers [i] = NULL;
740 void S9xTraceSoundDSP (const char *s, int i1 = 0, int i2 = 0, int i3 = 0,
741 int i4 = 0, int i5 = 0, int i6 = 0, int i7 = 0);
745 uint8 S9xDoHDMA (uint8 byte)
747 struct SDMA *p = &DMA [0];
751 for (uint8 mask = 1; mask; mask <<= 1, p++, d++)
757 uint8 line = S9xGetByte ((p->ABank << 16) + p->Address);
765 p->Repeat = !(line & 0x80);
766 p->LineCount = line & 0x7f;
769 // Disable H-DMA'ing into V-RAM (register 2118) for Hook
770 if (!p->LineCount || p->BAddress == 0x18)
773 p->IndirectAddress += HDMAMemPointers [d] - HDMABasePointers [d];
774 Memory.FillRAM [0x4305 + (d << 4)] = (uint8) p->IndirectAddress;
775 Memory.FillRAM [0x4306 + (d << 4)] = p->IndirectAddress >> 8;
781 if (p->HDMAIndirectAddressing)
783 p->IndirectBank = Memory.FillRAM [0x4307 + ((p - DMA) << 4)];
784 p->IndirectAddress = S9xGetWord ((p->ABank << 16) + p->Address);
789 p->IndirectBank = p->ABank;
790 p->IndirectAddress = p->Address;
792 HDMABasePointers [d] = HDMAMemPointers [d] =
793 S9xGetMemPointer ((p->IndirectBank << 16) + p->IndirectAddress);
795 if (!HDMAMemPointers [d])
797 if (!(HDMABasePointers [d] = HDMAMemPointers [d] =
798 S9xGetMemPointer ((p->IndirectBank << 16) + p->IndirectAddress)))
803 // Uncommenting the following line breaks Punchout - it starts
804 // H-DMA during the frame.
805 //p->FirstLine = TRUE;
807 if (p->Repeat && !p->FirstLine)
814 if (Settings.TraceSoundDSP && p->FirstLine &&
815 p->BAddress >= 0x40 && p->BAddress <= 0x43)
816 S9xTraceSoundDSP ("Spooling data!!!\n");
818 if (Settings.TraceHDMA && p->FirstLine)
820 sprintf (String, "H-DMA[%d] (%d) 0x%02X%04X->0x21%02X %s, Count: %3d, Rep: %s, V-LINE: %3ld %02X%04X",
821 p-DMA, p->TransferMode, p->IndirectBank,
824 p->HDMAIndirectAddressing ? "ind" : "abs",
826 p->Repeat ? "yes" : "no ", CPU.V_Counter,
827 p->ABank, p->Address);
828 S9xMessage (S9X_TRACE, S9X_HDMA_TRACE, String);
831 switch (p->TransferMode)
839 S9xSetPPU (*HDMAMemPointers [d]++, 0x2100 + p->BAddress);
848 S9xSetPPU (*(HDMAMemPointers [d] + 0), 0x2100 + p->BAddress);
849 S9xSetPPU (*(HDMAMemPointers [d] + 1), 0x2101 + p->BAddress);
850 HDMAMemPointers [d] += 2;
859 S9xSetPPU (*(HDMAMemPointers [d] + 0), 0x2100 + p->BAddress);
860 S9xSetPPU (*(HDMAMemPointers [d] + 1), 0x2100 + p->BAddress);
861 HDMAMemPointers [d] += 2;
870 S9xSetPPU (*(HDMAMemPointers [d] + 0), 0x2100 + p->BAddress);
871 S9xSetPPU (*(HDMAMemPointers [d] + 1), 0x2100 + p->BAddress);
872 S9xSetPPU (*(HDMAMemPointers [d] + 2), 0x2101 + p->BAddress);
873 S9xSetPPU (*(HDMAMemPointers [d] + 3), 0x2101 + p->BAddress);
874 HDMAMemPointers [d] += 4;
882 S9xSetPPU (*(HDMAMemPointers [d] + 0), 0x2100 + p->BAddress);
883 S9xSetPPU (*(HDMAMemPointers [d] + 1), 0x2101 + p->BAddress);
884 S9xSetPPU (*(HDMAMemPointers [d] + 2), 0x2102 + p->BAddress);
885 S9xSetPPU (*(HDMAMemPointers [d] + 3), 0x2103 + p->BAddress);
886 HDMAMemPointers [d] += 4;
889 if (!p->HDMAIndirectAddressing)
890 p->Address += HDMA_ModeByteCounts [p->TransferMode];
891 p->FirstLine = FALSE;
901 for (d = 0; d < 8; d++)
903 DMA [d].TransferDirection = FALSE;
904 DMA [d].HDMAIndirectAddressing = FALSE;
905 DMA [d].AAddressFixed = TRUE;
906 DMA [d].AAddressDecrement = FALSE;
907 DMA [d].TransferMode = 0xff;
908 DMA [d].ABank = 0xff;
909 DMA [d].AAddress = 0xffff;
910 DMA [d].Address = 0xffff;
911 DMA [d].BAddress = 0xff;
912 DMA [d].TransferBytes = 0xffff;
914 for (int c = 0x4300; c < 0x4380; c += 0x10)
916 for (d = c; d < c + 12; d++)
917 Memory.FillRAM [d] = 0xff;
919 Memory.FillRAM [c + 0xf] = 0xff;