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