updated bords/mappers/stuff to 0.98.15, lots of them got broken, asmcore support...
[fceu.git] / boards / mmc1.c
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
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
20  */\r
21 \r
22 #include "mapinc.h"\r
23 \r
24 static void GenMMC1Power(void);\r
25 static void GenMMC1Init(CartInfo *info, int prg, int chr, int wram, int battery);\r
26 \r
27 static uint8 DRegs[4];\r
28 static uint8 Buffer,BufferShift;\r
29 \r
30 static int mmc1opts;\r
31 \r
32 static void (*MMC1CHRHook4)(uint32 A, uint8 V);\r
33 static void (*MMC1PRGHook16)(uint32 A, uint8 V);\r
34 \r
35 static uint8 *WRAM=NULL;\r
36 static uint8 *CHRRAM=NULL;\r
37 static int is155;\r
38 \r
39 static 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
45 static 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
52 static 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   if(MMC1CHRHook4)\r
62   {\r
63     if(DRegs[0]&0x10)\r
64     {\r
65       MMC1CHRHook4(0x0000,DRegs[1]);\r
66       MMC1CHRHook4(0x1000,DRegs[2]);\r
67     }\r
68     else\r
69     {\r
70       MMC1CHRHook4(0x0000,(DRegs[1]&0xFE));\r
71       MMC1CHRHook4(0x1000,DRegs[1]|1);\r
72     }\r
73   }\r
74   else\r
75   {\r
76     if(DRegs[0]&0x10)\r
77     {\r
78       setchr4(0x0000,DRegs[1]);\r
79       setchr4(0x1000,DRegs[2]);\r
80     }\r
81     else\r
82       setchr8(DRegs[1]>>1);\r
83   }\r
84 }\r
85 \r
86 static void MMC1PRG(void)\r
87 {\r
88   uint8 offs=DRegs[1]&0x10;\r
89 \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 switch(DRegs[0]&0xC)\r
108   {\r
109     case 0xC: setprg16(0x8000,(DRegs[3]+offs));\r
110               setprg16(0xC000,0xF+offs);\r
111               break;\r
112     case 0x8: setprg16(0xC000,(DRegs[3]+offs));\r
113               setprg16(0x8000,offs);\r
114               break;\r
115     case 0x0:\r
116     case 0x4:\r
117               setprg16(0x8000,((DRegs[3]&~1)+offs));\r
118               setprg16(0xc000,((DRegs[3]&~1)+offs+1));\r
119               break;\r
120   }\r
121 }\r
122 \r
123 static void MMC1MIRROR(void)\r
124 {\r
125   switch(DRegs[0]&3)\r
126   {\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
131   }\r
132 }\r
133 \r
134 \r
135 static uint64 lreset;\r
136 static DECLFW(MMC1_write)\r
137 {\r
138   int n=(A>>13)-4;\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
142 \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
149 \r
150   if(V&0x80)\r
151   {\r
152     DRegs[0]|=0xC;\r
153     BufferShift=Buffer=0;\r
154     MMC1PRG();\r
155     lreset=timestampbase+timestamp;\r
156     return;\r
157   }\r
158   Buffer|=(V&1)<<(BufferShift++);\r
159   if(BufferShift==5)\r
160   {\r
161     DRegs[n] = Buffer;\r
162     BufferShift = Buffer = 0;\r
163     switch(n)\r
164     {\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
169     }\r
170   }\r
171 }\r
172 \r
173 static void MMC1_Restore(int version)\r
174 {\r
175   MMC1MIRROR();\r
176   MMC1CHR();\r
177   MMC1PRG();\r
178   //lreset=0;        /* timestamp(base) is not stored in save states. */ // it is now!\r
179 }\r
180 \r
181 static void MMC1CMReset(void)\r
182 {\r
183   int i;\r
184   for(i=0;i<4;i++)\r
185      DRegs[i]=0;\r
186   Buffer = BufferShift = 0;\r
187   DRegs[0]=0x1F;\r
188   DRegs[1]=0;\r
189   DRegs[2]=0;                  // Should this be something other than 0?\r
190   DRegs[3]=0;\r
191 \r
192   MMC1MIRROR();\r
193   MMC1CHR();\r
194   MMC1PRG();\r
195 }\r
196 \r
197 static int DetectMMC1WRAMSize(uint32 crc32)\r
198 {\r
199   switch(crc32)\r
200   {\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
207          return(16);\r
208          break;\r
209     default:return(8);\r
210   }\r
211 }\r
212 \r
213 static uint32 NWCIRQCount;\r
214 static uint8 NWCRec;\r
215 #define NWCDIP 0xE\r
216 \r
217 static void FP_FASTAPASS(1) NWCIRQHook(int a)\r
218 {\r
219   if(!(NWCRec&0x10))\r
220   {\r
221     NWCIRQCount+=a;\r
222     if((NWCIRQCount|(NWCDIP<<25))>=0x3e000000)\r
223     {\r
224       NWCIRQCount=0;\r
225       X6502_IRQBegin(FCEU_IQEXT);\r
226     }\r
227   }\r
228 }\r
229 \r
230 static void NWCCHRHook(uint32 A, uint8 V)\r
231 {\r
232   if((V&0x10)) // && !(NWCRec&0x10))\r
233   {\r
234     NWCIRQCount=0;\r
235     X6502_IRQEnd(FCEU_IQEXT);\r
236   }\r
237   NWCRec=V;\r
238   if(V&0x08)\r
239     MMC1PRG();\r
240   else\r
241     setprg32(0x8000,(V>>1)&3);\r
242 }\r
243 \r
244 static void NWCPRGHook(uint32 A, uint8 V)\r
245 {\r
246   if(NWCRec&0x8)\r
247     setprg16(A,8|(V&0x7));\r
248   else\r
249     setprg32(0x8000,(NWCRec>>1)&3);\r
250 }\r
251 \r
252 static void NWCPower(void)\r
253 {\r
254   GenMMC1Power();\r
255   setchr8r(0,0);\r
256 }\r
257 \r
258 void Mapper105_Init(CartInfo *info)\r
259 {\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
265 }\r
266 \r
267 static void GenMMC1Power(void)\r
268 {\r
269   lreset=0;\r
270   if(mmc1opts&1)\r
271   {\r
272     FCEU_CheatAddRAM(8,0x6000,WRAM);\r
273     if(mmc1opts&4)\r
274       FCEU_dwmemset(WRAM,0,8192)\r
275     else if(!(mmc1opts&2))\r
276       FCEU_dwmemset(WRAM,0,8192);\r
277   }\r
278   SetWriteHandler(0x8000,0xFFFF,MMC1_write);\r
279   SetReadHandler(0x8000,0xFFFF,CartBR);\r
280 \r
281   if(mmc1opts&1)\r
282   {\r
283     SetReadHandler(0x6000,0x7FFF,MAWRAM);\r
284     SetWriteHandler(0x6000,0x7FFF,MBWRAM);\r
285     setprg8r(0x10,0x6000,0);\r
286   }\r
287 \r
288   MMC1CMReset();\r
289 }\r
290 \r
291 static void GenMMC1Close(void)\r
292 {\r
293   if(CHRRAM)\r
294     FCEU_gfree(CHRRAM);\r
295   if(WRAM)\r
296     FCEU_gfree(WRAM);\r
297   CHRRAM=WRAM=NULL;\r
298 }\r
299 \r
300 static void GenMMC1Init(CartInfo *info, int prg, int chr, int wram, int battery)\r
301 {\r
302   is155=0;\r
303 \r
304   info->Close=GenMMC1Close;\r
305   MMC1PRGHook16=MMC1CHRHook4=0;\r
306   mmc1opts=0;\r
307   PRGmask16[0]&=(prg>>14)-1;\r
308   CHRmask4[0]&=(chr>>12)-1;\r
309   CHRmask8[0]&=(chr>>13)-1;\r
310 \r
311   if(wram)\r
312   {\r
313     WRAM=(uint8*)FCEU_gmalloc(wram*1024);\r
314     mmc1opts|=1;\r
315     if(wram>8) mmc1opts|=4;\r
316     SetupCartPRGMapping(0x10,WRAM,wram*1024,1);\r
317     AddExState(WRAM, wram*1024, 0, "WRAM");\r
318     if(battery)\r
319     {\r
320       mmc1opts|=2;\r
321       info->SaveGame[0]=WRAM+((mmc1opts&4)?8192:0);\r
322       info->SaveGameLen[0]=8192;\r
323     }\r
324   }\r
325   if(!chr)\r
326   {\r
327     CHRRAM=(uint8*)FCEU_gmalloc(8192);\r
328     SetupCartCHRMapping(0, CHRRAM, 8192, 1);\r
329     AddExState(CHRRAM, 8192, 0, "CHRR");\r
330   }\r
331   AddExState(DRegs, 4, 0, "DREG");\r
332 \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
338 }\r
339 \r
340 void Mapper1_Init(CartInfo *info)\r
341 {\r
342   int ws=DetectMMC1WRAMSize(info->CRC32);\r
343   GenMMC1Init(info, 512, 256, ws, info->battery);\r
344 }\r
345 \r
346 /* Same as mapper 1, without respect for WRAM enable bit. */\r
347 void Mapper155_Init(CartInfo *info)\r
348 {\r
349   GenMMC1Init(info,512,256,8,info->battery);\r
350   is155=1;\r
351 }\r
352 \r
353 void SAROM_Init(CartInfo *info)\r
354 {\r
355   GenMMC1Init(info, 128, 64, 8, info->battery);\r
356 }\r
357 \r
358 void SBROM_Init(CartInfo *info)\r
359 {\r
360   GenMMC1Init(info, 128, 64, 0, 0);\r
361 }\r
362 \r
363 void SCROM_Init(CartInfo *info)\r
364 {\r
365   GenMMC1Init(info, 128, 128, 0, 0);\r
366 }\r
367 \r
368 void SEROM_Init(CartInfo *info)\r
369 {\r
370   GenMMC1Init(info, 32, 64, 0, 0);\r
371 }\r
372 \r
373 void SGROM_Init(CartInfo *info)\r
374 {\r
375   GenMMC1Init(info, 256, 0, 0, 0);\r
376 }\r
377 \r
378 void SKROM_Init(CartInfo *info)\r
379 {\r
380   GenMMC1Init(info, 256, 64, 8, info->battery);\r
381 }\r
382 \r
383 void SLROM_Init(CartInfo *info)\r
384 {\r
385   GenMMC1Init(info, 256, 128, 0, 0);\r
386 }\r
387 \r
388 void SL1ROM_Init(CartInfo *info)\r
389 {\r
390   GenMMC1Init(info, 128, 128, 0, 0);\r
391 }\r
392 \r
393 /* Begin unknown - may be wrong - perhaps they use different MMC1s from the\r
394    similarly functioning boards?\r
395 */\r
396 \r
397 void SL2ROM_Init(CartInfo *info)\r
398 {\r
399   GenMMC1Init(info, 256, 256, 0, 0);\r
400 }\r
401 \r
402 void SFROM_Init(CartInfo *info)\r
403 {\r
404   GenMMC1Init(info, 256, 256, 0, 0);\r
405 }\r
406 \r
407 void SHROM_Init(CartInfo *info)\r
408 {\r
409   GenMMC1Init(info, 256, 256, 0, 0);\r
410 }\r
411 \r
412 /* End unknown  */\r
413 /*              */\r
414 /*              */\r
415 \r
416 void SNROM_Init(CartInfo *info)\r
417 {\r
418   GenMMC1Init(info, 256, 0, 8, info->battery);\r
419 }\r
420 \r
421 void SOROM_Init(CartInfo *info)\r
422 {\r
423   GenMMC1Init(info, 256, 0, 16, info->battery);\r
424 }\r
425 \r
426 \r