1 /* FCE Ultra - NES/Famicom Emulator
\r
3 * Copyright notice for this file:
\r
4 * Copyright (C) 2002 Xodnizel
\r
6 * This program is free software; you can redistribute it and/or modify
\r
7 * it under the terms of the GNU General Public License as published by
\r
8 * the Free Software Foundation; either version 2 of the License, or
\r
9 * (at your option) any later version.
\r
11 * This program is distributed in the hope that it will be useful,
\r
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
14 * GNU General Public License for more details.
\r
16 * You should have received a copy of the GNU General Public License
\r
17 * along with this program; if not, write to the Free Software
\r
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
\r
21 /* None of this code should use any of the iNES bank switching wrappers. */
\r
25 static void (*sfun)(int P);
\r
26 static void (*psfun)(void);
\r
28 void MMC5RunSound(int Count);
\r
29 void MMC5RunSoundHQ(void);
\r
31 static INLINE void MMC5SPRVROM_BANK1(uint32 A,uint32 V)
\r
36 MMC5SPRVPage[(A)>>10]=&CHRptr[0][(V)<<10]-(A);
\r
40 static INLINE void MMC5BGVROM_BANK1(uint32 A,uint32 V) {if(CHRptr[0]){V&=CHRmask1[0];MMC5BGVPage[(A)>>10]=&CHRptr[0][(V)<<10]-(A);}}
\r
42 static INLINE void MMC5SPRVROM_BANK2(uint32 A,uint32 V) {if(CHRptr[0]){V&=CHRmask2[0];MMC5SPRVPage[(A)>>10]=MMC5SPRVPage[((A)>>10)+1]=&CHRptr[0][(V)<<11]-(A);}}
\r
43 static INLINE void MMC5BGVROM_BANK2(uint32 A,uint32 V) {if(CHRptr[0]){V&=CHRmask2[0];MMC5BGVPage[(A)>>10]=MMC5BGVPage[((A)>>10)+1]=&CHRptr[0][(V)<<11]-(A);}}
\r
45 static INLINE void MMC5SPRVROM_BANK4(uint32 A,uint32 V) {if(CHRptr[0]){V&=CHRmask4[0];MMC5SPRVPage[(A)>>10]=MMC5SPRVPage[((A)>>10)+1]= MMC5SPRVPage[((A)>>10)+2]=MMC5SPRVPage[((A)>>10)+3]=&CHRptr[0][(V)<<12]-(A);}}
\r
46 static INLINE void MMC5BGVROM_BANK4(uint32 A,uint32 V) {if(CHRptr[0]){V&=CHRmask4[0];MMC5BGVPage[(A)>>10]=MMC5BGVPage[((A)>>10)+1]=MMC5BGVPage[((A)>>10)+2]=MMC5BGVPage[((A)>>10)+3]=&CHRptr[0][(V)<<12]-(A);}}
\r
48 static INLINE void MMC5SPRVROM_BANK8(uint32 V) {if(CHRptr[0]){V&=CHRmask8[0];MMC5SPRVPage[0]=MMC5SPRVPage[1]=MMC5SPRVPage[2]=MMC5SPRVPage[3]=MMC5SPRVPage[4]=MMC5SPRVPage[5]=MMC5SPRVPage[6]=MMC5SPRVPage[7]=&CHRptr[0][(V)<<13];}}
\r
49 static INLINE void MMC5BGVROM_BANK8(uint32 V) {if(CHRptr[0]){V&=CHRmask8[0];MMC5BGVPage[0]=MMC5BGVPage[1]=MMC5BGVPage[2]=MMC5BGVPage[3]=MMC5BGVPage[4]=MMC5BGVPage[5]=MMC5BGVPage[6]=MMC5BGVPage[7]=&CHRptr[0][(V)<<13];}}
\r
51 static uint8 PRGBanks[4];
\r
52 static uint8 WRAMPage;
\r
53 static uint16 CHRBanksA[8], CHRBanksB[4];
\r
54 static uint8 WRAMMaskEnable[2];
\r
55 uint8 mmc5ABMode; /* A=0, B=1 */
\r
57 static uint8 IRQScanline,IRQEnable;
\r
58 static uint8 CHRMode, NTAMirroring, NTFill, ATFill;
\r
60 static uint8 MMC5IRQR;
\r
61 static uint8 MMC5LineCounter;
\r
62 static uint8 mmc5psize, mmc5vsize;
\r
63 static uint8 mul[2];
\r
65 static uint8 *WRAM=NULL;
\r
66 static uint8 *MMC5fill=NULL;
\r
67 static uint8 *ExRAM=NULL;
\r
69 static uint8 MMC5WRAMsize;
\r
70 static uint8 MMC5WRAMIndex[8];
\r
72 static uint8 MMC5ROMWrProtect[4];
\r
73 static uint8 MMC5MemIn[5];
\r
75 static void MMC5CHRA(void);
\r
76 static void MMC5CHRB(void);
\r
78 typedef struct __cartdata {
\r
83 #define Sprite16 (PPU[0]&0x20) //Sprites 8x16/8x8
\r
84 //#define MMC5SPRVRAMADR(V) &MMC5SPRVPage[(V)>>10][(V)]
\r
85 static inline uint8 * MMC5BGVRAMADR(uint32 A)
\r
89 return &MMC5SPRVPage[(A)>>10][(A)];
\r
91 return &MMC5BGVPage[(A)>>10][(A)];
\r
92 } else return &MMC5BGVPage[(A)>>10][(A)];
\r
95 static void mmc5_PPUWrite(uint32 A, uint8 V) {
\r
97 extern uint8 PALRAM[0x20];
\r
103 PALRAM[0x00]=PALRAM[0x04]=PALRAM[0x08]=PALRAM[0x0C]=V&0x3F;
\r
104 else if(tmp&3) PALRAM[(tmp&0x1f)]=V&0x3f;
\r
106 else if(tmp<0x2000)
\r
108 if(PPUCHRRAM&(1<<(tmp>>10)))
\r
109 VPage[tmp>>10][tmp]=V;
\r
113 if(PPUNTARAM&(1<<((tmp&0xF00)>>10)))
\r
114 vnapage[((tmp&0xF00)>>10)][tmp&0x3FF]=V;
\r
118 uint8 FASTCALL mmc5_PPURead(uint32 A) {
\r
121 if(ppuphase == PPUPHASE_BG)
\r
122 return *MMC5BGVRAMADR(A);
\r
123 else return MMC5SPRVPage[(A)>>10][(A)];
\r
127 return vnapage[(A>>10)&0x3][A&0x3FF];
\r
133 // ELROM seems to have 8KB of RAM
\r
134 // ETROM seems to have 16KB of WRAM
\r
135 // EWROM seems to have 32KB of WRAM
\r
137 cartdata MMC5CartList[]=
\r
139 {0x9c18762b,2}, /* L'Empereur */
\r
142 {0xaca15643,2}, /* Uncharted Waters */
\r
143 {0xfe3488d1,2}, /* Dai Koukai Jidai */
\r
144 {0x15fe6d0f,2}, /* BKAC */
\r
145 {0x39f2ce4b,2}, /* Suikoden */
\r
146 {0x8ce478db,2}, /* Nobunaga's Ambition 2 */
\r
149 {0x1ced086f,2}, /* Ishin no Arashi */
\r
150 {0xf540677b,4}, /* Nobunaga...Bushou Fuuun Roku */
\r
151 {0x6f4e4312,4}, /* Aoki Ookami..Genchou */
\r
152 {0xf011e490,4}, /* Romance of the 3 Kingdoms 2 */
\r
153 {0x184c2124,4}, /* Sangokushi 2 */
\r
157 #define MMC5_NOCARTS (sizeof(MMC5CartList)/sizeof(MMC5CartList[0]))
\r
158 int DetectMMC5WRAMSize(uint32 crc32)
\r
161 for(x=0;x<MMC5_NOCARTS;x++) {
\r
162 if(crc32==MMC5CartList[x].crc32) {
\r
163 FCEU_printf(" >8KB external WRAM present. Use UNIF if you hack the ROM image.\n");
\r
164 return(MMC5CartList[x].size*8);
\r
168 //mbg 04-aug-08 - previously, this was returning 8KB
\r
169 //but I changed it to return 64 because unlisted carts are probably homebrews, and they should probably use 64 (why not use it all?)
\r
170 //ch4 10-dec-08 - then f***ng for what all this shit above? let's give em all this 64k shit! Damn
\r
171 // homebrew must use it's own emulators or standart features.
\r
172 //adelikat 20-dec-08 - reverting back to return 64, sounds like it was changed back to 8 simply on principle. FCEUX is all encompassing, and that include
\r
173 //rom-hacking. We want it to be the best emulator for such purposes. So unless return 64 harms compatibility with anything else, I see now reason not to have it
\r
174 //mbg 29-mar-09 - I should note that mmc5 is in principle capable of 64KB, even if no real carts ever supported it.
\r
175 //This does not in principle break any games which share this mapper, and it should be OK for homebrew.
\r
176 //if there are games which need 8KB instead of 64KB default then lets add them to the list
\r
180 static void BuildWRAMSizeTable(void)
\r
185 switch(MMC5WRAMsize)
\r
187 case 0: MMC5WRAMIndex[x]=255; break; //X,X,X,X,X,X,X,X
\r
188 case 1: MMC5WRAMIndex[x]=(x>3)?255:0; break; //0,0,0,0,X,X,X,X
\r
189 case 2: MMC5WRAMIndex[x]=(x&4)>>2; break; //0,0,0,0,1,1,1,1
\r
190 case 4: MMC5WRAMIndex[x]=(x>3)?255:(x&3); break; //0,1,2,3,X,X,X,X
\r
191 case 8: MMC5WRAMIndex[x]=x; break; //0,1,2,3,4,5,6,7,8
\r
192 //mbg 8/6/08 - i added this to support 64KB of wram
\r
193 //now, I have at least one example (laser invasion) which actually uses size 1 but isnt in the crc list
\r
194 //so, whereas before my change on 8/4/08 we would have selected size 1, now we select size 8
\r
195 //this means that we could have just introduced an emulation bug, in case those games happened to
\r
196 //address, say, page 3. with size 1 that would resolve to [0] but in size 8 it resolves to [3].
\r
197 //so, you know what to do if there are problems.
\r
202 static void MMC5CHRA(void)
\r
205 switch(mmc5vsize&3)
\r
207 case 0: setchr8(CHRBanksA[7]);
\r
208 MMC5SPRVROM_BANK8(CHRBanksA[7]);
\r
210 case 1: setchr4(0x0000,CHRBanksA[3]);
\r
211 setchr4(0x1000,CHRBanksA[7]);
\r
212 MMC5SPRVROM_BANK4(0x0000,CHRBanksA[3]);
\r
213 MMC5SPRVROM_BANK4(0x1000,CHRBanksA[7]);
\r
215 case 2: setchr2(0x0000,CHRBanksA[1]);
\r
216 setchr2(0x0800,CHRBanksA[3]);
\r
217 setchr2(0x1000,CHRBanksA[5]);
\r
218 setchr2(0x1800,CHRBanksA[7]);
\r
219 MMC5SPRVROM_BANK2(0x0000,CHRBanksA[1]);
\r
220 MMC5SPRVROM_BANK2(0x0800,CHRBanksA[3]);
\r
221 MMC5SPRVROM_BANK2(0x1000,CHRBanksA[5]);
\r
222 MMC5SPRVROM_BANK2(0x1800,CHRBanksA[7]);
\r
224 case 3: for(x=0;x<8;x++)
\r
226 setchr1(x<<10,CHRBanksA[x]);
\r
227 MMC5SPRVROM_BANK1(x<<10,CHRBanksA[x]);
\r
233 static void MMC5CHRB(void)
\r
236 switch(mmc5vsize&3)
\r
238 case 0: setchr8(CHRBanksB[3]);
\r
239 MMC5BGVROM_BANK8(CHRBanksB[3]);
\r
241 case 1: setchr4(0x0000,CHRBanksB[3]);
\r
242 setchr4(0x1000,CHRBanksB[3]);
\r
243 MMC5BGVROM_BANK4(0x0000,CHRBanksB[3]);
\r
244 MMC5BGVROM_BANK4(0x1000,CHRBanksB[3]);
\r
246 case 2: setchr2(0x0000,CHRBanksB[1]);
\r
247 setchr2(0x0800,CHRBanksB[3]);
\r
248 setchr2(0x1000,CHRBanksB[1]);
\r
249 setchr2(0x1800,CHRBanksB[3]);
\r
250 MMC5BGVROM_BANK2(0x0000,CHRBanksB[1]);
\r
251 MMC5BGVROM_BANK2(0x0800,CHRBanksB[3]);
\r
252 MMC5BGVROM_BANK2(0x1000,CHRBanksB[1]);
\r
253 MMC5BGVROM_BANK2(0x1800,CHRBanksB[3]);
\r
255 case 3: for(x=0;x<8;x++)
\r
257 setchr1(x<<10,CHRBanksB[x&3]);
\r
258 MMC5BGVROM_BANK1(x<<10,CHRBanksB[x&3]);
\r
264 static void MMC5WRAM(uint32 A, uint32 V)
\r
266 //printf("%02x\n",V);
\r
267 V=MMC5WRAMIndex[V&7];
\r
270 setprg8r(0x10,A,V);
\r
271 MMC5MemIn[(A-0x6000)>>13]=1;
\r
274 MMC5MemIn[(A-0x6000)>>13]=0;
\r
277 static void MMC5PRG(void)
\r
280 switch(mmc5psize&3)
\r
282 case 0: MMC5ROMWrProtect[0]=MMC5ROMWrProtect[1]=
\r
283 MMC5ROMWrProtect[2]=MMC5ROMWrProtect[3]=1;
\r
284 setprg32(0x8000,((PRGBanks[1]&0x7F)>>2));
\r
288 case 1: if(PRGBanks[1]&0x80)
\r
290 MMC5ROMWrProtect[0]=MMC5ROMWrProtect[1]=1;
\r
291 setprg16(0x8000,(PRGBanks[1]>>1));
\r
292 MMC5MemIn[1]=MMC5MemIn[2]=1;
\r
296 MMC5ROMWrProtect[0]=MMC5ROMWrProtect[1]=0;
\r
297 MMC5WRAM(0x8000,PRGBanks[1]&7&0xFE);
\r
298 MMC5WRAM(0xA000,(PRGBanks[1]&7&0xFE)+1);
\r
300 MMC5MemIn[3]=MMC5MemIn[4]=1;
\r
301 MMC5ROMWrProtect[2]=MMC5ROMWrProtect[3]=1;
\r
302 setprg16(0xC000,(PRGBanks[3]&0x7F)>>1);
\r
304 case 2: if(PRGBanks[1]&0x80)
\r
306 MMC5MemIn[1]=MMC5MemIn[2]=1;
\r
307 MMC5ROMWrProtect[0]=MMC5ROMWrProtect[1]=1;
\r
308 setprg16(0x8000,(PRGBanks[1]&0x7F)>>1);
\r
312 MMC5ROMWrProtect[0]=MMC5ROMWrProtect[1]=0;
\r
313 MMC5WRAM(0x8000,PRGBanks[1]&7&0xFE);
\r
314 MMC5WRAM(0xA000,(PRGBanks[1]&7&0xFE)+1);
\r
316 if(PRGBanks[2]&0x80)
\r
318 MMC5ROMWrProtect[2]=1;
\r
320 setprg8(0xC000,PRGBanks[2]&0x7F);
\r
324 MMC5ROMWrProtect[2]=0;
\r
325 MMC5WRAM(0xC000,PRGBanks[2]&7);
\r
328 MMC5ROMWrProtect[3]=1;
\r
329 setprg8(0xE000,PRGBanks[3]&0x7F);
\r
331 case 3: for(x=0;x<3;x++)
\r
332 if(PRGBanks[x]&0x80)
\r
334 MMC5ROMWrProtect[x]=1;
\r
335 setprg8(0x8000+(x<<13),PRGBanks[x]&0x7F);
\r
340 MMC5ROMWrProtect[x]=0;
\r
341 MMC5WRAM(0x8000+(x<<13),PRGBanks[x]&7);
\r
344 MMC5ROMWrProtect[3]=1;
\r
345 setprg8(0xE000,PRGBanks[3]&0x7F);
\r
350 static DECLFW(Mapper5_write)
\r
352 if(A>=0x5120&&A<=0x5127)
\r
355 CHRBanksA[A&7]=V | ((MMC50x5130&0x3)<<8); //if we had a test case for this then we could test this, but it hasnt been verified
\r
356 //CHRBanksA[A&7]=V;
\r
365 switch((V>>(x<<1))&3)
\r
368 PPUNTARAM|=1<<x;vnapage[x]=NTARAM;break;
\r
370 PPUNTARAM|=1<<x;vnapage[x]=NTARAM+0x400;break;
\r
372 PPUNTARAM|=1<<x;vnapage[x]=ExRAM;break;
\r
374 PPUNTARAM&=~(1<<x);vnapage[x]=MMC5fill;break;
\r
380 case 0x5113: WRAMPage=V;MMC5WRAM(0x6000,V&7);break;
\r
381 case 0x5100: mmc5psize=V;MMC5PRG();break;
\r
382 case 0x5101: mmc5vsize=V;
\r
384 { MMC5CHRB();MMC5CHRA();}
\r
386 { MMC5CHRA();MMC5CHRB();}
\r
391 case 0x5117: PRGBanks[A&3]=V;MMC5PRG();break;
\r
395 case 0x512b: mmc5ABMode=1;
\r
399 case 0x5102: WRAMMaskEnable[0]=V;break;
\r
400 case 0x5103: WRAMMaskEnable[1]=V;break;
\r
401 case 0x5104: CHRMode=V;MMC5HackCHRMode=V&3;break;
\r
402 case 0x5106: if(V!=NTFill)
\r
405 t=V|(V<<8)|(V<<16)|(V<<24);
\r
406 FCEU_dwmemset(MMC5fill,t,0x3c0);
\r
410 case 0x5107: if(V!=ATFill)
\r
412 unsigned char moop;
\r
414 moop=V|(V<<2)|(V<<4)|(V<<6);
\r
415 t=moop|(moop<<8)|(moop<<16)|(moop<<24);
\r
416 FCEU_dwmemset(MMC5fill+0x3c0,t,0x40);
\r
420 case 0x5130: MMC50x5130=V;break;
\r
422 case 0x5200: MMC5HackSPMode=V;break;
\r
423 case 0x5201: MMC5HackSPScroll=(V>>3)&0x1F;break;
\r
424 case 0x5202: MMC5HackSPPage=V&0x3F;break;
\r
425 case 0x5203: X6502_IRQEnd(FCEU_IQEXT);IRQScanline=V;break;
\r
426 case 0x5204: X6502_IRQEnd(FCEU_IQEXT);IRQEnable=V&0x80;break;
\r
427 case 0x5205: mul[0]=V;break;
\r
428 case 0x5206: mul[1]=V;break;
\r
432 static DECLFR(MMC5_ReadROMRAM)
\r
434 if(MMC5MemIn[(A-0x6000)>>13])
\r
435 return Page[A>>11][A];
\r
440 static DECLFW(MMC5_WriteROMRAM)
\r
443 if(MMC5ROMWrProtect[(A-0x8000)>>13]) return;
\r
444 if(MMC5MemIn[(A-0x6000)>>13])
\r
445 if(((WRAMMaskEnable[0]&3)|((WRAMMaskEnable[1]&3)<<2)) == 6)
\r
449 static DECLFW(MMC5_ExRAMWr)
\r
451 if(MMC5HackCHRMode!=3)
\r
455 static DECLFR(MMC5_ExRAMRd)
\r
457 /* Not sure if this is correct, so I'll comment it out for now. */
\r
458 //if(MMC5HackCHRMode>=2)
\r
459 return ExRAM[A&0x3ff];
\r
464 static DECLFR(MMC5_read)
\r
468 case 0x5204: X6502_IRQEnd(FCEU_IQEXT);
\r
476 case 0x5205: return (mul[0]*mul[1]);
\r
477 case 0x5206: return ((mul[0]*mul[1])>>8);
\r
482 void MMC5Synco(void)
\r
489 switch((NTAMirroring>>(x<<1))&3)
\r
491 case 0:PPUNTARAM|=1<<x;vnapage[x]=NTARAM;break;
\r
492 case 1:PPUNTARAM|=1<<x;vnapage[x]=NTARAM+0x400;break;
\r
493 case 2:PPUNTARAM|=1<<x;vnapage[x]=ExRAM;break;
\r
494 case 3:PPUNTARAM&=~(1<<x);vnapage[x]=MMC5fill;break;
\r
497 MMC5WRAM(0x6000,WRAMPage&7);
\r
510 t=NTFill|(NTFill<<8)|(NTFill<<16)|(NTFill<<24);
\r
511 FCEU_dwmemset(MMC5fill,t,0x3c0);
\r
514 unsigned char moop;
\r
516 moop=ATFill|(ATFill<<2)|(ATFill<<4)|(ATFill<<6);
\r
517 t=moop|(moop<<8)|(moop<<16)|(moop<<24);
\r
518 FCEU_dwmemset(MMC5fill+0x3c0,t,0x40);
\r
520 X6502_IRQEnd(FCEU_IQEXT);
\r
521 MMC5HackCHRMode=CHRMode&3;
\r
524 void MMC5_hb(int scanline)
\r
532 if(MMC5LineCounter<240)
\r
534 if(MMC5LineCounter==IRQScanline)
\r
538 X6502_IRQBegin(FCEU_IQEXT);
\r
542 if(MMC5LineCounter==240)
\r
546 void MMC5_StateRestore(int version)
\r
563 static MMC5APU MMC5Sound;
\r
566 static void Do5PCM()
\r
571 start=MMC5Sound.BC[2];
\r
572 end=(SOUNDTS<<16)/soundtsinc;
\r
573 if(end<=start) return;
\r
574 MMC5Sound.BC[2]=end;
\r
576 if(!(MMC5Sound.rawcontrol&0x40) && MMC5Sound.raw)
\r
577 for(V=start;V<end;V++)
\r
578 Wave[V>>4]+=MMC5Sound.raw<<1;
\r
581 static void Do5PCMHQ()
\r
583 uint32 V; //mbg merge 7/17/06 made uint32
\r
584 if(!(MMC5Sound.rawcontrol&0x40) && MMC5Sound.raw)
\r
585 for(V=MMC5Sound.BC[2];V<SOUNDTS;V++)
\r
586 WaveHi[V]+=MMC5Sound.raw<<5;
\r
587 MMC5Sound.BC[2]=SOUNDTS;
\r
591 static DECLFW(Mapper5_SW)
\r
595 GameExpSound.Fill=MMC5RunSound;
\r
596 GameExpSound.HiFill=MMC5RunSoundHQ;
\r
600 case 0x10:if(psfun) psfun();MMC5Sound.rawcontrol=V;break;
\r
601 case 0x11:if(psfun) psfun();MMC5Sound.raw=V;break;
\r
604 case 0x4://printf("%04x:$%02x\n",A,V&0x30);
\r
605 if(sfun) sfun(A>>2);
\r
606 MMC5Sound.env[A>>2]=V;
\r
609 case 0x6: if(sfun) sfun(A>>2);
\r
610 MMC5Sound.wl[A>>2]&=~0x00FF;
\r
611 MMC5Sound.wl[A>>2]|=V&0xFF;
\r
614 case 0x7://printf("%04x:$%02x\n",A,V>>3);
\r
615 MMC5Sound.wl[A>>2]&=~0x0700;
\r
616 MMC5Sound.wl[A>>2]|=(V&0x07)<<8;
\r
617 MMC5Sound.running|=1<<(A>>2);
\r
624 MMC5Sound.running&=V;
\r
625 MMC5Sound.enable=V;
\r
626 //printf("%02x\n",V);
\r
631 static void Do5SQ(int P)
\r
633 static int tal[4]={1,2,4,6};
\r
634 int32 V,amp,rthresh,wl;
\r
637 start=MMC5Sound.BC[P];
\r
638 end=(SOUNDTS<<16)/soundtsinc;
\r
639 if(end<=start) return;
\r
640 MMC5Sound.BC[P]=end;
\r
642 wl=MMC5Sound.wl[P]+1;
\r
643 amp=(MMC5Sound.env[P]&0xF)<<4;
\r
644 rthresh=tal[(MMC5Sound.env[P]&0xC0)>>6];
\r
646 if(wl>=8 && (MMC5Sound.running&(P+1)))
\r
651 dc=MMC5Sound.dcount[P];
\r
652 vc=MMC5Sound.vcount[P];
\r
654 for(V=start;V<end;V++)
\r
665 MMC5Sound.dcount[P]=dc;
\r
666 MMC5Sound.vcount[P]=vc;
\r
670 static void Do5SQHQ(int P)
\r
672 static int tal[4]={1,2,4,6};
\r
673 uint32 V; //mbg merge 7/17/06 made uint32
\r
674 int32 amp,rthresh,wl;
\r
676 wl=MMC5Sound.wl[P]+1;
\r
677 amp=((MMC5Sound.env[P]&0xF)<<8);
\r
678 rthresh=tal[(MMC5Sound.env[P]&0xC0)>>6];
\r
680 if(wl>=8 && (MMC5Sound.running&(P+1)))
\r
686 dc=MMC5Sound.dcount[P];
\r
687 vc=MMC5Sound.vcount[P];
\r
688 for(V=MMC5Sound.BC[P];V<SOUNDTS;V++)
\r
693 if(vc<=0) /* Less than zero when first started. */
\r
699 MMC5Sound.dcount[P]=dc;
\r
700 MMC5Sound.vcount[P]=vc;
\r
702 MMC5Sound.BC[P]=SOUNDTS;
\r
705 void MMC5RunSoundHQ(void)
\r
712 void MMC5HiSync(int32 ts)
\r
715 for(x=0;x<3;x++) MMC5Sound.BC[x]=ts;
\r
718 void MMC5RunSound(int Count)
\r
725 MMC5Sound.BC[x]=Count;
\r
728 void Mapper5_ESI(void)
\r
730 GameExpSound.RChange=Mapper5_ESI;
\r
731 if(FSettings.SndRate)
\r
733 if(FSettings.soundq>=1)
\r
749 memset(MMC5Sound.BC,0,sizeof(MMC5Sound.BC));
\r
750 memset(MMC5Sound.vcount,0,sizeof(MMC5Sound.vcount));
\r
751 GameExpSound.HiSync=MMC5HiSync;
\r
754 void NSFMMC5_Init(void)
\r
756 memset(&MMC5Sound,0,sizeof(MMC5Sound));
\r
758 ExRAM=(uint8*)FCEU_gmalloc(1024);
\r
760 SetWriteHandler(0x5c00,0x5fef,MMC5_ExRAMWr);
\r
761 SetReadHandler(0x5c00,0x5fef,MMC5_ExRAMRd);
\r
763 SetWriteHandler(0x5000,0x5015,Mapper5_SW);
\r
764 SetWriteHandler(0x5205,0x5206,Mapper5_write);
\r
765 SetReadHandler(0x5205,0x5206,MMC5_read);
\r
768 void NSFMMC5_Close(void)
\r
774 static void GenMMC5Reset(void)
\r
778 for(x=0;x<4;x++) PRGBanks[x]=~0;
\r
779 for(x=0;x<8;x++) CHRBanksA[x]=~0;
\r
780 for(x=0;x<4;x++) CHRBanksB[x]=~0;
\r
781 WRAMMaskEnable[0]=WRAMMaskEnable[1]=~0;
\r
783 mmc5psize=mmc5vsize=3;
\r
786 NTAMirroring=NTFill=ATFill=0xFF;
\r
790 SetWriteHandler(0x4020,0x5bff,Mapper5_write);
\r
791 SetReadHandler(0x4020,0x5bff,MMC5_read);
\r
793 SetWriteHandler(0x5c00,0x5fff,MMC5_ExRAMWr);
\r
794 SetReadHandler(0x5c00,0x5fff,MMC5_ExRAMRd);
\r
796 SetWriteHandler(0x6000,0xFFFF,MMC5_WriteROMRAM);
\r
797 SetReadHandler(0x6000,0xFFFF,MMC5_ReadROMRAM);
\r
799 SetWriteHandler(0x5000,0x5015,Mapper5_SW);
\r
800 SetWriteHandler(0x5205,0x5206,Mapper5_write);
\r
801 SetReadHandler(0x5205,0x5206,MMC5_read);
\r
803 //GameHBIRQHook=MMC5_hb;
\r
804 FCEU_CheatAddRAM(8,0x6000,WRAM);
\r
805 FCEU_CheatAddRAM(1,0x5c00,ExRAM);
\r
808 static SFORMAT MMC5_StateRegs[]={
\r
809 { PRGBanks, 4, "PRGB"},
\r
810 { CHRBanksA, 16, "CHRA"},
\r
811 { CHRBanksB, 8, "CHRB"},
\r
812 { &WRAMPage, 1, "WRMP"},
\r
813 { WRAMMaskEnable, 2, "WRME"},
\r
814 { &mmc5ABMode, 1, "ABMD"},
\r
815 { &IRQScanline, 1, "IRQS"},
\r
816 { &IRQEnable, 1, "IRQE"},
\r
817 { &CHRMode, 1, "CHRM"},
\r
818 { &NTAMirroring, 1, "NTAM"},
\r
819 { &NTFill, 1, "NTFL"},
\r
820 { &ATFill, 1, "ATFL"},
\r
822 { &MMC5Sound.wl[0], 2|FCEUSTATE_RLSB, "SDW0"},
\r
823 { &MMC5Sound.wl[1], 2|FCEUSTATE_RLSB, "SDW1"},
\r
824 { MMC5Sound.env, 2, "SDEV"},
\r
825 { &MMC5Sound.enable, 1, "SDEN"},
\r
826 { &MMC5Sound.running, 1, "SDRU"},
\r
827 { &MMC5Sound.raw, 1, "SDRW"},
\r
828 { &MMC5Sound.rawcontrol, 1, "SDRC"},
\r
832 static void GenMMC5_Init(CartInfo *info, int wsize, int battery)
\r
836 WRAM=(uint8*)FCEU_gmalloc(wsize*1024);
\r
837 SetupCartPRGMapping(0x10,WRAM,wsize*1024,1);
\r
838 AddExState(WRAM, wsize*1024, 0, "WRAM");
\r
841 MMC5fill=(uint8*)FCEU_gmalloc(1024);
\r
842 ExRAM=(uint8*)FCEU_gmalloc(1024);
\r
844 AddExState(MMC5_StateRegs, ~0, 0, 0);
\r
845 AddExState(WRAM, wsize*1024, 0, "WRAM");
\r
846 AddExState(ExRAM, 1024, 0, "ERAM");
\r
847 AddExState(&MMC5HackSPMode, 1, 0, "SPLM");
\r
848 AddExState(&MMC5HackSPScroll, 1, 0, "SPLS");
\r
849 AddExState(&MMC5HackSPPage, 1, 0, "SPLP");
\r
850 AddExState(&MMC50x5130, 1, 0, "5130");
\r
852 MMC5WRAMsize=wsize/8;
\r
853 BuildWRAMSizeTable();
\r
854 GameStateRestore=MMC5_StateRestore;
\r
855 info->Power=GenMMC5Reset;
\r
859 info->SaveGame[0]=WRAM;
\r
861 info->SaveGameLen[0]=8192;
\r
863 info->SaveGameLen[0]=32768;
\r
866 MMC5HackVROMMask=CHRmask4[0];
\r
867 MMC5HackExNTARAMPtr=ExRAM;
\r
869 MMC5HackVROMPTR=CHRptr[0];
\r
871 MMC5HackSPMode=MMC5HackSPScroll=MMC5HackSPPage=0;
\r
874 FFCEUX_PPURead = mmc5_PPURead;
\r
875 FFCEUX_PPUWrite = mmc5_PPUWrite;
\r
878 void Mapper5_Init(CartInfo *info)
\r
880 GenMMC5_Init(info, DetectMMC5WRAMSize(info->CRC32), info->battery);
\r
883 // ELROM seems to have 0KB of WRAM
\r
884 // EKROM seems to have 8KB of WRAM
\r
885 // ETROM seems to have 16KB of WRAM
\r
886 // EWROM seems to have 32KB of WRAM
\r
888 // ETROM and EWROM are battery-backed, EKROM isn't.
\r
890 void ETROM_Init(CartInfo *info)
\r
892 GenMMC5_Init(info, 16,info->battery);
\r
895 void ELROM_Init(CartInfo *info)
\r
897 GenMMC5_Init(info,0,0);
\r
900 void EWROM_Init(CartInfo *info)
\r
902 GenMMC5_Init(info,32,info->battery);
\r
905 void EKROM_Init(CartInfo *info)
\r
907 GenMMC5_Init(info,8,info->battery);
\r