updated bords/mappers/stuff to 0.98.15, lots of them got broken, asmcore support...
[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{
c0bf6f9f 41 if(MMC1_reg[3]&0x10)
c62d2810 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);
c0bf6f9f 54 X6502_Rebase();
c62d2810 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
66static 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 }
c0bf6f9f 85 X6502_Rebase();
c62d2810 86}
87static 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
98static uint64 lreset;
99
100static 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
150static void MMC1_Restore(int version)
151{
152 MMC1MIRROR();
153 MMC1CHR();
154 MMC1PRG();
155}
156
157static 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
175void 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
190void Mapper1_init(void)
191{
192 lreset=0;
193 mmc1opts=0;
c0bf6f9f 194 MMC1CMReset();
c62d2810 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
211static void GenMMC1Close(void)
212{
213 UNIFOpenWRAM(UOW_WR,0,0);
214 UNIFWriteWRAM(WRAM+((mmc1opts&4)?8192:0),8192);
215 UNIFCloseWRAM();
216}
217
218
219static 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
243static 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
c0bf6f9f 250 if(wram)
251 {
c62d2810 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)
282void SAROM_Init(void)
283{
c0bf6f9f 284 GenMMC1Init(128, 64, 8, 1);
c62d2810 285}
286
287void SBROM_Init(void)
288{
289 GenMMC1Init(128, 64, 0, 0);
290}
291
c0bf6f9f 292void SCROM_Init(void)
c62d2810 293{
294 GenMMC1Init(128, 128, 0, 0);
295}
296
297void SEROM_Init(void)
298{
299 GenMMC1Init(32, 64, 0, 0);
300}
301
302void SGROM_Init(void)
303{
304 GenMMC1Init(256, 0, 0, 0);
305}
306
307void SKROM_Init(void)
308{
309 GenMMC1Init(256, 64, 8, 1);
310}
311
312void SLROM_Init(void)
313{
314 GenMMC1Init(256, 128, 0, 0);
315}
316
317void 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
326void SL2ROM_Init(void)
327{
328 GenMMC1Init(256, 256, 0, 0);
329}
330
331void SFROM_Init(void)
332{
333 GenMMC1Init(256, 256, 0, 0);
334}
335
336void SHROM_Init(void)
337{
338 GenMMC1Init(256, 256, 0, 0);
339}
340
341/* End unknown */
342/* */
343/* */
344
345void SNROM_Init(void)
346{
347 GenMMC1Init(256, 0, 8, 1);
348}
349
350void SOROM_Init(void)
351{
352 GenMMC1Init(256, 0, 16, 1);
353}
354
355