1 /* FCE Ultra - NES/Famicom Emulator
3 * Copyright notice for this file:
4 * Copyright (C) 1998 BERO
5 * Copyright (C) 2002 Xodnizel
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 static void GenMMC1Power(void);
25 static void GenMMC1Init(CartInfo *info, int prg, int chr, int wram, int battery);
27 static uint8 DRegs[4];
28 static uint8 Buffer,BufferShift;
32 static void (*MMC1CHRHook4)(uint32 A, uint8 V);
33 static void (*MMC1PRGHook16)(uint32 A, uint8 V);
35 static uint8 *WRAM=NULL;
36 static uint8 *CHRRAM=NULL;
41 if(!(DRegs[3]&0x10)||is155)
42 Page[A>>11][A]=V; // WRAM is enabled.
47 if((DRegs[3]&0x10)&&!is155)
48 return X.DB; // WRAM is disabled
49 return(Page[A>>11][A]);
52 static void MMC1CHR(void)
57 setprg8r(0x10,0x6000,(DRegs[1]>>4)&1);
59 setprg8r(0x10,0x6000,(DRegs[1]>>3)&1);
65 MMC1CHRHook4(0x0000,DRegs[1]);
66 MMC1CHRHook4(0x1000,DRegs[2]);
70 MMC1CHRHook4(0x0000,(DRegs[1]&0xFE));
71 MMC1CHRHook4(0x1000,DRegs[1]|1);
78 setchr4(0x0000,DRegs[1]);
79 setchr4(0x1000,DRegs[2]);
86 static void MMC1PRG(void)
88 uint8 offs=DRegs[1]&0x10;
93 case 0xC: MMC1PRGHook16(0x8000,(DRegs[3]+offs));
94 MMC1PRGHook16(0xC000,0xF+offs);
96 case 0x8: MMC1PRGHook16(0xC000,(DRegs[3]+offs));
97 MMC1PRGHook16(0x8000,offs);
101 MMC1PRGHook16(0x8000,((DRegs[3]&~1)+offs));
102 MMC1PRGHook16(0xc000,((DRegs[3]&~1)+offs+1));
106 else switch(DRegs[0]&0xC)
108 case 0xC: setprg16(0x8000,(DRegs[3]+offs));
109 setprg16(0xC000,0xF+offs);
111 case 0x8: setprg16(0xC000,(DRegs[3]+offs));
112 setprg16(0x8000,offs);
116 setprg16(0x8000,((DRegs[3]&~1)+offs));
117 setprg16(0xc000,((DRegs[3]&~1)+offs+1));
122 static void MMC1MIRROR(void)
126 case 2: setmirror(MI_V); break;
127 case 3: setmirror(MI_H); break;
128 case 0: setmirror(MI_0); break;
129 case 1: setmirror(MI_1); break;
133 static uint64 lreset;
134 static DECLFW(MMC1_write)
137 //FCEU_DispMessage("%016x",timestampbase+timestamp);
138 //printf("$%04x:$%02x, $%04x\n",A,V,X.PC);
139 //DumpMem("out",0xe000,0xffff);
141 /* The MMC1 is busy so ignore the write. */
142 /* As of version FCE Ultra 0.81, the timestamp is only
143 increased before each instruction is executed(in other words
144 precision isn't that great), but this should still work to
145 deal with 2 writes in a row from a single RMW instruction. */
146 if((timestampbase+timestamp)<(lreset+2)) return;
150 BufferShift=Buffer=0;
152 lreset=timestampbase+timestamp;
155 Buffer|=(V&1)<<(BufferShift++);
159 BufferShift = Buffer = 0;
162 case 0: MMC1MIRROR(); MMC1CHR(); MMC1PRG(); break;
163 case 1: MMC1CHR(); MMC1PRG(); break;
164 case 2: MMC1CHR(); break;
165 case 3: MMC1PRG(); break;
170 static void MMC1_Restore(int version)
175 lreset=0; /* timestamp(base) is not stored in save states. */
178 static void MMC1CMReset(void)
183 Buffer = BufferShift = 0;
186 DRegs[2]=0; // Should this be something other than 0?
194 static int DetectMMC1WRAMSize(uint32 crc32)
198 case 0xc6182024: /* Romance of the 3 Kingdoms */
199 case 0x2225c20f: /* Genghis Khan */
200 case 0x4642dda6: /* Nobunaga's Ambition */
201 case 0x29449ba9: /* "" "" (J) */
202 case 0x2b11e0b0: /* "" "" (J) */
203 case 0xb8747abf: /* Best Play Pro Yakyuu Special (J) */
204 case 0xc9556b36: /* Final Fantasy I & II (J) [!] */
205 FCEU_printf(" >8KB external WRAM present. Use UNIF if you hack the ROM image.\n");
212 static uint32 NWCIRQCount;
216 static void FP_FASTAPASS(1) NWCIRQHook(int a)
221 if((NWCIRQCount|(NWCDIP<<25))>=0x3e000000)
224 X6502_IRQBegin(FCEU_IQEXT);
229 static void NWCCHRHook(uint32 A, uint8 V)
231 if((V&0x10)) // && !(NWCRec&0x10))
234 X6502_IRQEnd(FCEU_IQEXT);
240 setprg32(0x8000,(V>>1)&3);
243 static void NWCPRGHook(uint32 A, uint8 V)
246 setprg16(A,8|(V&0x7));
248 setprg32(0x8000,(NWCRec>>1)&3);
251 static void NWCPower(void)
257 void Mapper105_Init(CartInfo *info)
259 GenMMC1Init(info, 256, 256, 8, 0);
260 MMC1CHRHook4=NWCCHRHook;
261 MMC1PRGHook16=NWCPRGHook;
262 MapIRQHook=NWCIRQHook;
263 info->Power=NWCPower;
266 static void GenMMC1Power(void)
271 FCEU_CheatAddRAM(8,0x6000,WRAM);
273 FCEU_dwmemset(WRAM,0,8192)
274 else if(!(mmc1opts&2))
275 FCEU_dwmemset(WRAM,0,8192);
277 SetWriteHandler(0x8000,0xFFFF,MMC1_write);
278 SetReadHandler(0x8000,0xFFFF,CartBR);
282 SetReadHandler(0x6000,0x7FFF,MAWRAM);
283 SetWriteHandler(0x6000,0x7FFF,MBWRAM);
284 setprg8r(0x10,0x6000,0);
290 static void GenMMC1Close(void)
299 static void GenMMC1Init(CartInfo *info, int prg, int chr, int wram, int battery)
303 info->Close=GenMMC1Close;
304 MMC1PRGHook16=MMC1CHRHook4=0;
306 PRGmask16[0]&=(prg>>14)-1;
307 CHRmask4[0]&=(chr>>12)-1;
308 CHRmask8[0]&=(chr>>13)-1;
312 WRAM=(uint8*)FCEU_gmalloc(wram*1024);
314 if(wram>8) mmc1opts|=4;
315 SetupCartPRGMapping(0x10,WRAM,wram*1024,1);
316 AddExState(WRAM, wram*1024, 0, "WRAM");
320 info->SaveGame[0]=WRAM+((mmc1opts&4)?8192:0);
321 info->SaveGameLen[0]=8192;
326 CHRRAM=(uint8*)FCEU_gmalloc(8192);
327 SetupCartCHRMapping(0, CHRRAM, 8192, 1);
328 AddExState(CHRRAM, 8192, 0, "CHRR");
330 AddExState(DRegs, 4, 0, "DREG");
332 info->Power=GenMMC1Power;
333 GameStateRestore=MMC1_Restore;
334 AddExState(&lreset, 8, 1, "LRST");
337 void Mapper1_Init(CartInfo *info)
339 int ws=DetectMMC1WRAMSize(info->CRC32);
340 GenMMC1Init(info, 512, 256, ws, info->battery);
343 /* Same as mapper 1, without respect for WRAM enable bit. */
344 void Mapper155_Init(CartInfo *info)
346 GenMMC1Init(info,512,256,8,info->battery);
350 void SAROM_Init(CartInfo *info)
352 GenMMC1Init(info, 128, 64, 8, info->battery);
355 void SBROM_Init(CartInfo *info)
357 GenMMC1Init(info, 128, 64, 0, 0);
360 void SCROM_Init(CartInfo *info)
362 GenMMC1Init(info, 128, 128, 0, 0);
365 void SEROM_Init(CartInfo *info)
367 GenMMC1Init(info, 32, 64, 0, 0);
370 void SGROM_Init(CartInfo *info)
372 GenMMC1Init(info, 256, 0, 0, 0);
375 void SKROM_Init(CartInfo *info)
377 GenMMC1Init(info, 256, 64, 8, info->battery);
380 void SLROM_Init(CartInfo *info)
382 GenMMC1Init(info, 256, 128, 0, 0);
385 void SL1ROM_Init(CartInfo *info)
387 GenMMC1Init(info, 128, 128, 0, 0);
390 /* Begin unknown - may be wrong - perhaps they use different MMC1s from the
391 similarly functioning boards?
394 void SL2ROM_Init(CartInfo *info)
396 GenMMC1Init(info, 256, 256, 0, 0);
399 void SFROM_Init(CartInfo *info)
401 GenMMC1Init(info, 256, 256, 0, 0);
404 void SHROM_Init(CartInfo *info)
406 GenMMC1Init(info, 256, 256, 0, 0);
413 void SNROM_Init(CartInfo *info)
415 GenMMC1Init(info, 256, 0, 8, info->battery);
418 void SOROM_Init(CartInfo *info)
420 GenMMC1Init(info, 256, 0, 16, info->battery);