1 /* FCE Ultra - NES/Famicom Emulator
\r
3 * Copyright notice for this file:
\r
4 * Copyright (C) 1998 BERO
\r
5 * Copyright (C) 2002 Xodnizel
\r
7 * This program is free software; you can redistribute it and/or modify
\r
8 * it under the terms of the GNU General Public License as published by
\r
9 * the Free Software Foundation; either version 2 of the License, or
\r
10 * (at your option) any later version.
\r
12 * This program is distributed in the hope that it will be useful,
\r
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
15 * GNU General Public License for more details.
\r
17 * You should have received a copy of the GNU General Public License
\r
18 * along with this program; if not, write to the Free Software
\r
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
\r
24 static void GenMMC1Power(void);
\r
25 static void GenMMC1Init(CartInfo *info, int prg, int chr, int wram, int battery);
\r
27 static uint8 BufferShift,DRegs[4];
\r
28 static uint8 Buffer;
\r
30 static int mmc1opts;
\r
32 static void (*MMC1CHRHook4)(uint32 A, uint8 V);
\r
33 static void (*MMC1PRGHook16)(uint32 A, uint8 V);
\r
35 static uint8 *WRAM=NULL;
\r
36 static uint8 *CHRRAM=NULL;
\r
37 static int is155, is171;
\r
39 static DECLFW(MBWRAM)
\r
41 if(!(DRegs[3]&0x10)||is155)
\r
42 Page[A>>11][A]=V; // WRAM is enabled.
\r
45 static DECLFR(MAWRAM)
\r
47 if((DRegs[3]&0x10)&&!is155)
\r
48 return X.DB; // WRAM is disabled
\r
49 return(Page[A>>11][A]);
\r
52 static void MMC1CHR(void)
\r
57 setprg8r(0x10,0x6000,(DRegs[1]>>4)&1);
\r
59 setprg8r(0x10,0x6000,(DRegs[1]>>3)&1);
\r
66 MMC1CHRHook4(0x0000,DRegs[1]);
\r
67 MMC1CHRHook4(0x1000,DRegs[2]);
\r
71 MMC1CHRHook4(0x0000,(DRegs[1]&0xFE));
\r
72 MMC1CHRHook4(0x1000,DRegs[1]|1);
\r
79 setchr4(0x0000,DRegs[1]);
\r
80 setchr4(0x1000,DRegs[2]);
\r
83 setchr8(DRegs[1]>>1);
\r
87 static void MMC1PRG(void)
\r
89 uint8 offs=DRegs[1]&0x10;
\r
92 switch(DRegs[0]&0xC)
\r
94 case 0xC: MMC1PRGHook16(0x8000,(DRegs[3]+offs));
\r
95 MMC1PRGHook16(0xC000,0xF+offs);
\r
97 case 0x8: MMC1PRGHook16(0xC000,(DRegs[3]+offs));
\r
98 MMC1PRGHook16(0x8000,offs);
\r
102 MMC1PRGHook16(0x8000,((DRegs[3]&~1)+offs));
\r
103 MMC1PRGHook16(0xc000,((DRegs[3]&~1)+offs+1));
\r
109 switch(DRegs[0]&0xC)
\r
111 case 0xC: setprg16(0x8000,(DRegs[3]+offs));
\r
112 setprg16(0xC000,0xF+offs);
\r
114 case 0x8: setprg16(0xC000,(DRegs[3]+offs));
\r
115 setprg16(0x8000,offs);
\r
119 setprg16(0x8000,((DRegs[3]&~1)+offs));
\r
120 setprg16(0xc000,((DRegs[3]&~1)+offs+1));
\r
126 static void MMC1MIRROR(void)
\r
131 case 2: setmirror(MI_V); break;
\r
132 case 3: setmirror(MI_H); break;
\r
133 case 0: setmirror(MI_0); break;
\r
134 case 1: setmirror(MI_1); break;
\r
138 static uint64 lreset;
\r
139 static DECLFW(MMC1_write)
\r
142 //FCEU_DispMessage("%016x",timestampbase+timestamp);
\r
143 // FCEU_printf("$%04x:$%02x, $%04x\n",A,V,X.PC);
\r
144 //DumpMem("out",0xe000,0xffff);
\r
146 /* The MMC1 is busy so ignore the write. */
\r
147 /* As of version FCE Ultra 0.81, the timestamp is only
\r
148 increased before each instruction is executed(in other words
\r
149 precision isn't that great), but this should still work to
\r
150 deal with 2 writes in a row from a single RMW instruction.
\r
152 if((timestampbase+timestamp)<(lreset+2))
\r
154 // FCEU_printf("Write %04x:%02x\n",A,V);
\r
158 BufferShift=Buffer=0;
\r
160 lreset=timestampbase+timestamp;
\r
164 Buffer|=(V&1)<<(BufferShift++);
\r
168 // FCEU_printf("REG[%d]=%02x\n",n,Buffer);
\r
170 BufferShift = Buffer = 0;
\r
173 case 0: MMC1MIRROR(); MMC1CHR(); MMC1PRG(); break;
\r
174 case 1: MMC1CHR(); MMC1PRG(); break;
\r
175 case 2: MMC1CHR(); break;
\r
176 case 3: MMC1PRG(); break;
\r
181 static void MMC1_Restore(int version)
\r
186 lreset=0; /* timestamp(base) is not stored in save states. */
\r
189 static void MMC1CMReset(void)
\r
195 Buffer = BufferShift = 0;
\r
199 DRegs[2]=0; // Should this be something other than 0?
\r
207 static int DetectMMC1WRAMSize(uint32 crc32)
\r
211 case 0xc6182024: /* Romance of the 3 Kingdoms */
\r
212 case 0x2225c20f: /* Genghis Khan */
\r
213 case 0x4642dda6: /* Nobunaga's Ambition */
\r
214 case 0x29449ba9: /* "" "" (J) */
\r
215 case 0x2b11e0b0: /* "" "" (J) */
\r
216 case 0xb8747abf: /* Best Play Pro Yakyuu Special (J) */
\r
217 case 0xc9556b36: /* Final Fantasy I & II (J) [!] */
\r
218 FCEU_printf(" >8KB external WRAM present. Use UNIF if you hack the ROM image.\n");
\r
225 static uint32 NWCIRQCount;
\r
226 static uint8 NWCRec;
\r
229 static void NWCIRQHook(int a)
\r
234 if((NWCIRQCount|(NWCDIP<<25))>=0x3e000000)
\r
237 X6502_IRQBegin(FCEU_IQEXT);
\r
242 static void NWCCHRHook(uint32 A, uint8 V)
\r
244 if((V&0x10)) // && !(NWCRec&0x10))
\r
247 X6502_IRQEnd(FCEU_IQEXT);
\r
254 setprg32(0x8000,(V>>1)&3);
\r
257 static void NWCPRGHook(uint32 A, uint8 V)
\r
260 setprg16(A,8|(V&0x7));
\r
262 setprg32(0x8000,(NWCRec>>1)&3);
\r
265 static void NWCPower(void)
\r
271 void Mapper105_Init(CartInfo *info)
\r
273 GenMMC1Init(info, 256, 256, 8, 0);
\r
274 MMC1CHRHook4=NWCCHRHook;
\r
275 MMC1PRGHook16=NWCPRGHook;
\r
276 MapIRQHook=NWCIRQHook;
\r
277 info->Power=NWCPower;
\r
280 static void GenMMC1Power(void)
\r
285 FCEU_CheatAddRAM(8,0x6000,WRAM);
\r
287 FCEU_dwmemset(WRAM,0,8192)
\r
288 else if(!(mmc1opts&2))
\r
289 FCEU_dwmemset(WRAM,0,8192);
\r
291 SetWriteHandler(0x8000,0xFFFF,MMC1_write);
\r
292 SetReadHandler(0x8000,0xFFFF,CartBR);
\r
296 SetReadHandler(0x6000,0x7FFF,MAWRAM);
\r
297 SetWriteHandler(0x6000,0x7FFF,MBWRAM);
\r
298 setprg8r(0x10,0x6000,0);
\r
304 static void GenMMC1Close(void)
\r
307 FCEU_gfree(CHRRAM);
\r
313 static void GenMMC1Init(CartInfo *info, int prg, int chr, int wram, int battery)
\r
317 info->Close=GenMMC1Close;
\r
318 MMC1PRGHook16=MMC1CHRHook4=0;
\r
320 PRGmask16[0]&=(prg>>14)-1;
\r
321 CHRmask4[0]&=(chr>>12)-1;
\r
322 CHRmask8[0]&=(chr>>13)-1;
\r
326 WRAM=(uint8*)FCEU_gmalloc(wram*1024);
\r
328 if(wram>8) mmc1opts|=4;
\r
329 SetupCartPRGMapping(0x10,WRAM,wram*1024,1);
\r
330 AddExState(WRAM, wram*1024, 0, "WRAM");
\r
334 info->SaveGame[0]=WRAM+((mmc1opts&4)?8192:0);
\r
335 info->SaveGameLen[0]=8192;
\r
340 CHRRAM=(uint8*)FCEU_gmalloc(8192);
\r
341 SetupCartCHRMapping(0, CHRRAM, 8192, 1);
\r
342 AddExState(CHRRAM, 8192, 0, "CHRR");
\r
344 AddExState(DRegs, 4, 0, "DREG");
\r
346 info->Power=GenMMC1Power;
\r
347 GameStateRestore=MMC1_Restore;
\r
348 AddExState(&lreset, 8, 1, "LRST");
\r
351 void Mapper1_Init(CartInfo *info)
\r
353 int ws=DetectMMC1WRAMSize(info->CRC32);
\r
354 GenMMC1Init(info, 512, 256, ws, info->battery);
\r
357 /* Same as mapper 1, without respect for WRAM enable bit. */
\r
358 void Mapper155_Init(CartInfo *info)
\r
360 GenMMC1Init(info,512,256,8,info->battery);
\r
364 /* Same as mapper 1, with different (or without) mirroring control. */
\r
365 /* Kaiser KS7058 board, KS203 custom chip */
\r
366 void Mapper171_Init(CartInfo *info)
\r
368 GenMMC1Init(info,32,32,0,0);
\r
372 void SAROM_Init(CartInfo *info)
\r
374 GenMMC1Init(info, 128, 64, 8, info->battery);
\r
377 void SBROM_Init(CartInfo *info)
\r
379 GenMMC1Init(info, 128, 64, 0, 0);
\r
382 void SCROM_Init(CartInfo *info)
\r
384 GenMMC1Init(info, 128, 128, 0, 0);
\r
387 void SEROM_Init(CartInfo *info)
\r
389 GenMMC1Init(info, 32, 64, 0, 0);
\r
392 void SGROM_Init(CartInfo *info)
\r
394 GenMMC1Init(info, 256, 0, 0, 0);
\r
397 void SKROM_Init(CartInfo *info)
\r
399 GenMMC1Init(info, 256, 64, 8, info->battery);
\r
402 void SLROM_Init(CartInfo *info)
\r
404 GenMMC1Init(info, 256, 128, 0, 0);
\r
407 void SL1ROM_Init(CartInfo *info)
\r
409 GenMMC1Init(info, 128, 128, 0, 0);
\r
412 /* Begin unknown - may be wrong - perhaps they use different MMC1s from the
\r
413 similarly functioning boards?
\r
416 void SL2ROM_Init(CartInfo *info)
\r
418 GenMMC1Init(info, 256, 256, 0, 0);
\r
421 void SFROM_Init(CartInfo *info)
\r
423 GenMMC1Init(info, 256, 256, 0, 0);
\r
426 void SHROM_Init(CartInfo *info)
\r
428 GenMMC1Init(info, 256, 256, 0, 0);
\r
435 void SNROM_Init(CartInfo *info)
\r
437 GenMMC1Init(info, 256, 0, 8, info->battery);
\r
440 void SOROM_Init(CartInfo *info)
\r
442 GenMMC1Init(info, 256, 0, 16, info->battery);
\r