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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 DRegs[4];
\r
28 static uint8 Buffer,BufferShift;
\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",0,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
169 BufferShift = Buffer = 0;
\r
172 case 0: MMC1MIRROR(); MMC1CHR(); MMC1PRG(); break;
\r
173 case 1: MMC1CHR(); MMC1PRG(); break;
\r
174 case 2: MMC1CHR(); break;
\r
175 case 3: MMC1PRG(); break;
\r
180 static void MMC1_Restore(int version)
\r
185 lreset=0; /* timestamp(base) is not stored in save states. */
\r
188 static void MMC1CMReset(void)
\r
194 Buffer = BufferShift = 0;
\r
198 DRegs[2]=0; // Should this be something other than 0?
\r
206 static int DetectMMC1WRAMSize(uint32 crc32)
\r
210 case 0xc6182024: /* Romance of the 3 Kingdoms */
\r
211 case 0x2225c20f: /* Genghis Khan */
\r
212 case 0x4642dda6: /* Nobunaga's Ambition */
\r
213 case 0x29449ba9: /* "" "" (J) */
\r
214 case 0x2b11e0b0: /* "" "" (J) */
\r
215 case 0xb8747abf: /* Best Play Pro Yakyuu Special (J) */
\r
216 case 0xc9556b36: /* Final Fantasy I & II (J) [!] */
\r
217 FCEU_printf(" >8KB external WRAM present. Use UNIF if you hack the ROM image.\n");
\r
224 static uint32 NWCIRQCount;
\r
225 static uint8 NWCRec;
\r
228 static void NWCIRQHook(int a)
\r
233 if((NWCIRQCount|(NWCDIP<<25))>=0x3e000000)
\r
236 X6502_IRQBegin(FCEU_IQEXT);
\r
241 static void NWCCHRHook(uint32 A, uint8 V)
\r
243 if((V&0x10)) // && !(NWCRec&0x10))
\r
246 X6502_IRQEnd(FCEU_IQEXT);
\r
253 setprg32(0x8000,(V>>1)&3);
\r
256 static void NWCPRGHook(uint32 A, uint8 V)
\r
259 setprg16(A,8|(V&0x7));
\r
261 setprg32(0x8000,(NWCRec>>1)&3);
\r
264 static void NWCPower(void)
\r
270 void Mapper105_Init(CartInfo *info)
\r
272 GenMMC1Init(info, 256, 256, 8, 0);
\r
273 MMC1CHRHook4=NWCCHRHook;
\r
274 MMC1PRGHook16=NWCPRGHook;
\r
275 MapIRQHook=NWCIRQHook;
\r
276 info->Power=NWCPower;
\r
279 static void GenMMC1Power(void)
\r
284 FCEU_CheatAddRAM(8,0x6000,WRAM);
\r
286 FCEU_dwmemset(WRAM,0,8192)
\r
287 else if(!(mmc1opts&2))
\r
288 FCEU_dwmemset(WRAM,0,8192);
\r
290 SetWriteHandler(0x8000,0xFFFF,MMC1_write);
\r
291 SetReadHandler(0x8000,0xFFFF,CartBR);
\r
295 SetReadHandler(0x6000,0x7FFF,MAWRAM);
\r
296 SetWriteHandler(0x6000,0x7FFF,MBWRAM);
\r
297 setprg8r(0x10,0x6000,0);
\r
303 static void GenMMC1Close(void)
\r
306 FCEU_gfree(CHRRAM);
\r
312 static void GenMMC1Init(CartInfo *info, int prg, int chr, int wram, int battery)
\r
316 info->Close=GenMMC1Close;
\r
317 MMC1PRGHook16=MMC1CHRHook4=0;
\r
319 PRGmask16[0]&=(prg>>14)-1;
\r
320 CHRmask4[0]&=(chr>>12)-1;
\r
321 CHRmask8[0]&=(chr>>13)-1;
\r
325 WRAM=(uint8*)FCEU_gmalloc(wram*1024);
\r
326 //mbg 17-jun-08 - this shouldve been cleared to re-initialize save ram
\r
327 //ch4 10-dec-08 - nope, this souldn't
\r
328 //mbg 29-mar-09 - no time to debate this, we need to keep from breaking some old stuff.
\r
329 //we really need to make up a policy for how compatibility and accuracy can be resolved.
\r
330 memset(WRAM,0,wram*1024);
\r
332 if(wram>8) mmc1opts|=4;
\r
333 SetupCartPRGMapping(0x10,WRAM,wram*1024,1);
\r
334 AddExState(WRAM, wram*1024, 0, "WRAM");
\r
338 info->SaveGame[0]=WRAM+((mmc1opts&4)?8192:0);
\r
339 info->SaveGameLen[0]=8192;
\r
344 CHRRAM=(uint8*)FCEU_gmalloc(8192);
\r
345 SetupCartCHRMapping(0, CHRRAM, 8192, 1);
\r
346 AddExState(CHRRAM, 8192, 0, "CHRR");
\r
348 AddExState(DRegs, 4, 0, "DREG");
\r
350 info->Power=GenMMC1Power;
\r
351 GameStateRestore=MMC1_Restore;
\r
352 AddExState(&lreset, 8, 1, "LRST");
\r
353 AddExState(&Buffer, 1, 1, "BFFR");
\r
354 AddExState(&BufferShift, 1, 1, "BFRS");
\r
357 void Mapper1_Init(CartInfo *info)
\r
359 int ws=DetectMMC1WRAMSize(info->CRC32);
\r
360 GenMMC1Init(info, 512, 256, ws, info->battery);
\r
363 /* Same as mapper 1, without respect for WRAM enable bit. */
\r
364 void Mapper155_Init(CartInfo *info)
\r
366 GenMMC1Init(info,512,256,8,info->battery);
\r
370 /* Same as mapper 1, with different (or without) mirroring control. */
\r
371 /* Kaiser KS7058 board, KS203 custom chip */
\r
372 void Mapper171_Init(CartInfo *info)
\r
374 GenMMC1Init(info,32,32,0,0);
\r
378 void SAROM_Init(CartInfo *info)
\r
380 GenMMC1Init(info, 128, 64, 8, info->battery);
\r
383 void SBROM_Init(CartInfo *info)
\r
385 GenMMC1Init(info, 128, 64, 0, 0);
\r
388 void SCROM_Init(CartInfo *info)
\r
390 GenMMC1Init(info, 128, 128, 0, 0);
\r
393 void SEROM_Init(CartInfo *info)
\r
395 GenMMC1Init(info, 32, 64, 0, 0);
\r
398 void SGROM_Init(CartInfo *info)
\r
400 GenMMC1Init(info, 256, 0, 0, 0);
\r
403 void SKROM_Init(CartInfo *info)
\r
405 GenMMC1Init(info, 256, 64, 8, info->battery);
\r
408 void SLROM_Init(CartInfo *info)
\r
410 GenMMC1Init(info, 256, 128, 0, 0);
\r
413 void SL1ROM_Init(CartInfo *info)
\r
415 GenMMC1Init(info, 128, 128, 0, 0);
\r
418 /* Begin unknown - may be wrong - perhaps they use different MMC1s from the
\r
419 similarly functioning boards?
\r
422 void SL2ROM_Init(CartInfo *info)
\r
424 GenMMC1Init(info, 256, 256, 0, 0);
\r
427 void SFROM_Init(CartInfo *info)
\r
429 GenMMC1Init(info, 256, 256, 0, 0);
\r
432 void SHROM_Init(CartInfo *info)
\r
434 GenMMC1Init(info, 256, 256, 0, 0);
\r
441 void SNROM_Init(CartInfo *info)
\r
443 GenMMC1Init(info, 256, 0, 8, info->battery);
\r
446 void SOROM_Init(CartInfo *info)
\r
448 GenMMC1Init(info, 256, 0, 16, info->battery);
\r