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 | |
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 | |