gpfce patch part3
[fceu.git] / mbshare / mmc1.c
CommitLineData
c62d2810 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
28static int mmc1opts;
29
30
31uint8 MMC1WRAMsize; /* For use in iNES.c */
32
33static DECLFW(MBWRAM)
34{
35 if(!(MMC1_reg[3]&0x10))
36 Page[A>>11][A]=V; // WRAM is enabled.
37}
38
39static DECLFR(MAWRAM)
40{
41 if(MMC1_reg[3]&0x10)
42 return X.DB; // WRAM is disabled
43 return(Page[A>>11][A]);
44}
45
46static 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
65static 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}
85static 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
96static uint64 lreset;
97
98static 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
148static void MMC1_Restore(int version)
149{
150 MMC1MIRROR();
151 MMC1CHR();
152 MMC1PRG();
153}
154
155static 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
173void 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
188void 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
209static void GenMMC1Close(void)
210{
211 UNIFOpenWRAM(UOW_WR,0,0);
212 UNIFWriteWRAM(WRAM+((mmc1opts&4)?8192:0),8192);
213 UNIFCloseWRAM();
214}
215
216
217static 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
241static 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)
280void SAROM_Init(void)
281{
282 GenMMC1Init(128, 64, 8, 1);
283}
284
285void SBROM_Init(void)
286{
287 GenMMC1Init(128, 64, 0, 0);
288}
289
290void SCROM_Init(void)
291{
292 GenMMC1Init(128, 128, 0, 0);
293}
294
295void SEROM_Init(void)
296{
297 GenMMC1Init(32, 64, 0, 0);
298}
299
300void SGROM_Init(void)
301{
302 GenMMC1Init(256, 0, 0, 0);
303}
304
305void SKROM_Init(void)
306{
307 GenMMC1Init(256, 64, 8, 1);
308}
309
310void SLROM_Init(void)
311{
312 GenMMC1Init(256, 128, 0, 0);
313}
314
315void 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
324void SL2ROM_Init(void)
325{
326 GenMMC1Init(256, 256, 0, 0);
327}
328
329void SFROM_Init(void)
330{
331 GenMMC1Init(256, 256, 0, 0);
332}
333
334void SHROM_Init(void)
335{
336 GenMMC1Init(256, 256, 0, 0);
337}
338
339/* End unknown */
340/* */
341/* */
342
343void SNROM_Init(void)
344{
345 GenMMC1Init(256, 0, 8, 1);
346}
347
348void SOROM_Init(void)
349{
350 GenMMC1Init(256, 0, 16, 1);
351}
352
353