random warning fixes
[fceu.git] / boards / mmc1.c
CommitLineData
386f5371 1/* FCE Ultra - NES/Famicom Emulator\r
2 *\r
3 * Copyright notice for this file:\r
4 * Copyright (C) 1998 BERO\r
5 * Copyright (C) 2002 Xodnizel\r
6 *\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
11 *\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
16 *\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
43725da7 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
386f5371 20 */\r
21\r
22#include "mapinc.h"\r
23\r
24static void GenMMC1Power(void);\r
25static void GenMMC1Init(CartInfo *info, int prg, int chr, int wram, int battery);\r
26\r
43725da7 27static uint8 BufferShift,DRegs[4];\r
28static uint8 Buffer;\r
386f5371 29\r
30static int mmc1opts;\r
31\r
32static void (*MMC1CHRHook4)(uint32 A, uint8 V);\r
33static void (*MMC1PRGHook16)(uint32 A, uint8 V);\r
34\r
35static uint8 *WRAM=NULL;\r
36static uint8 *CHRRAM=NULL;\r
37static int is155, is171;\r
38\r
39static DECLFW(MBWRAM)\r
40{\r
41 if(!(DRegs[3]&0x10)||is155)\r
42 Page[A>>11][A]=V; // WRAM is enabled.\r
43}\r
44\r
45static DECLFR(MAWRAM)\r
46{\r
47 if((DRegs[3]&0x10)&&!is155)\r
48 return X.DB; // WRAM is disabled\r
49 return(Page[A>>11][A]);\r
50}\r
51\r
52static void MMC1CHR(void)\r
53{\r
54 if(mmc1opts&4)\r
55 {\r
56 if(DRegs[0]&0x10)\r
57 setprg8r(0x10,0x6000,(DRegs[1]>>4)&1);\r
58 else\r
59 setprg8r(0x10,0x6000,(DRegs[1]>>3)&1);\r
60 }\r
61\r
62 if(MMC1CHRHook4)\r
63 {\r
64 if(DRegs[0]&0x10)\r
65 {\r
66 MMC1CHRHook4(0x0000,DRegs[1]);\r
67 MMC1CHRHook4(0x1000,DRegs[2]);\r
68 }\r
69 else\r
70 {\r
71 MMC1CHRHook4(0x0000,(DRegs[1]&0xFE));\r
72 MMC1CHRHook4(0x1000,DRegs[1]|1);\r
73 }\r
74 }\r
75 else\r
76 {\r
77 if(DRegs[0]&0x10)\r
78 {\r
79 setchr4(0x0000,DRegs[1]);\r
80 setchr4(0x1000,DRegs[2]);\r
81 }\r
82 else\r
83 setchr8(DRegs[1]>>1);\r
84 }\r
85}\r
86\r
87static void MMC1PRG(void)\r
88{\r
89 uint8 offs=DRegs[1]&0x10;\r
90 if(MMC1PRGHook16)\r
91 {\r
92 switch(DRegs[0]&0xC)\r
93 {\r
94 case 0xC: MMC1PRGHook16(0x8000,(DRegs[3]+offs));\r
95 MMC1PRGHook16(0xC000,0xF+offs);\r
96 break;\r
97 case 0x8: MMC1PRGHook16(0xC000,(DRegs[3]+offs));\r
98 MMC1PRGHook16(0x8000,offs);\r
99 break;\r
100 case 0x0:\r
101 case 0x4:\r
102 MMC1PRGHook16(0x8000,((DRegs[3]&~1)+offs));\r
103 MMC1PRGHook16(0xc000,((DRegs[3]&~1)+offs+1));\r
104 break;\r
105 }\r
106 }\r
107 else\r
108 {\r
109 switch(DRegs[0]&0xC)\r
43725da7 110 {\r
111 case 0xC: setprg16(0x8000,(DRegs[3]+offs));\r
112 setprg16(0xC000,0xF+offs);\r
113 break;\r
114 case 0x8: setprg16(0xC000,(DRegs[3]+offs));\r
115 setprg16(0x8000,offs);\r
116 break;\r
117 case 0x0:\r
118 case 0x4:\r
119 setprg16(0x8000,((DRegs[3]&~1)+offs));\r
120 setprg16(0xc000,((DRegs[3]&~1)+offs+1));\r
121 break;\r
122 }\r
386f5371 123 }\r
124}\r
386f5371 125\r
126static void MMC1MIRROR(void)\r
127{\r
128 if(!is171) \r
43725da7 129 switch(DRegs[0]&3)\r
130 {\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
135 }\r
386f5371 136}\r
137\r
138static uint64 lreset;\r
139static DECLFW(MMC1_write)\r
140{\r
141 int n=(A>>13)-4;\r
43725da7 142 //FCEU_DispMessage("%016x",timestampbase+timestamp);\r
386f5371 143// FCEU_printf("$%04x:$%02x, $%04x\n",A,V,X.PC);\r
144 //DumpMem("out",0xe000,0xffff);\r
145\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
151 */\r
152 if((timestampbase+timestamp)<(lreset+2))\r
153 return;\r
154// FCEU_printf("Write %04x:%02x\n",A,V);\r
155 if(V&0x80)\r
156 {\r
157 DRegs[0]|=0xC;\r
158 BufferShift=Buffer=0;\r
159 MMC1PRG();\r
160 lreset=timestampbase+timestamp;\r
161 return;\r
162 }\r
163\r
164 Buffer|=(V&1)<<(BufferShift++);\r
165\r
166 if(BufferShift==5)\r
167 {\r
43725da7 168// FCEU_printf("REG[%d]=%02x\n",n,Buffer);\r
386f5371 169 DRegs[n] = Buffer;\r
170 BufferShift = Buffer = 0;\r
171 switch(n)\r
172 {\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
177 }\r
178 }\r
179}\r
180\r
181static void MMC1_Restore(int version)\r
182{\r
183 MMC1MIRROR();\r
184 MMC1CHR();\r
185 MMC1PRG();\r
186 lreset=0; /* timestamp(base) is not stored in save states. */\r
187}\r
188\r
189static void MMC1CMReset(void)\r
190{\r
191 int i;\r
192\r
193 for(i=0;i<4;i++)\r
194 DRegs[i]=0;\r
195 Buffer = BufferShift = 0;\r
196 DRegs[0]=0x1F;\r
197\r
198 DRegs[1]=0;\r
199 DRegs[2]=0; // Should this be something other than 0?\r
200 DRegs[3]=0;\r
201\r
202 MMC1MIRROR();\r
203 MMC1CHR();\r
204 MMC1PRG();\r
205}\r
206\r
207static int DetectMMC1WRAMSize(uint32 crc32)\r
208{\r
209 switch(crc32)\r
210 {\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
219 return(16);\r
220 break;\r
221 default:return(8);\r
222 }\r
223}\r
224\r
225static uint32 NWCIRQCount;\r
226static uint8 NWCRec;\r
227#define NWCDIP 0xE\r
228\r
229static void NWCIRQHook(int a)\r
230{\r
231 if(!(NWCRec&0x10))\r
232 {\r
233 NWCIRQCount+=a;\r
234 if((NWCIRQCount|(NWCDIP<<25))>=0x3e000000)\r
235 {\r
236 NWCIRQCount=0;\r
237 X6502_IRQBegin(FCEU_IQEXT);\r
238 }\r
239 }\r
240}\r
241\r
242static void NWCCHRHook(uint32 A, uint8 V)\r
243{\r
244 if((V&0x10)) // && !(NWCRec&0x10))\r
245 {\r
246 NWCIRQCount=0;\r
247 X6502_IRQEnd(FCEU_IQEXT);\r
248 }\r
249\r
250 NWCRec=V;\r
251 if(V&0x08)\r
252 MMC1PRG();\r
253 else\r
254 setprg32(0x8000,(V>>1)&3);\r
255}\r
256\r
257static void NWCPRGHook(uint32 A, uint8 V)\r
258{\r
259 if(NWCRec&0x8)\r
260 setprg16(A,8|(V&0x7));\r
261 else\r
262 setprg32(0x8000,(NWCRec>>1)&3);\r
263}\r
264\r
265static void NWCPower(void)\r
266{\r
267 GenMMC1Power();\r
268 setchr8r(0,0);\r
269}\r
270\r
271void Mapper105_Init(CartInfo *info)\r
272{\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
278}\r
279\r
280static void GenMMC1Power(void)\r
281{\r
282 lreset=0;\r
283 if(mmc1opts&1)\r
284 {\r
285 FCEU_CheatAddRAM(8,0x6000,WRAM);\r
286 if(mmc1opts&4)\r
287 FCEU_dwmemset(WRAM,0,8192)\r
288 else if(!(mmc1opts&2))\r
289 FCEU_dwmemset(WRAM,0,8192);\r
290 }\r
291 SetWriteHandler(0x8000,0xFFFF,MMC1_write);\r
292 SetReadHandler(0x8000,0xFFFF,CartBR);\r
293\r
294 if(mmc1opts&1)\r
295 {\r
296 SetReadHandler(0x6000,0x7FFF,MAWRAM);\r
297 SetWriteHandler(0x6000,0x7FFF,MBWRAM);\r
298 setprg8r(0x10,0x6000,0);\r
299 }\r
300\r
301 MMC1CMReset();\r
302}\r
303\r
304static void GenMMC1Close(void)\r
305{\r
306 if(CHRRAM)\r
307 FCEU_gfree(CHRRAM);\r
308 if(WRAM)\r
309 FCEU_gfree(WRAM);\r
310 CHRRAM=WRAM=NULL;\r
311}\r
312\r
313static void GenMMC1Init(CartInfo *info, int prg, int chr, int wram, int battery)\r
314{\r
315 is155=0;\r
316\r
317 info->Close=GenMMC1Close;\r
318 MMC1PRGHook16=MMC1CHRHook4=0;\r
319 mmc1opts=0;\r
320 PRGmask16[0]&=(prg>>14)-1;\r
321 CHRmask4[0]&=(chr>>12)-1;\r
322 CHRmask8[0]&=(chr>>13)-1;\r
323\r
324 if(wram)\r
325 {\r
326 WRAM=(uint8*)FCEU_gmalloc(wram*1024);\r
386f5371 327 mmc1opts|=1;\r
328 if(wram>8) mmc1opts|=4;\r
329 SetupCartPRGMapping(0x10,WRAM,wram*1024,1);\r
330 AddExState(WRAM, wram*1024, 0, "WRAM");\r
331 if(battery)\r
332 {\r
333 mmc1opts|=2;\r
334 info->SaveGame[0]=WRAM+((mmc1opts&4)?8192:0);\r
335 info->SaveGameLen[0]=8192;\r
336 }\r
337 }\r
338 if(!chr)\r
339 {\r
340 CHRRAM=(uint8*)FCEU_gmalloc(8192);\r
341 SetupCartCHRMapping(0, CHRRAM, 8192, 1);\r
342 AddExState(CHRRAM, 8192, 0, "CHRR");\r
343 }\r
344 AddExState(DRegs, 4, 0, "DREG");\r
345\r
346 info->Power=GenMMC1Power;\r
347 GameStateRestore=MMC1_Restore;\r
348 AddExState(&lreset, 8, 1, "LRST");\r
386f5371 349}\r
350\r
351void Mapper1_Init(CartInfo *info)\r
352{\r
353 int ws=DetectMMC1WRAMSize(info->CRC32);\r
354 GenMMC1Init(info, 512, 256, ws, info->battery);\r
355}\r
356\r
357/* Same as mapper 1, without respect for WRAM enable bit. */\r
358void Mapper155_Init(CartInfo *info)\r
359{\r
360 GenMMC1Init(info,512,256,8,info->battery);\r
361 is155=1;\r
362}\r
363\r
364/* Same as mapper 1, with different (or without) mirroring control. */\r
365/* Kaiser KS7058 board, KS203 custom chip */\r
366void Mapper171_Init(CartInfo *info)\r
367{\r
368 GenMMC1Init(info,32,32,0,0);\r
369 is171=1;\r
370}\r
371\r
372void SAROM_Init(CartInfo *info)\r
373{\r
374 GenMMC1Init(info, 128, 64, 8, info->battery);\r
375}\r
376\r
377void SBROM_Init(CartInfo *info)\r
378{\r
379 GenMMC1Init(info, 128, 64, 0, 0);\r
380}\r
381\r
382void SCROM_Init(CartInfo *info)\r
383{\r
384 GenMMC1Init(info, 128, 128, 0, 0);\r
385}\r
386\r
387void SEROM_Init(CartInfo *info)\r
388{\r
389 GenMMC1Init(info, 32, 64, 0, 0);\r
390}\r
391\r
392void SGROM_Init(CartInfo *info)\r
393{\r
394 GenMMC1Init(info, 256, 0, 0, 0);\r
395}\r
396\r
397void SKROM_Init(CartInfo *info)\r
398{\r
399 GenMMC1Init(info, 256, 64, 8, info->battery);\r
400}\r
401\r
402void SLROM_Init(CartInfo *info)\r
403{\r
404 GenMMC1Init(info, 256, 128, 0, 0);\r
405}\r
406\r
407void SL1ROM_Init(CartInfo *info)\r
408{\r
409 GenMMC1Init(info, 128, 128, 0, 0);\r
410}\r
411\r
412/* Begin unknown - may be wrong - perhaps they use different MMC1s from the\r
413 similarly functioning boards?\r
414*/\r
415\r
416void SL2ROM_Init(CartInfo *info)\r
417{\r
418 GenMMC1Init(info, 256, 256, 0, 0);\r
419}\r
420\r
421void SFROM_Init(CartInfo *info)\r
422{\r
423 GenMMC1Init(info, 256, 256, 0, 0);\r
424}\r
425\r
426void SHROM_Init(CartInfo *info)\r
427{\r
428 GenMMC1Init(info, 256, 256, 0, 0);\r
429}\r
430\r
431/* End unknown */\r
432/* */\r
433/* */\r
434\r
435void SNROM_Init(CartInfo *info)\r
436{\r
437 GenMMC1Init(info, 256, 0, 8, info->battery);\r
438}\r
439\r
440void SOROM_Init(CartInfo *info)\r
441{\r
442 GenMMC1Init(info, 256, 0, 16, info->battery);\r
443}\r
444\r
445\r