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 | /* Code for emulating iNES mappers 4, 118,119 */ |
23 | |
24 | #include "mapinc.h" |
25 | |
26 | #define resetmode mapbyte1[0] |
27 | #define MMC3_cmd mapbyte1[1] |
28 | #define A000B mapbyte1[2] |
29 | #define A001B mapbyte1[3] |
30 | #define DRegBuf mapbyte4 |
31 | |
32 | #define PPUCHRBus mapbyte2[0] |
33 | #define TKSMIR mapbyte3 |
34 | #define PIRREGS mapbyte2 |
35 | |
36 | static void (*pwrap)(uint32 A, uint8 V); |
37 | static void (*cwrap)(uint32 A, uint8 V); |
38 | static void (*mwrap)(uint8 V); |
39 | |
40 | static int mmc3opts=0; |
41 | |
42 | static INLINE void FixMMC3PRG(int V); |
43 | static INLINE void FixMMC3CHR(int V); |
44 | |
45 | static int latched; |
46 | |
47 | static DECLFW(MMC3_IRQWrite) |
48 | { |
49 | //printf("$%04x:$%02x, %d\n",A,V,scanline); |
50 | switch(A&0xE001) |
51 | { |
52 | case 0xc000:IRQLatch=V; |
53 | latched=1; |
54 | if(resetmode) |
55 | { |
56 | IRQCount=V; |
57 | latched=0; |
58 | //resetmode=0; |
59 | } |
60 | break; |
61 | case 0xc001:IRQCount=IRQLatch; |
62 | break; |
63 | case 0xE000:IRQa=0; |
64 | X6502_IRQEnd(FCEU_IQEXT); |
65 | resetmode=1; |
66 | break; |
67 | case 0xE001:IRQa=1; |
c0bf6f9f |
68 | if(latched) |
c62d2810 |
69 | IRQCount=IRQLatch; |
70 | break; |
71 | } |
72 | } |
73 | |
74 | static INLINE void FixMMC3PRG(int V) |
75 | { |
76 | if(V&0x40) |
77 | { |
78 | pwrap(0xC000,DRegBuf[6]); |
79 | pwrap(0x8000,~1); |
80 | } |
81 | else |
82 | { |
83 | pwrap(0x8000,DRegBuf[6]); |
84 | pwrap(0xC000,~1); |
85 | } |
86 | pwrap(0xA000,DRegBuf[7]); |
87 | pwrap(0xE000,~0); |
c0bf6f9f |
88 | X6502_Rebase(); |
c62d2810 |
89 | } |
90 | |
91 | static INLINE void FixMMC3CHR(int V) |
92 | { |
93 | int cbase=(V&0x80)<<5; |
94 | cwrap((cbase^0x000),DRegBuf[0]&(~1)); |
95 | cwrap((cbase^0x400),DRegBuf[0]|1); |
96 | cwrap((cbase^0x800),DRegBuf[1]&(~1)); |
97 | cwrap((cbase^0xC00),DRegBuf[1]|1); |
98 | |
99 | cwrap(cbase^0x1000,DRegBuf[2]); |
100 | cwrap(cbase^0x1400,DRegBuf[3]); |
101 | cwrap(cbase^0x1800,DRegBuf[4]); |
102 | cwrap(cbase^0x1c00,DRegBuf[5]); |
103 | } |
104 | |
105 | static void MMC3RegReset(void) |
106 | { |
107 | IRQCount=IRQLatch=IRQa=MMC3_cmd=0; |
108 | |
109 | DRegBuf[0]=0; |
110 | DRegBuf[1]=2; |
111 | DRegBuf[2]=4; |
112 | DRegBuf[3]=5; |
113 | DRegBuf[4]=6; |
114 | DRegBuf[5]=7; |
115 | DRegBuf[6]=0; |
116 | DRegBuf[7]=1; |
117 | |
118 | FixMMC3PRG(0); |
119 | FixMMC3CHR(0); |
120 | } |
121 | |
122 | static DECLFW(Mapper4_write) |
123 | { |
124 | switch(A&0xE001) |
125 | { |
126 | case 0x8000: |
127 | if((V&0x40) != (MMC3_cmd&0x40)) |
128 | FixMMC3PRG(V); |
129 | if((V&0x80) != (MMC3_cmd&0x80)) |
130 | FixMMC3CHR(V); |
131 | MMC3_cmd = V; |
132 | break; |
133 | |
134 | case 0x8001: |
135 | { |
136 | int cbase=(MMC3_cmd&0x80)<<5; |
137 | DRegBuf[MMC3_cmd&0x7]=V; |
138 | switch(MMC3_cmd&0x07) |
139 | { |
140 | case 0: cwrap((cbase^0x000),V&(~1)); |
141 | cwrap((cbase^0x400),V|1); |
142 | break; |
143 | case 1: cwrap((cbase^0x800),V&(~1)); |
144 | cwrap((cbase^0xC00),V|1); |
145 | break; |
146 | case 2: cwrap(cbase^0x1000,V); break; |
147 | case 3: cwrap(cbase^0x1400,V); break; |
148 | case 4: cwrap(cbase^0x1800,V); break; |
149 | case 5: cwrap(cbase^0x1C00,V); break; |
150 | case 6: if (MMC3_cmd&0x40) pwrap(0xC000,V); |
151 | else pwrap(0x8000,V); |
c0bf6f9f |
152 | X6502_Rebase(); |
c62d2810 |
153 | break; |
154 | case 7: pwrap(0xA000,V); |
c0bf6f9f |
155 | X6502_Rebase(); |
c62d2810 |
156 | break; |
157 | } |
158 | } |
159 | break; |
160 | |
161 | case 0xA000: |
162 | if(mwrap) mwrap(V&1); |
163 | break; |
164 | case 0xA001: |
165 | A001B=V; |
166 | break; |
167 | } |
168 | } |
169 | |
170 | static void MMC3_hb(void) |
171 | { |
172 | resetmode=0; |
173 | if(IRQCount>=0) |
174 | { |
175 | IRQCount--; |
176 | if(IRQCount<0) |
177 | { |
178 | //printf("IRQ: %d\n",scanline); |
179 | if(IRQa) |
180 | X6502_IRQBegin(FCEU_IQEXT); |
181 | } |
182 | } |
183 | } |
184 | static int isines; |
185 | |
186 | static void genmmc3restore(int version) |
187 | { |
188 | if(version>=56) |
189 | { |
190 | mwrap(A000B&1); |
191 | FixMMC3PRG(MMC3_cmd); |
192 | FixMMC3CHR(MMC3_cmd); |
193 | } |
194 | else if(isines) |
195 | iNESStateRestore(version); |
196 | } |
197 | |
198 | static void GENCWRAP(uint32 A, uint8 V) |
199 | { |
200 | setchr1(A,V); |
201 | } |
202 | |
203 | static void GENPWRAP(uint32 A, uint8 V) |
204 | { |
205 | setprg8(A,V&0x3F); |
206 | } |
207 | |
208 | static void GENMWRAP(uint8 V) |
209 | { |
210 | A000B=V; |
211 | setmirror(V^1); |
212 | } |
213 | |
214 | static void GENNOMWRAP(uint8 V) |
215 | { |
216 | A000B=V; |
217 | } |
218 | |
c0bf6f9f |
219 | static void genmmc3ii(void (*PW)(uint32 A, uint8 V), |
220 | void (*CW)(uint32 A, uint8 V), |
c62d2810 |
221 | void (*MW)(uint8 V)) |
222 | { |
223 | pwrap=GENPWRAP; |
224 | cwrap=GENCWRAP; |
225 | mwrap=GENMWRAP; |
226 | if(PW) pwrap=PW; |
227 | if(CW) cwrap=CW; |
228 | if(MW) mwrap=MW; |
229 | A000B=(Mirroring&1)^1; // For hard-wired mirroring on some MMC3 games. |
230 | // iNES format needs to die or be extended... |
231 | mmc3opts=0; |
232 | SetWriteHandler(0x8000,0xBFFF,Mapper4_write); |
233 | SetWriteHandler(0xC000,0xFFFF,MMC3_IRQWrite); |
234 | |
235 | GameHBIRQHook=MMC3_hb; |
236 | GameStateRestore=genmmc3restore; |
237 | if(!VROM_size) |
238 | SetupCartCHRMapping(0, CHRRAM, 8192, 1); |
239 | isines=1; |
240 | MMC3RegReset(); |
241 | MapperReset=MMC3RegReset; |
242 | } |
243 | |
244 | void Mapper4_init(void) |
245 | { |
246 | genmmc3ii(0,0,0); |
247 | } |
248 | |
249 | static void M47PW(uint32 A, uint8 V) |
250 | { |
251 | V&=0xF; |
252 | V|=PIRREGS[0]<<4; |
253 | setprg8(A,V); |
254 | } |
255 | |
256 | static void M47CW(uint32 A, uint8 V) |
257 | { |
258 | uint32 NV=V; |
259 | NV&=0x7F; |
260 | NV|=PIRREGS[0]<<7; |
261 | setchr1(A,NV); |
262 | } |
263 | |
264 | static DECLFW(M47Write) |
265 | { |
266 | PIRREGS[0]=V&1; |
267 | FixMMC3PRG(MMC3_cmd); |
c0bf6f9f |
268 | FixMMC3CHR(MMC3_cmd); |
c62d2810 |
269 | } |
270 | |
271 | void Mapper47_init(void) |
272 | { |
273 | genmmc3ii(M47PW,M47CW,0); |
274 | SetWriteHandler(0x6000,0x7FFF,M47Write); |
275 | SetReadHandler(0x6000,0x7FFF,0); |
276 | } |
277 | |
278 | static void M44PW(uint32 A, uint8 V) |
279 | { |
280 | uint32 NV=V; |
281 | if(PIRREGS[0]>=6) NV&=0x1F; |
282 | else NV&=0x0F; |
283 | NV|=PIRREGS[0]<<4; |
284 | setprg8(A,NV); |
285 | } |
286 | static void M44CW(uint32 A, uint8 V) |
287 | { |
288 | uint32 NV=V; |
289 | if(PIRREGS[0]<6) NV&=0x7F; |
290 | NV|=PIRREGS[0]<<7; |
291 | setchr1(A,NV); |
292 | } |
293 | |
294 | static DECLFW(Mapper44_write) |
295 | { |
296 | if(A&1) |
297 | { |
298 | PIRREGS[0]=V&7; |
299 | FixMMC3PRG(MMC3_cmd); |
300 | FixMMC3CHR(MMC3_cmd); |
301 | } |
302 | else |
303 | Mapper4_write(A,V); |
304 | } |
305 | |
306 | void Mapper44_init(void) |
307 | { |
308 | genmmc3ii(M44PW,M44CW,0); |
309 | SetWriteHandler(0xA000,0xBFFF,Mapper44_write); |
310 | } |
311 | |
312 | static void M52PW(uint32 A, uint8 V) |
313 | { |
314 | uint32 NV=V; |
315 | NV&=0x1F^((PIRREGS[0]&8)<<1); |
316 | NV|=((PIRREGS[0]&6)|((PIRREGS[0]>>3)&PIRREGS[0]&1))<<4; |
317 | setprg8(A,NV); |
318 | } |
319 | |
320 | static void M52CW(uint32 A, uint8 V) |
321 | { |
322 | uint32 NV=V; |
323 | NV&=0xFF^((PIRREGS[0]&0x40)<<1); |
324 | NV|=(((PIRREGS[0]>>3)&4)|((PIRREGS[0]>>1)&2)|((PIRREGS[0]>>6)&(PIRREGS[0]>>4)&1))<<7; |
325 | setchr1(A,NV); |
326 | } |
327 | |
328 | static DECLFW(Mapper52_write) |
329 | { |
c0bf6f9f |
330 | if(PIRREGS[1]) |
c62d2810 |
331 | { |
332 | (WRAM-0x6000)[A]=V; |
333 | return; |
334 | } |
335 | PIRREGS[1]=1; |
336 | PIRREGS[0]=V; |
337 | FixMMC3PRG(MMC3_cmd); |
338 | FixMMC3CHR(MMC3_cmd); |
339 | } |
340 | |
341 | static void M52Reset(void) |
342 | { |
343 | PIRREGS[0]=PIRREGS[1]=0; |
c0bf6f9f |
344 | MMC3RegReset(); |
c62d2810 |
345 | } |
346 | |
347 | void Mapper52_init(void) |
348 | { |
349 | genmmc3ii(M52PW,M52CW,0); |
350 | SetWriteHandler(0x6000,0x7FFF,Mapper52_write); |
351 | MapperReset=M52Reset; |
352 | } |
353 | |
354 | static void M45CW(uint32 A, uint8 V) |
355 | { |
356 | uint32 NV=V; |
357 | if(PIRREGS[2]&8) |
358 | NV&=(1<<( (PIRREGS[2]&7)+1 ))-1; |
359 | else |
360 | NV&=0; |
361 | NV|=PIRREGS[0]|((PIRREGS[2]&0x10)<<4); |
362 | setchr1(A,NV); |
363 | } |
364 | |
365 | static void M45PW(uint32 A, uint8 V) |
366 | { |
367 | V&=(PIRREGS[3]&0x3F)^0x3F; |
368 | V|=PIRREGS[1]; |
369 | setprg8(A,V); |
370 | } |
371 | |
372 | static DECLFW(Mapper45_write) |
373 | { |
374 | if(PIRREGS[3]&0x40) return; |
375 | PIRREGS[PIRREGS[4]]=V; |
376 | PIRREGS[4]=(PIRREGS[4]+1)&3; |
377 | FixMMC3PRG(MMC3_cmd); |
378 | FixMMC3CHR(MMC3_cmd); |
379 | } |
380 | |
381 | static void M45Reset(void) |
382 | { |
383 | FCEU_dwmemset(PIRREGS,0,5); |
384 | MMC3RegReset(); |
385 | } |
386 | |
387 | void Mapper45_init(void) |
388 | { |
389 | genmmc3ii(M45PW,M45CW,0); |
390 | SetWriteHandler(0x6000,0x7FFF,Mapper45_write); |
391 | SetReadHandler(0x6000,0x7FFF,0); |
392 | MapperReset=M45Reset; |
393 | } |
394 | static void M49PW(uint32 A, uint8 V) |
395 | { |
396 | if(PIRREGS[0]&1) |
397 | { |
398 | V&=0xF; |
399 | V|=(PIRREGS[0]&0xC0)>>2; |
400 | setprg8(A,V); |
401 | } |
402 | else |
c0bf6f9f |
403 | { |
c62d2810 |
404 | setprg32(0x8000,(PIRREGS[0]>>4)&3); |
c0bf6f9f |
405 | X6502_Rebase(); |
406 | } |
c62d2810 |
407 | } |
408 | |
409 | static void M49CW(uint32 A, uint8 V) |
410 | { |
411 | uint32 NV=V; |
412 | NV&=0x7F; |
413 | NV|=(PIRREGS[0]&0xC0)<<1; |
414 | setchr1(A,NV); |
415 | } |
416 | |
417 | static DECLFW(M49Write) |
418 | { |
419 | //printf("$%04x:$%02x\n",A,V); |
420 | if(A001B&0x80) |
421 | { |
422 | PIRREGS[0]=V; |
423 | FixMMC3PRG(MMC3_cmd); |
424 | FixMMC3CHR(MMC3_cmd); |
425 | } |
426 | } |
427 | |
428 | static void M49Reset(void) |
429 | { |
430 | PIRREGS[0]=0; |
431 | MMC3RegReset(); |
432 | } |
433 | |
434 | void Mapper49_init(void) |
435 | { |
436 | genmmc3ii(M49PW,M49CW,0); |
437 | SetWriteHandler(0x6000,0x7FFF,M49Write); |
438 | SetReadHandler(0x6000,0x7FFF,0); |
439 | MapperReset=M49Reset; |
440 | } |
441 | |
442 | static DECLFW(Mapper250_write) |
443 | { |
444 | Mapper4_write((A&0xE000)|((A&0x400)>>10),A&0xFF); |
445 | } |
446 | |
447 | static DECLFW(M250_IRQWrite) |
448 | { |
449 | MMC3_IRQWrite((A&0xE000)|((A&0x400)>>10),A&0xFF); |
450 | } |
451 | |
452 | void Mapper250_init(void) |
453 | { |
454 | genmmc3ii(0,0,0); |
455 | SetWriteHandler(0x8000,0xBFFF,Mapper250_write); |
456 | SetWriteHandler(0xC000,0xFFFF,M250_IRQWrite); |
457 | } |
458 | |
459 | static void FP_FASTAPASS(1) TKSPPU(uint32 A) |
460 | { |
461 | //static uint8 z; |
462 | //if(A>=0x2000 || type<0) return; |
463 | //if(type<0) return; |
464 | A&=0x1FFF; |
465 | //if(scanline>=140 && scanline<=200) {setmirror(MI_1);return;} |
466 | //if(scanline>=140 && scanline<=200) |
467 | // if(scanline>=190 && scanline<=200) {setmirror(MI_1);return;} |
c0bf6f9f |
468 | // setmirror(MI_1); |
c62d2810 |
469 | //printf("$%04x\n",A); |
470 | |
471 | A>>=10; |
472 | PPUCHRBus=A; |
473 | setmirror(MI_0+TKSMIR[A]); |
474 | } |
475 | |
476 | static void TKSWRAP(uint32 A, uint8 V) |
477 | { |
478 | TKSMIR[A>>10]=V>>7; |
479 | setchr1(A,V&0x7F); |
480 | if(PPUCHRBus==(A>>10)) |
481 | setmirror(MI_0+(V>>7)); |
482 | } |
483 | |
484 | void Mapper118_init(void) |
485 | { |
486 | genmmc3ii(0,TKSWRAP,GENNOMWRAP); |
487 | PPU_hook=TKSPPU; |
488 | } |
489 | |
490 | static void TQWRAP(uint32 A, uint8 V) |
491 | { |
492 | setchr1r((V&0x40)>>2,A,V&0x3F); |
493 | } |
494 | |
495 | void Mapper119_init(void) |
496 | { |
497 | genmmc3ii(0,TQWRAP,0); |
498 | SetupCartCHRMapping(0x10, CHRRAM, 8192, 1); |
499 | } |
500 | |
501 | static int wrams; |
502 | |
503 | static void GenMMC3Close(void) |
504 | { |
505 | UNIFOpenWRAM(UOW_WR,0,1); |
506 | UNIFWriteWRAM(WRAM,wrams); |
507 | UNIFCloseWRAM(); |
508 | } |
509 | |
510 | static DECLFW(MBWRAM) |
511 | { |
512 | (WRAM-0x6000)[A]=V; |
513 | } |
514 | |
515 | static DECLFR(MAWRAM) |
516 | { |
517 | return((WRAM-0x6000)[A]); |
518 | } |
519 | |
520 | static DECLFW(MBWRAMMMC6) |
521 | { |
522 | WRAM[A&0x3ff]=V; |
523 | } |
524 | |
525 | static DECLFR(MAWRAMMMC6) |
526 | { |
527 | return(WRAM[A&0x3ff]); |
528 | } |
529 | |
530 | static void GenMMC3Power(void) |
531 | { |
532 | SetWriteHandler(0x8000,0xBFFF,Mapper4_write); |
533 | SetReadHandler(0x8000,0xFFFF,CartBR); |
534 | SetWriteHandler(0xC000,0xFFFF,MMC3_IRQWrite); |
535 | |
536 | if(mmc3opts&1) |
537 | { |
538 | if(wrams==1024) |
539 | { |
540 | FCEU_CheatAddRAM(1,0x7000,WRAM); |
541 | SetReadHandler(0x7000,0x7FFF,MAWRAMMMC6); |
542 | SetWriteHandler(0x7000,0x7FFF,MBWRAMMMC6); |
543 | } |
544 | else |
545 | { |
546 | FCEU_CheatAddRAM(wrams/1024,0x6000,WRAM); |
547 | SetReadHandler(0x6000,0x6000+wrams-1,MAWRAM); |
548 | SetWriteHandler(0x6000,0x6000+wrams-1,MBWRAM); |
549 | } |
550 | if(!(mmc3opts&2)) |
551 | FCEU_dwmemset(WRAM,0,wrams); |
552 | } |
553 | MMC3RegReset(); |
554 | } |
555 | |
556 | void GenMMC3_Init(int prg, int chr, int wram, int battery) |
557 | { |
558 | pwrap=GENPWRAP; |
559 | cwrap=GENCWRAP; |
560 | mwrap=GENMWRAP; |
561 | |
562 | wrams=wram*1024; |
563 | |
564 | PRGmask8[0]&=(prg>>13)-1; |
565 | CHRmask1[0]&=(chr>>10)-1; |
566 | CHRmask2[0]&=(chr>>11)-1; |
567 | |
568 | if(wram) |
569 | { |
570 | mmc3opts|=1; |
571 | AddExState(WRAM, wram*1024, 0, "WRAM"); |
572 | } |
573 | |
574 | if(battery) |
575 | { |
576 | mmc3opts|=2; |
577 | BoardClose=GenMMC3Close; |
578 | |
579 | UNIFOpenWRAM(UOW_RD,0,1); |
580 | UNIFReadWRAM(WRAM,wram*1024); |
581 | UNIFCloseWRAM(); |
582 | } |
583 | |
584 | if(!chr) |
585 | { |
586 | CHRmask1[0]=7; |
587 | CHRmask2[0]=3; |
588 | SetupCartCHRMapping(0, CHRRAM, 8192, 1); |
589 | AddExState(CHRRAM, 8192, 0, "CHRR"); |
590 | } |
591 | AddExState(mapbyte1, 32, 0, "MPBY"); |
592 | AddExState(&IRQa, 1, 0, "IRQA"); |
593 | AddExState(&IRQCount, 4, 1, "IRQC"); |
594 | AddExState(&IRQLatch, 4, 1, "IQL1"); |
595 | |
596 | BoardPower=GenMMC3Power; |
597 | BoardReset=MMC3RegReset; |
598 | |
599 | GameHBIRQHook=MMC3_hb; |
600 | GameStateRestore=genmmc3restore; |
601 | isines=0; |
602 | } |
603 | |
604 | // void GenMMC3_Init(int prg, int chr, int wram, int battery) |
605 | |
606 | void TFROM_Init(void) |
607 | { |
608 | GenMMC3_Init(512, 64, 0, 0); |
609 | } |
610 | |
611 | void TGROM_Init(void) |
612 | { |
613 | GenMMC3_Init(512, 0, 0, 0); |
614 | } |
615 | |
616 | void TKROM_Init(void) |
617 | { |
618 | GenMMC3_Init(512, 256, 8, 1); |
619 | } |
620 | |
621 | void TLROM_Init(void) |
622 | { |
623 | GenMMC3_Init(512, 256, 0, 0); |
624 | } |
625 | |
626 | void TSROM_Init(void) |
627 | { |
628 | GenMMC3_Init(512, 256, 8, 0); |
629 | } |
630 | |
631 | void TLSROM_Init(void) |
632 | { |
633 | GenMMC3_Init(512, 256, 8, 0); |
634 | cwrap=TKSWRAP; |
635 | mwrap=GENNOMWRAP; |
636 | } |
637 | |
638 | void TKSROM_Init(void) |
639 | { |
640 | GenMMC3_Init(512, 256, 8, 1); |
641 | cwrap=TKSWRAP; |
642 | mwrap=GENNOMWRAP; |
643 | } |
644 | |
645 | void TQROM_Init(void) |
646 | { |
647 | GenMMC3_Init(512, 64, 0, 0); |
648 | cwrap=TQWRAP; |
649 | } |
650 | |
651 | /* MMC6 board */ |
652 | void HKROM_Init(void) |
653 | { |
654 | GenMMC3_Init(512, 512, 1, 1); |
655 | } |