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 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
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
65 MMC1CHRHook4(0x0000,DRegs[1]);
\r
66 MMC1CHRHook4(0x1000,DRegs[2]);
\r
70 MMC1CHRHook4(0x0000,(DRegs[1]&0xFE));
\r
71 MMC1CHRHook4(0x1000,DRegs[1]|1);
\r
78 setchr4(0x0000,DRegs[1]);
\r
79 setchr4(0x1000,DRegs[2]);
\r
82 setchr8(DRegs[1]>>1);
\r
86 static void MMC1PRG(void)
\r
88 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
107 else switch(DRegs[0]&0xC)
\r
109 case 0xC: setprg16(0x8000,(DRegs[3]+offs));
\r
110 setprg16(0xC000,0xF+offs);
\r
112 case 0x8: setprg16(0xC000,(DRegs[3]+offs));
\r
113 setprg16(0x8000,offs);
\r
117 setprg16(0x8000,((DRegs[3]&~1)+offs));
\r
118 setprg16(0xc000,((DRegs[3]&~1)+offs+1));
\r
123 static void MMC1MIRROR(void)
\r
127 case 2: setmirror(MI_V); break;
\r
128 case 3: setmirror(MI_H); break;
\r
129 case 0: setmirror(MI_0); break;
\r
130 case 1: setmirror(MI_1); break;
\r
135 static uint64 lreset;
\r
136 static DECLFW(MMC1_write)
\r
139 //FCEU_DispMessage("%016x",timestampbase+timestamp);
\r
140 //printf("$%04x:$%02x, $%04x\n",A,V,X.PC);
\r
141 //DumpMem("out",0xe000,0xffff);
\r
143 /* The MMC1 is busy so ignore the write. */
\r
144 /* As of version FCE Ultra 0.81, the timestamp is only
\r
145 increased before each instruction is executed(in other words
\r
146 precision isn't that great), but this should still work to
\r
147 deal with 2 writes in a row from a single RMW instruction. */
\r
148 if((timestampbase+timestamp)<(lreset+2)) return;
\r
153 BufferShift=Buffer=0;
\r
155 lreset=timestampbase+timestamp;
\r
158 Buffer|=(V&1)<<(BufferShift++);
\r
162 BufferShift = Buffer = 0;
\r
165 case 0: MMC1MIRROR(); MMC1CHR(); MMC1PRG(); break;
\r
166 case 1: MMC1CHR(); MMC1PRG(); break;
\r
167 case 2: MMC1CHR(); break;
\r
168 case 3: MMC1PRG(); break;
\r
173 static void MMC1_Restore(int version)
\r
178 //lreset=0; /* timestamp(base) is not stored in save states. */ // it is now!
\r
181 static void MMC1CMReset(void)
\r
186 Buffer = BufferShift = 0;
\r
189 DRegs[2]=0; // Should this be something other than 0?
\r
197 static int DetectMMC1WRAMSize(uint32 crc32)
\r
201 case 0xc6182024: /* Romance of the 3 Kingdoms */
\r
202 case 0x2225c20f: /* Genghis Khan */
\r
203 case 0x4642dda6: /* Nobunaga's Ambition */
\r
204 case 0x29449ba9: /* "" "" (J) */
\r
205 case 0x2b11e0b0: /* "" "" (J) */
\r
206 FCEU_printf(" >8KB external WRAM present. Use UNIF if you hack the ROM image.\n");
\r
213 static uint32 NWCIRQCount;
\r
214 static uint8 NWCRec;
\r
217 static void FP_FASTAPASS(1) NWCIRQHook(int a)
\r
222 if((NWCIRQCount|(NWCDIP<<25))>=0x3e000000)
\r
225 X6502_IRQBegin(FCEU_IQEXT);
\r
230 static void NWCCHRHook(uint32 A, uint8 V)
\r
232 if((V&0x10)) // && !(NWCRec&0x10))
\r
235 X6502_IRQEnd(FCEU_IQEXT);
\r
241 setprg32(0x8000,(V>>1)&3);
\r
244 static void NWCPRGHook(uint32 A, uint8 V)
\r
247 setprg16(A,8|(V&0x7));
\r
249 setprg32(0x8000,(NWCRec>>1)&3);
\r
252 static void NWCPower(void)
\r
258 void Mapper105_Init(CartInfo *info)
\r
260 GenMMC1Init(info, 256, 256, 8, 0);
\r
261 MMC1CHRHook4=NWCCHRHook;
\r
262 MMC1PRGHook16=NWCPRGHook;
\r
263 MapIRQHook=NWCIRQHook;
\r
264 info->Power=NWCPower;
\r
267 static void GenMMC1Power(void)
\r
272 FCEU_CheatAddRAM(8,0x6000,WRAM);
\r
274 FCEU_dwmemset(WRAM,0,8192)
\r
275 else if(!(mmc1opts&2))
\r
276 FCEU_dwmemset(WRAM,0,8192);
\r
278 SetWriteHandler(0x8000,0xFFFF,MMC1_write);
\r
279 SetReadHandler(0x8000,0xFFFF,CartBR);
\r
283 SetReadHandler(0x6000,0x7FFF,MAWRAM);
\r
284 SetWriteHandler(0x6000,0x7FFF,MBWRAM);
\r
285 setprg8r(0x10,0x6000,0);
\r
291 static void GenMMC1Close(void)
\r
294 FCEU_gfree(CHRRAM);
\r
300 static void GenMMC1Init(CartInfo *info, int prg, int chr, int wram, int battery)
\r
304 info->Close=GenMMC1Close;
\r
305 MMC1PRGHook16=MMC1CHRHook4=0;
\r
307 PRGmask16[0]&=(prg>>14)-1;
\r
308 CHRmask4[0]&=(chr>>12)-1;
\r
309 CHRmask8[0]&=(chr>>13)-1;
\r
313 WRAM=(uint8*)FCEU_gmalloc(wram*1024);
\r
315 if(wram>8) mmc1opts|=4;
\r
316 SetupCartPRGMapping(0x10,WRAM,wram*1024,1);
\r
317 AddExState(WRAM, wram*1024, 0, "WRAM");
\r
321 info->SaveGame[0]=WRAM+((mmc1opts&4)?8192:0);
\r
322 info->SaveGameLen[0]=8192;
\r
327 CHRRAM=(uint8*)FCEU_gmalloc(8192);
\r
328 SetupCartCHRMapping(0, CHRRAM, 8192, 1);
\r
329 AddExState(CHRRAM, 8192, 0, "CHRR");
\r
331 AddExState(DRegs, 4, 0, "DREG");
\r
333 info->Power=GenMMC1Power;
\r
334 GameStateRestore=MMC1_Restore;
\r
335 AddExState(&lreset, 8, 1, "LRST");
\r
336 AddExState(&Buffer, 1, 1, "BFFR");
\r
337 AddExState(&BufferShift, 1, 1, "BFRS");
\r
340 void Mapper1_Init(CartInfo *info)
\r
342 int ws=DetectMMC1WRAMSize(info->CRC32);
\r
343 GenMMC1Init(info, 512, 256, ws, info->battery);
\r
346 /* Same as mapper 1, without respect for WRAM enable bit. */
\r
347 void Mapper155_Init(CartInfo *info)
\r
349 GenMMC1Init(info,512,256,8,info->battery);
\r
353 void SAROM_Init(CartInfo *info)
\r
355 GenMMC1Init(info, 128, 64, 8, info->battery);
\r
358 void SBROM_Init(CartInfo *info)
\r
360 GenMMC1Init(info, 128, 64, 0, 0);
\r
363 void SCROM_Init(CartInfo *info)
\r
365 GenMMC1Init(info, 128, 128, 0, 0);
\r
368 void SEROM_Init(CartInfo *info)
\r
370 GenMMC1Init(info, 32, 64, 0, 0);
\r
373 void SGROM_Init(CartInfo *info)
\r
375 GenMMC1Init(info, 256, 0, 0, 0);
\r
378 void SKROM_Init(CartInfo *info)
\r
380 GenMMC1Init(info, 256, 64, 8, info->battery);
\r
383 void SLROM_Init(CartInfo *info)
\r
385 GenMMC1Init(info, 256, 128, 0, 0);
\r
388 void SL1ROM_Init(CartInfo *info)
\r
390 GenMMC1Init(info, 128, 128, 0, 0);
\r
393 /* Begin unknown - may be wrong - perhaps they use different MMC1s from the
\r
394 similarly functioning boards?
\r
397 void SL2ROM_Init(CartInfo *info)
\r
399 GenMMC1Init(info, 256, 256, 0, 0);
\r
402 void SFROM_Init(CartInfo *info)
\r
404 GenMMC1Init(info, 256, 256, 0, 0);
\r
407 void SHROM_Init(CartInfo *info)
\r
409 GenMMC1Init(info, 256, 256, 0, 0);
\r
416 void SNROM_Init(CartInfo *info)
\r
418 GenMMC1Init(info, 256, 0, 8, info->battery);
\r
421 void SOROM_Init(CartInfo *info)
\r
423 GenMMC1Init(info, 256, 0, 16, info->battery);
\r