1 /* FCE Ultra - NES/Famicom Emulator
3 * Copyright notice for this file:
4 * Copyright (C) 2002 Ben Parnell
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 /* None of this code should use any of the iNES bank switching wrappers. */
25 void MMC5Sound(int Count);
28 static INLINE void MMC5SPRVROM_BANK1(uint32 A,uint32 V)
33 MMC5SPRVPage[(A)>>10]=&CHRptr[0][(V)<<10]-(A);
37 static INLINE void MMC5BGVROM_BANK1(uint32 A,uint32 V) {if(CHRptr[0]){V&=CHRmask1[0];MMC5BGVPage[(A)>>10]=&CHRptr[0][(V)<<10]-(A);}}
39 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);}}
40 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);}}
42 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);}}
43 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);}}
45 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];}}
46 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];}}
49 uint8 MMC5fill[0x400];
51 #define MMC5IRQR mapbyte3[4]
52 #define MMC5LineCounter mapbyte3[5]
53 #define mmc5psize mapbyte1[0]
54 #define mmc5vsize mapbyte1[1]
57 uint8 MMC5WRAMIndex[8];
59 uint8 MMC5ROMWrProtect[4];
62 static void MMC5CHRA(void);
63 static void MMC5CHRB(void);
65 typedef struct __cartdata {
71 // ETROM seems to have 16KB of WRAM, ELROM seems to have 8KB
72 // EWROM seems to have 32KB of WRAM
74 #define MMC5_NOCARTS 14
75 cartdata MMC5CartList[MMC5_NOCARTS]=
77 {0x9c18762b,2}, /* L'Empereur */
81 {0xaca15643,2}, /* Uncharted Waters */
82 {0xfe3488d1,2}, /* Dai Koukai Jidai */
84 {0x15fe6d0f,2}, /* BKAC */
85 {0x39f2ce4b,2}, /* Suikoden */
87 {0x8ce478db,2}, /* Nobunaga's Ambition 2 */
90 {0x1ced086f,2}, /* Ishin no Arashi */
92 {0xf540677b,4}, /* Nobunaga...Bushou Fuuun Roku */
94 {0x6f4e4312,4}, /* Aoki Ookami..Genchou */
96 {0xf011e490,4}, /* Romance of the 3 Kingdoms 2 */
97 {0x184c2124,4}, /* Sangokushi 2 */
101 // Called by iNESLoad()
102 void DetectMMC5WRAMSize(void)
108 for(x=0;x<MMC5_NOCARTS;x++)
109 if(iNESGameCRC32==MMC5CartList[x].crc32)
111 MMC5WRAMsize=MMC5CartList[x].size;
116 static void BuildWRAMSizeTable(void)
125 case 1:MMC5WRAMIndex[x]=(x>3)?255:0;break;
126 case 2:MMC5WRAMIndex[x]=(x&4)>>2;break;
127 case 4:MMC5WRAMIndex[x]=(x>3)?255:(x&3);break;
132 static void MMC5CHRA(void)
135 switch(mapbyte1[1]&3)
137 case 0:MMC5SPRVROM_BANK8(mapbyte2[7]);
138 setchr8(mapbyte2[7]);
140 case 1:MMC5SPRVROM_BANK4(0x0000,mapbyte2[3]);
141 MMC5SPRVROM_BANK4(0x1000,mapbyte2[7]);
142 setchr4(0x0000,mapbyte2[3]);
143 setchr4(0x1000,mapbyte2[7]);
145 case 2:MMC5SPRVROM_BANK2(0x0000,mapbyte2[1]);
146 MMC5SPRVROM_BANK2(0x0800,mapbyte2[3]);
147 MMC5SPRVROM_BANK2(0x1000,mapbyte2[5]);
148 MMC5SPRVROM_BANK2(0x1800,mapbyte2[7]);
149 setchr2(0x0000,mapbyte2[1]);
150 setchr2(0x0800,mapbyte2[3]);
151 setchr2(0x1000,mapbyte2[5]);
152 setchr2(0x1800,mapbyte2[7]);
157 setchr1(x<<10,mapbyte2[x]);
158 MMC5SPRVROM_BANK1(x<<10,mapbyte2[x]);
164 static void MMC5CHRB(void)
167 switch(mapbyte1[1]&3)
169 case 0:MMC5BGVROM_BANK8(mapbyte3[3]);
170 setchr8(mapbyte3[3]);
173 MMC5BGVROM_BANK4(0x0000,mapbyte3[3]);
174 MMC5BGVROM_BANK4(0x1000,mapbyte3[3]);
175 setchr4(0x0000,mapbyte3[3]);
176 setchr4(0x1000,mapbyte3[3]);
178 case 2:MMC5BGVROM_BANK2(0x0000,mapbyte3[1]);
179 MMC5BGVROM_BANK2(0x0800,mapbyte3[3]);
180 MMC5BGVROM_BANK2(0x1000,mapbyte3[1]);
181 MMC5BGVROM_BANK2(0x1800,mapbyte3[3]);
182 setchr2(0x0000,mapbyte3[1]);
183 setchr2(0x0800,mapbyte3[3]);
184 setchr2(0x1000,mapbyte3[1]);
185 setchr2(0x1800,mapbyte3[3]);
190 setchr1(x<<10,mapbyte3[x&3]);
191 MMC5BGVROM_BANK1(x<<10,mapbyte3[x&3]);
197 static void FASTAPASS(2) MMC5WRAM(uint32 A, uint32 V)
199 V=MMC5WRAMIndex[V&7];
203 MMC5MemIn[(A-0x6000)>>13]=1;
206 MMC5MemIn[(A-0x6000)>>13]=0;
209 static void MMC5PRG(void)
213 switch(mapbyte1[0]&3)
216 MMC5ROMWrProtect[0]=MMC5ROMWrProtect[1]=
217 MMC5ROMWrProtect[2]=MMC5ROMWrProtect[3]=1;
218 setprg32(0x8000,((mapbyte1[5]&0x7F)>>2));
225 MMC5ROMWrProtect[0]=MMC5ROMWrProtect[1]=1;
226 setprg16(0x8000,(mapbyte1[5]>>1));
227 MMC5MemIn[1]=MMC5MemIn[2]=1;
231 MMC5ROMWrProtect[0]=MMC5ROMWrProtect[1]=0;
232 MMC5WRAM(0x8000,mapbyte1[5]&7&0xFE);
233 MMC5WRAM(0xA000,(mapbyte1[5]&7&0xFE)+1);
235 MMC5MemIn[3]=MMC5MemIn[4]=1;
236 MMC5ROMWrProtect[2]=MMC5ROMWrProtect[3]=1;
237 setprg16(0xC000,(mapbyte1[7]&0x7F)>>1);
242 MMC5MemIn[1]=MMC5MemIn[2]=1;
243 MMC5ROMWrProtect[0]=MMC5ROMWrProtect[1]=1;
244 setprg16(0x8000,(mapbyte1[5]&0x7F)>>1);
248 MMC5ROMWrProtect[0]=MMC5ROMWrProtect[1]=0;
249 MMC5WRAM(0x8000,mapbyte1[5]&7&0xFE);
250 MMC5WRAM(0xA000,(mapbyte1[5]&7&0xFE)+1);
253 {MMC5ROMWrProtect[2]=1;MMC5MemIn[3]=1;setprg8(0xC000,mapbyte1[6]&0x7F);}
255 {MMC5ROMWrProtect[2]=0;MMC5WRAM(0xC000,mapbyte1[6]&7);}
257 MMC5ROMWrProtect[3]=1;
258 setprg8(0xE000,mapbyte1[7]&0x7F);
262 if(mapbyte1[4+x]&0x80)
264 MMC5ROMWrProtect[0]=1;
265 setprg8(0x8000+(x<<13),mapbyte1[4+x]&0x7F);
270 MMC5ROMWrProtect[0]=0;
271 MMC5WRAM(0x8000+(x<<13),mapbyte1[4+x]&7);
274 MMC5ROMWrProtect[3]=1;
275 setprg8(0xE000,mapbyte1[7]&0x7F);
280 #define mul1 mapbyte3[6]
281 #define mul2 mapbyte3[7]
283 static DECLFW(Mapper5_write)
293 switch((V>>(x<<1))&3)
295 case 0:PPUNTARAM|=1<<x;vnapage[x]=NTARAM;break;
296 case 1:PPUNTARAM|=1<<x;vnapage[x]=NTARAM+0x400;break;
297 case 2:PPUNTARAM|=1<<x;vnapage[x]=MapperExRAM+0x6000;break;
298 case 3:PPUNTARAM&=~(1<<x);vnapage[x]=MMC5fill;break;
305 case 0x5113:mapbyte4[6]=V;MMC5WRAM(0x6000,V&7);break;
306 case 0x5100:mapbyte1[0]=V;MMC5PRG();break;
307 case 0x5101:mapbyte1[1]=V;
309 {MMC5CHRB();MMC5CHRA();}
311 {MMC5CHRA();MMC5CHRB();}
318 mapbyte1[A&7]=V;MMC5PRG();break;
327 case 0x5127:mapbyte4[7]=0;
328 mapbyte2[A&7]=V;MMC5CHRA();break;
332 case 0x512b:mapbyte4[7]=1;
333 mapbyte3[A&3]=V;MMC5CHRB();break;
334 case 0x5102:mapbyte4[0]=V;break;
335 case 0x5103:mapbyte4[1]=V;break;
336 case 0x5104:mapbyte4[2]=V;MMC5HackCHRMode=V&3;break;
337 case 0x5106:if(V!=mapbyte4[4])
340 t=V|(V<<8)|(V<<16)|(V<<24);
341 FCEU_dwmemset(MMC5fill,t,0x3c0);
345 case 0x5107:if(V!=mapbyte4[5])
349 moop=V|(V<<2)|(V<<4)|(V<<6);
350 t=moop|(moop<<8)|(moop<<16)|(moop<<24);
351 FCEU_dwmemset(MMC5fill+0x3c0,t,0x40);
355 case 0x5200:MMC5HackSPMode=V;break;
356 case 0x5201:MMC5HackSPScroll=(V>>3)&0x1F;break;
357 case 0x5202:MMC5HackSPPage=V&0x3F;break;
358 case 0x5203:X6502_IRQEnd(FCEU_IQEXT);IRQCount=V;break;
359 case 0x5204:X6502_IRQEnd(FCEU_IQEXT);IRQa=V&0x80;break;
360 case 0x5205:mul1=V;break;
361 case 0x5206:mul2=V;break;
365 DECLFR(MMC5_ReadROMRAM)
367 if(MMC5MemIn[(A-0x6000)>>13])
368 return Page[A>>11][A];
373 DECLFW(MMC5_WriteROMRAM)
376 if(MMC5ROMWrProtect[(A-0x8000)>>13])
378 if(MMC5MemIn[(A-0x6000)>>13])
379 if(((mapbyte4[0]&3)|((mapbyte4[1]&3)<<2)) == 6)
383 static DECLFW(MMC5_ExRAMWr)
385 if(MMC5HackCHRMode!=3)
386 (MapperExRAM+0x6000)[A&0x3ff]=V;
389 static DECLFR(MMC5_ExRAMRd)
391 /* Not sure if this is correct, so I'll comment it out for now. */
392 //if(MMC5HackCHRMode>=2)
393 return (MapperExRAM+0x6000)[A&0x3ff];
398 static DECLFR(MMC5_read)
402 //default:printf("$%04x\n",A);break;
403 case 0x5204:X6502_IRQEnd(FCEU_IQEXT);
410 case 0x5205:return (mul1*mul2);
411 case 0x5206:return ((mul1*mul2)>>8);
425 switch((mapbyte4[3]>>(x<<1))&3)
427 case 0:PPUNTARAM|=1<<x;vnapage[x]=NTARAM;break;
428 case 1:PPUNTARAM|=1<<x;vnapage[x]=NTARAM+0x400;break;
429 case 2:PPUNTARAM|=1<<x;vnapage[x]=MapperExRAM+0x6000;break;
430 case 3:PPUNTARAM&=~(1<<x);vnapage[x]=MMC5fill;break;
433 MMC5WRAM(0x6000,mapbyte4[6]&7);
446 t=mapbyte4[4]|(mapbyte4[4]<<8)|(mapbyte4[4]<<16)|(mapbyte4[4]<<24);
447 FCEU_dwmemset(MMC5fill,t,0x3c0);
452 moop=mapbyte4[5]|(mapbyte4[5]<<2)|(mapbyte4[5]<<4)|(mapbyte4[5]<<6);
453 t=moop|(moop<<8)|(moop<<16)|(moop<<24);
454 FCEU_dwmemset(MMC5fill+0x3c0,t,0x40);
456 X6502_IRQEnd(FCEU_IQEXT);
457 MMC5HackCHRMode=mapbyte4[2]&3;
465 if(MMC5LineCounter<245)
468 if(MMC5LineCounter==IRQCount) MMC5IRQR|=0x80;
469 if((MMC5LineCounter==IRQCount && IRQa&0x80))
470 X6502_IRQBegin(FCEU_IQEXT);
472 if(MMC5LineCounter>=239)
485 if(MMC5LineCounter<240)
488 if(MMC5LineCounter==IRQCount)
492 X6502_IRQBegin(FCEU_IQEXT);
495 // printf("%d:%d\n",MMC5LineCounter,scanline);
496 if(MMC5LineCounter==240)
500 void Mapper5_StateRestore(int version)
506 FCEU_memmove(tmp,MapperExRAM,8192);
507 FCEU_memmove(MapperExRAM,MapperExRAM+8192,16384+8192);
508 FCEU_memmove(MapperExRAM+16384+8192,tmp,8192);
513 #define MMC5PSG (MapperExRAM+0x640B+8)
515 static int C5BC[3]={0,0,0};
517 static void Do5PCM(void)
523 end=(timestamp<<16)/soundtsinc;
524 if(end<=start) return;
527 if(!(MMC5PSG[0x10]&0x40) && MMC5PSG[0x11])
528 for(V=start;V<end;V++)
529 Wave[V>>4]+=MMC5PSG[0x11]<<2;
534 GameExpSound.Fill=MMC5Sound;
540 case 0x11:Do5PCM();break;
542 case 0x0:Do5SQ(0);break;
543 case 0x2:Do5SQ(0);break;
544 case 0x3:Do5SQ(0);break;
545 case 0x4:Do5SQ(1);break;
546 case 0x6:Do5SQ(1);break;
547 case 0x7:Do5SQ(1);break;
550 int t=V^MMC5PSG[0x15];
561 static int32 vcount[2];
569 end=(timestamp<<16)/soundtsinc;
570 if(end<=start) return;
575 if(MMC5PSG[0x15]&(P+1))
578 unsigned char amplitude;
581 freq=(((MMC5PSG[(P<<2)+0x2]|((MMC5PSG[(P<<2)+0x3]&7)<<8))));
583 if(freq<8) goto mmc5enda;
585 inc=(long double)((unsigned long)((FSettings.SndRate OVERSAMPLE)<<12))/((long double)PSG_base/freq);
587 switch(MMC5PSG[P<<2]&0xC0)
590 case 0x00:dcycs=inc>>3;break;
591 case 0x40:dcycs=inc>>2;break;
592 case 0x80:dcycs=inc>>1;break;
593 case 0xC0:dcycs=(inc+inc+inc)>>2;break;
596 amplitude=(MMC5PSG[P<<2]&15)<<4;
599 for(V=start;V<end;V++)
602 Wave[V>>4]+=amplitude;
604 if(vcoo>=inc) vcoo-=inc;
608 mmc5enda:; // semi-colon must be here for MSVC
611 void MMC5Sound(int Count)
621 static void MMC5SoundC(void)
623 if(FSettings.SndRate)
626 SetWriteHandler(0x5000,0x5015,0);
629 void Mapper5_ESI(void)
631 GameExpSound.RChange=MMC5SoundC;
633 if(FSettings.SndRate)
635 SetWriteHandler(0x5000,0x5015,Mapper5_SW);
636 SetWriteHandler(0x5205,0x5206,Mapper5_write);
637 SetReadHandler(0x5205,0x5206,MMC5_read);
639 if(FCEUGameInfo.type==GIT_NSF)
641 SetWriteHandler(0x5c00,0x5fef,MMC5_ExRAMWr);
642 SetReadHandler(0x5c00,0x5fef,MMC5_ExRAMRd);
646 GameHBIRQHook=MMC5_hb;
649 static void GenMMC5Reset(void)
651 mapbyte1[4]=mapbyte1[5]=mapbyte1[6]=mapbyte1[7]=~0;
652 mapbyte1[0]=mapbyte1[1]=3;
655 mapbyte4[3]=mapbyte4[4]=mapbyte4[5]=0xFF;
659 SetWriteHandler(0x4020,0x5bff,Mapper5_write);
660 SetReadHandler(0x4020,0x5bff,MMC5_read);
662 SetWriteHandler(0x5c00,0x5fff,MMC5_ExRAMWr);
663 SetReadHandler(0x5c00,0x5fff,MMC5_ExRAMRd);
665 SetWriteHandler(0x6000,0xFFFF,MMC5_WriteROMRAM);
666 SetReadHandler(0x6000,0xFFFF,MMC5_ReadROMRAM);
670 GameHBIRQHook=MMC5_hb;
671 FCEU_CheatAddRAM(8,0x6000,WRAM);
672 FCEU_CheatAddRAM(1,0x5c00,MapperExRAM+0x6000);
675 void Mapper5_init(void)
677 AddExState(&MMC5HackSPMode, 1, 0, "SPLM");
678 AddExState(&MMC5HackSPScroll, 1, 0, "SPLS");
679 AddExState(&MMC5HackSPPage, 1, 0, "SPLP");
680 SetupCartPRGMapping(0x10,WRAM,32768,1);
682 BuildWRAMSizeTable();
683 GameStateRestore=Mapper5_StateRestore;
687 static void GenMMC5_Close(void)
689 UNIFOpenWRAM(UOW_WR,0,1);
691 UNIFWriteWRAM(WRAM,8192);
693 UNIFWriteWRAM(WRAM,32768);
697 static void GenMMC5_Init(int wsize, int battery)
699 SetupCartPRGMapping(0x10,WRAM,32768,1);
700 AddExState(WRAM, 8192, 0, "WRAM");
701 AddExState(MapperExRAM, 32768, 0, "MEXR");
702 AddExState(&IRQCount, 4, 1, "IRQC");
703 AddExState(&IRQa, 1, 0, "IRQA");
704 AddExState(mapbyte1, 32, 0, "MPBY");
705 AddExState(&MMC5HackSPMode, 1, 0, "SPLM");
706 AddExState(&MMC5HackSPScroll, 1, 0, "SPLS");
707 AddExState(&MMC5HackSPPage, 1, 0, "SPLP");
709 MMC5WRAMsize=wsize/8;
710 BuildWRAMSizeTable();
711 GameStateRestore=Mapper5_StateRestore;
712 BoardPower=GenMMC5Reset;
716 UNIFOpenWRAM(UOW_RD,0,1);
718 UNIFReadWRAM(WRAM,8192);
720 UNIFReadWRAM(WRAM,32768);
722 BoardClose=GenMMC5_Close;
726 MMC5HackVROMMask=CHRmask4[0];
727 MMC5HackExNTARAMPtr=MapperExRAM+0x6000;
729 MMC5HackVROMPTR=CHRptr[0];
731 MMC5HackSPMode=MMC5HackSPScroll=MMC5HackSPPage=0;
735 // ETROM seems to have 16KB of WRAM, ELROM seems to have 8KB
736 // EWROM seems to have 32KB of WRAM
738 // ETROM and EWROM are battery-backed, ELROM isn't.
740 void ETROM_Init(void)
745 void ELROM_Init(void)
750 void EWROM_Init(void)
755 void EKROM_Init(void)