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