8386ee34e9cbdc4a3dfd8a7b751fef2cde07d76b
[fceu.git] / mbshare / mmc1.c
1 /* FCE Ultra - NES/Famicom Emulator
2  *
3  * Copyright notice for this file:
4  *  Copyright (C) 1998 BERO
5  *  Copyright (C) 2002 Ben Parnell
6  *
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.
11  *
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.
16  *
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
20  */
21
22 #include "mapinc.h"
23
24 #define MMC1_reg mapbyte1
25 #define MMC1_buf mapbyte2[0]
26 #define MMC1_sft mapbyte3[0]
27
28 static int mmc1opts;
29
30
31 uint8 MMC1WRAMsize;     /* For use in iNES.c */
32
33 static DECLFW(MBWRAM)
34 {
35  if(!(MMC1_reg[3]&0x10))
36   Page[A>>11][A]=V;     // WRAM is enabled.
37 }
38
39 static DECLFR(MAWRAM)
40 {
41  if(MMC1_reg[3]&0x10)
42   return X.DB;          // WRAM is disabled
43  return(Page[A>>11][A]);
44 }
45
46 static void MMC1CHR(void)
47 {
48     if(mmc1opts&4)
49     {
50      if(MMC1_reg[0]&0x10)
51       setprg8r(0x10,0x6000,(MMC1_reg[1]>>4)&1);
52      else
53       setprg8r(0x10,0x6000,(MMC1_reg[1]>>3)&1);
54      X6502_Rebase();
55     }
56
57     if(MMC1_reg[0]&0x10)
58     {
59      setchr4(0x0000,MMC1_reg[1]);
60      setchr4(0x1000,MMC1_reg[2]);
61     }
62     else
63      setchr8(MMC1_reg[1]>>1);
64 }
65
66 static void MMC1PRG(void)
67 {
68         uint8 offs;
69
70         offs=MMC1_reg[1]&0x10;
71         switch(MMC1_reg[0]&0xC)
72         {
73           case 0xC: setprg16(0x8000,(MMC1_reg[3]+offs));
74                     setprg16(0xC000,0xF+offs);
75                     break;
76           case 0x8: setprg16(0xC000,(MMC1_reg[3]+offs));
77                     setprg16(0x8000,offs);
78                     break;
79           case 0x0:
80           case 0x4:
81                     setprg16(0x8000,((MMC1_reg[3]&~1)+offs));
82                     setprg16(0xc000,((MMC1_reg[3]&~1)+offs+1));
83                     break;
84         }
85         X6502_Rebase();
86 }
87 static void MMC1MIRROR(void)
88 {
89                 switch(MMC1_reg[0]&3)
90                 {
91                  case 2: setmirror(MI_V);break;
92                  case 3: setmirror(MI_H);break;
93                  case 0: setmirror(MI_0);break;
94                  case 1: setmirror(MI_1);break;
95                 }
96 }
97
98 static uint64 lreset;
99
100 static DECLFW(MMC1_write)
101 {
102         int n=(A>>13)-4;
103         //FCEU_DispMessage("%016x",timestampbase+timestamp);
104         //printf("$%04x:$%02x, $%04x\n",A,V,X.PC);
105         //DumpMem("out",0xe000,0xffff);
106
107         /* The MMC1 is busy so ignore the write. */
108         /* As of version FCE Ultra 0.81, the timestamp is only
109            increased before each instruction is executed(in other words
110            precision isn't that great), but this should still work to
111            deal with 2 writes in a row from a single RMW instruction.
112         */
113         if( (timestampbase+timestamp)<(lreset+2))
114          return;
115         if (V&0x80)
116         {
117          MMC1_reg[0]|=0xC;
118          MMC1_sft=MMC1_buf=0;
119          MMC1PRG();
120          lreset=timestampbase+timestamp;
121          return;
122         }
123
124         MMC1_buf|=(V&1)<<(MMC1_sft++);
125
126   if (MMC1_sft==5) {
127         MMC1_reg[n]=MMC1_buf;
128         MMC1_sft = MMC1_buf=0;
129
130         switch(n){
131         case 0:
132                 MMC1MIRROR();
133                 MMC1CHR();
134                 MMC1PRG();
135                 break;
136         case 1:
137                 MMC1CHR();
138                 MMC1PRG();
139                 break;
140         case 2:
141                 MMC1CHR();
142                 break;
143         case 3:
144                 MMC1PRG();
145                 break;
146         }
147   }
148 }
149
150 static void MMC1_Restore(int version)
151 {
152  MMC1MIRROR();
153  MMC1CHR();
154  MMC1PRG();
155 }
156
157 static void MMC1CMReset(void)
158 {
159         int i;
160
161         for(i=0;i<4;i++)
162          MMC1_reg[i]=0;
163         MMC1_sft = MMC1_buf =0;
164         MMC1_reg[0]=0x1F;
165
166         MMC1_reg[1]=0;
167         MMC1_reg[2]=0;                  // Should this be something other than 0?
168         MMC1_reg[3]=0;
169
170         MMC1MIRROR();
171         MMC1CHR();
172         MMC1PRG();
173 }
174
175 void DetectMMC1WRAMSize(void)
176 {
177         switch(iNESGameCRC32)
178         {
179          default:MMC1WRAMsize=1;break;
180          case 0xc6182024:       /* Romance of the 3 Kingdoms */
181          case 0x2225c20f:       /* Genghis Khan */
182          case 0x4642dda6:       /* Nobunaga's Ambition */
183          case 0x29449ba9:       /* ""   "" (J) */
184          case 0x2b11e0b0:       /* ""   "" (J) */
185                 MMC1WRAMsize=2;
186                 break;
187         }
188 }
189
190 void Mapper1_init(void)
191 {
192         lreset=0;
193         mmc1opts=0;
194         MMC1CMReset();
195         SetWriteHandler(0x8000,0xFFFF,MMC1_write);
196         MapStateRestore=MMC1_Restore;
197         AddExState(&lreset, 8, 1, "LRST");
198
199         if(!VROM_size)
200          SetupCartCHRMapping(0, CHRRAM, 8192, 1);
201
202         if(MMC1WRAMsize==2)
203          mmc1opts|=4;
204
205         SetupCartPRGMapping(0x10,WRAM,MMC1WRAMsize*8192,1);
206         SetReadHandler(0x6000,0x7FFF,MAWRAM);
207         SetWriteHandler(0x6000,0x7FFF,MBWRAM);
208         setprg8r(0x10,0x6000,0);
209 }
210
211 static void GenMMC1Close(void)
212 {
213  UNIFOpenWRAM(UOW_WR,0,0);
214  UNIFWriteWRAM(WRAM+((mmc1opts&4)?8192:0),8192);
215  UNIFCloseWRAM();
216 }
217
218
219 static void GenMMC1Power(void)
220 {
221  lreset=0;
222  if(mmc1opts&1)
223  {
224   FCEU_CheatAddRAM(8,0x6000,WRAM);
225   if(mmc1opts&4)
226    FCEU_dwmemset(WRAM,0,8192)
227   else if(!(mmc1opts&2))
228    FCEU_dwmemset(WRAM,0,8192);
229  }
230  SetWriteHandler(0x8000,0xFFFF,MMC1_write);
231  SetReadHandler(0x8000,0xFFFF,CartBR);
232
233  if(mmc1opts&1)
234  {
235   SetReadHandler(0x6000,0x7FFF,MAWRAM);
236   SetWriteHandler(0x6000,0x7FFF,MBWRAM);
237   setprg8r(0x10,0x6000,0);
238  }
239
240  MMC1CMReset();
241 }
242
243 static void GenMMC1Init(int prg, int chr, int wram, int battery)
244 {
245  mmc1opts=0;
246  PRGmask16[0]&=(prg>>14)-1;
247  CHRmask4[0]&=(chr>>12)-1;
248  CHRmask8[0]&=(chr>>13)-1;
249
250  if(wram)
251  {
252   mmc1opts|=1;
253   if(wram>8) mmc1opts|=4;
254   SetupCartPRGMapping(0x10,WRAM,wram*1024,1);
255   AddExState(WRAM, wram*1024, 0, "WRAM");
256  }
257
258  if(battery && UNIFbattery)
259  {
260   mmc1opts|=2;
261   BoardClose=GenMMC1Close;
262
263   UNIFOpenWRAM(UOW_RD,0,0);
264   UNIFReadWRAM(WRAM+((mmc1opts&4)?8192:0),8192);
265   UNIFCloseWRAM();
266  }
267
268  if(!chr)
269  {
270   CHRmask4[0]=1;
271   SetupCartCHRMapping(0, CHRRAM, 8192, 1);
272   AddExState(CHRRAM, 8192, 0, "CHRR");
273  }
274  AddExState(mapbyte1, 32, 0, "MPBY");
275  BoardPower=GenMMC1Power;
276
277  GameStateRestore=MMC1_Restore;
278  AddExState(&lreset, 8, 1, "LRST");
279 }
280
281 //static void GenMMC1Init(int prg, int chr, int wram, int battery)
282 void SAROM_Init(void)
283 {
284  GenMMC1Init(128, 64, 8, 1);
285 }
286
287 void SBROM_Init(void)
288 {
289  GenMMC1Init(128, 64, 0, 0);
290 }
291
292 void SCROM_Init(void)
293 {
294  GenMMC1Init(128, 128, 0, 0);
295 }
296
297 void SEROM_Init(void)
298 {
299  GenMMC1Init(32, 64, 0, 0);
300 }
301
302 void SGROM_Init(void)
303 {
304  GenMMC1Init(256, 0, 0, 0);
305 }
306
307 void SKROM_Init(void)
308 {
309  GenMMC1Init(256, 64, 8, 1);
310 }
311
312 void SLROM_Init(void)
313 {
314  GenMMC1Init(256, 128, 0, 0);
315 }
316
317 void SL1ROM_Init(void)
318 {
319  GenMMC1Init(128, 128, 0, 0);
320 }
321
322 /* Begin unknown - may be wrong - perhaps they use different MMC1s from the
323    similarly functioning boards?
324 */
325
326 void SL2ROM_Init(void)
327 {
328  GenMMC1Init(256, 256, 0, 0);
329 }
330
331 void SFROM_Init(void)
332 {
333  GenMMC1Init(256, 256, 0, 0);
334 }
335
336 void SHROM_Init(void)
337 {
338  GenMMC1Init(256, 256, 0, 0);
339 }
340
341 /* End unknown  */
342 /*              */
343 /*              */
344
345 void SNROM_Init(void)
346 {
347  GenMMC1Init(256, 0, 8, 1);
348 }
349
350 void SOROM_Init(void)
351 {
352  GenMMC1Init(256, 0, 16, 1);
353 }
354
355