gp2x_test added, cli removed
[fceu.git] / boards / mmc5.c
CommitLineData
d97315ac 1/* FCE Ultra - NES/Famicom Emulator
2 *
3 * Copyright notice for this file:
4 * Copyright (C) 2002 Xodnizel
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21/* None of this code should use any of the iNES bank switching wrappers. */
22
23#include "mapinc.h"
24
25static void (*sfun)(int P);
26static void (*psfun)(void);
27
28void MMC5RunSound(int Count);
29//void MMC5RunSoundHQ(void);
30
31static INLINE void MMC5SPRVROM_BANK1(uint32 A,uint32 V)
32{
33 if(CHRptr[0])
34 {
35 V&=CHRmask1[0];
36 MMC5SPRVPage[(A)>>10]=&CHRptr[0][(V)<<10]-(A);
37 }
38}
39
40static INLINE void MMC5BGVROM_BANK1(uint32 A,uint32 V) {if(CHRptr[0]){V&=CHRmask1[0];MMC5BGVPage[(A)>>10]=&CHRptr[0][(V)<<10]-(A);}}
41
42static INLINE void MMC5SPRVROM_BANK2(uint32 A,uint32 V) {if(CHRptr[0]){V&=CHRmask2[0];MMC5SPRVPage[(A)>>10]=MMC5SPRVPage[((A)>>10)+1]=&CHRptr[0][(V)<<11]-(A);}}
43static INLINE void MMC5BGVROM_BANK2(uint32 A,uint32 V) {if(CHRptr[0]){V&=CHRmask2[0];MMC5BGVPage[(A)>>10]=MMC5BGVPage[((A)>>10)+1]=&CHRptr[0][(V)<<11]-(A);}}
44
45static INLINE void MMC5SPRVROM_BANK4(uint32 A,uint32 V) {if(CHRptr[0]){V&=CHRmask4[0];MMC5SPRVPage[(A)>>10]=MMC5SPRVPage[((A)>>10)+1]= MMC5SPRVPage[((A)>>10)+2]=MMC5SPRVPage[((A)>>10)+3]=&CHRptr[0][(V)<<12]-(A);}}
46static INLINE void MMC5BGVROM_BANK4(uint32 A,uint32 V) {if(CHRptr[0]){V&=CHRmask4[0];MMC5BGVPage[(A)>>10]=MMC5BGVPage[((A)>>10)+1]=MMC5BGVPage[((A)>>10)+2]=MMC5BGVPage[((A)>>10)+3]=&CHRptr[0][(V)<<12]-(A);}}
47
48static INLINE void MMC5SPRVROM_BANK8(uint32 V) {if(CHRptr[0]){V&=CHRmask8[0];MMC5SPRVPage[0]=MMC5SPRVPage[1]=MMC5SPRVPage[2]=MMC5SPRVPage[3]=MMC5SPRVPage[4]=MMC5SPRVPage[5]=MMC5SPRVPage[6]=MMC5SPRVPage[7]=&CHRptr[0][(V)<<13];}}
49static INLINE void MMC5BGVROM_BANK8(uint32 V) {if(CHRptr[0]){V&=CHRmask8[0];MMC5BGVPage[0]=MMC5BGVPage[1]=MMC5BGVPage[2]=MMC5BGVPage[3]=MMC5BGVPage[4]=MMC5BGVPage[5]=MMC5BGVPage[6]=MMC5BGVPage[7]=&CHRptr[0][(V)<<13];}}
50
51static uint8 PRGBanks[4];
52static uint8 WRAMPage;
53static uint8 CHRBanksA[8], CHRBanksB[4];
54static uint8 WRAMMaskEnable[2];
55static uint8 ABMode; /* A=0, B=1 */
56
57static uint8 IRQScanline,IRQEnable;
58static uint8 CHRMode, NTAMirroring, NTFill, ATFill;
59
60static uint8 MMC5IRQR;
61static uint8 MMC5LineCounter;
62static uint8 mmc5psize, mmc5vsize;
63static uint8 mul[2];
64
65static uint8 *WRAM=NULL;
66static uint8 *MMC5fill=NULL;
67static uint8 *ExRAM=NULL;
68
69static uint8 MMC5WRAMsize;
70static uint8 MMC5WRAMIndex[8];
71
72static uint8 MMC5ROMWrProtect[4];
73static uint8 MMC5MemIn[5];
74
75static void MMC5CHRA(void);
76static void MMC5CHRB(void);
77
78typedef struct __cartdata {
79 uint32 crc32;
80 uint8 size;
81} cartdata;
82
83
84// ETROM seems to have 16KB of WRAM, ELROM seems to have 8KB
85// EWROM seems to have 32KB of WRAM
86
87#define MMC5_NOCARTS 14
88cartdata MMC5CartList[MMC5_NOCARTS]=
89{
90 {0x9c18762b,2}, /* L'Empereur */
91 {0x26533405,2},
92 {0x6396b988,2},
93
94 {0xaca15643,2}, /* Uncharted Waters */
95 {0xfe3488d1,2}, /* Dai Koukai Jidai */
96
97 {0x15fe6d0f,2}, /* BKAC */
98 {0x39f2ce4b,2}, /* Suikoden */
99
100 {0x8ce478db,2}, /* Nobunaga's Ambition 2 */
101 {0xeee9a682,2},
102
103 {0x1ced086f,2}, /* Ishin no Arashi */
104
105 {0xf540677b,4}, /* Nobunaga...Bushou Fuuun Roku */
106
107 {0x6f4e4312,4}, /* Aoki Ookami..Genchou */
108
109 {0xf011e490,4}, /* Romance of the 3 Kingdoms 2 */
110 {0x184c2124,4}, /* Sangokushi 2 */
111};
112
113
114int DetectMMC5WRAMSize(uint32 crc32)
115{
116 int x;
117 for(x=0;x<MMC5_NOCARTS;x++)
118 if(crc32==MMC5CartList[x].crc32)
119 {
120 FCEU_printf(" >8KB external WRAM present. Use UNIF if you hack the ROM image.\n");
121 return(MMC5CartList[x].size*8);
122 }
123 return(8);
124}
125
126static void BuildWRAMSizeTable(void)
127{
128 int x;
129 for(x=0;x<8;x++)
130 {
131 switch(MMC5WRAMsize)
132 {
133 case 0: MMC5WRAMIndex[x]=255; break;
134 case 1: MMC5WRAMIndex[x]=(x>3)?255:0; break;
135 case 2: MMC5WRAMIndex[x]=(x&4)>>2; break;
136 case 4: MMC5WRAMIndex[x]=(x>3)?255:(x&3); break;
137 }
138 }
139}
140
141static void MMC5CHRA(void)
142{
143 int x;
144 switch(mmc5vsize&3)
145 {
146 case 0: setchr8(CHRBanksA[7]);
147 MMC5SPRVROM_BANK8(CHRBanksA[7]);
148 break;
149 case 1: setchr4(0x0000,CHRBanksA[3]);
150 setchr4(0x1000,CHRBanksA[7]);
151 MMC5SPRVROM_BANK4(0x0000,CHRBanksA[3]);
152 MMC5SPRVROM_BANK4(0x1000,CHRBanksA[7]);
153 break;
154 case 2: setchr2(0x0000,CHRBanksA[1]);
155 setchr2(0x0800,CHRBanksA[3]);
156 setchr2(0x1000,CHRBanksA[5]);
157 setchr2(0x1800,CHRBanksA[7]);
158 MMC5SPRVROM_BANK2(0x0000,CHRBanksA[1]);
159 MMC5SPRVROM_BANK2(0x0800,CHRBanksA[3]);
160 MMC5SPRVROM_BANK2(0x1000,CHRBanksA[5]);
161 MMC5SPRVROM_BANK2(0x1800,CHRBanksA[7]);
162 break;
163 case 3: for(x=0;x<8;x++)
164 {
165 setchr1(x<<10,CHRBanksA[x]);
166 MMC5SPRVROM_BANK1(x<<10,CHRBanksA[x]);
167 }
168 break;
169 }
170}
171
172static void MMC5CHRB(void)
173{
174 int x;
175 switch(mmc5vsize&3)
176 {
177 case 0: setchr8(CHRBanksB[3]);
178 MMC5BGVROM_BANK8(CHRBanksB[3]);
179 break;
180 case 1: setchr4(0x0000,CHRBanksB[3]);
181 setchr4(0x1000,CHRBanksB[3]);
182 MMC5BGVROM_BANK4(0x0000,CHRBanksB[3]);
183 MMC5BGVROM_BANK4(0x1000,CHRBanksB[3]);
184 break;
185 case 2: setchr2(0x0000,CHRBanksB[1]);
186 setchr2(0x0800,CHRBanksB[3]);
187 setchr2(0x1000,CHRBanksB[1]);
188 setchr2(0x1800,CHRBanksB[3]);
189 MMC5BGVROM_BANK2(0x0000,CHRBanksB[1]);
190 MMC5BGVROM_BANK2(0x0800,CHRBanksB[3]);
191 MMC5BGVROM_BANK2(0x1000,CHRBanksB[1]);
192 MMC5BGVROM_BANK2(0x1800,CHRBanksB[3]);
193 break;
194 case 3: for(x=0;x<8;x++)
195 {
196 setchr1(x<<10,CHRBanksB[x&3]);
197 MMC5BGVROM_BANK1(x<<10,CHRBanksB[x&3]);
198 }
199 break;
200 }
201}
202
203static void FASTAPASS(2) MMC5WRAM(uint32 A, uint32 V)
204{
205 //printf("%02x\n",V);
206 V=MMC5WRAMIndex[V&7];
207 if(V!=255)
208 {
209 setprg8r(0x10,A,V);
210 MMC5MemIn[(A-0x6000)>>13]=1;
211 }
212 else
213 MMC5MemIn[(A-0x6000)>>13]=0;
214}
215
216static void MMC5PRG(void)
217{
218 int x;
219 switch(mmc5psize&3)
220 {
221 case 0: MMC5ROMWrProtect[0]=MMC5ROMWrProtect[1]=
222 MMC5ROMWrProtect[2]=MMC5ROMWrProtect[3]=1;
223 setprg32(0x8000,((PRGBanks[1]&0x7F)>>2));
224 for(x=0;x<4;x++)
225 MMC5MemIn[1+x]=1;
226 break;
227 case 1: if(PRGBanks[1]&0x80)
228 {
229 MMC5ROMWrProtect[0]=MMC5ROMWrProtect[1]=1;
230 setprg16(0x8000,(PRGBanks[1]>>1));
231 MMC5MemIn[1]=MMC5MemIn[2]=1;
232 }
233 else
234 {
235 MMC5ROMWrProtect[0]=MMC5ROMWrProtect[1]=0;
236 MMC5WRAM(0x8000,PRGBanks[1]&7&0xFE);
237 MMC5WRAM(0xA000,(PRGBanks[1]&7&0xFE)+1);
238 }
239 MMC5MemIn[3]=MMC5MemIn[4]=1;
240 MMC5ROMWrProtect[2]=MMC5ROMWrProtect[3]=1;
241 setprg16(0xC000,(PRGBanks[3]&0x7F)>>1);
242 break;
243 case 2: if(PRGBanks[1]&0x80)
244 {
245 MMC5MemIn[1]=MMC5MemIn[2]=1;
246 MMC5ROMWrProtect[0]=MMC5ROMWrProtect[1]=1;
247 setprg16(0x8000,(PRGBanks[1]&0x7F)>>1);
248 }
249 else
250 {
251 MMC5ROMWrProtect[0]=MMC5ROMWrProtect[1]=0;
252 MMC5WRAM(0x8000,PRGBanks[1]&7&0xFE);
253 MMC5WRAM(0xA000,(PRGBanks[1]&7&0xFE)+1);
254 }
255 if(PRGBanks[2]&0x80)
256 {
257 MMC5ROMWrProtect[2]=1;
258 MMC5MemIn[3]=1;
259 setprg8(0xC000,PRGBanks[2]&0x7F);
260 }
261 else
262 {
263 MMC5ROMWrProtect[2]=0;
264 MMC5WRAM(0xC000,PRGBanks[2]&7);
265 }
266 MMC5MemIn[4]=1;
267 MMC5ROMWrProtect[3]=1;
268 setprg8(0xE000,PRGBanks[3]&0x7F);
269 break;
270 case 3: for(x=0;x<3;x++)
271 if(PRGBanks[x]&0x80)
272 {
273 MMC5ROMWrProtect[x]=1;
274 setprg8(0x8000+(x<<13),PRGBanks[x]&0x7F);
275 MMC5MemIn[1+x]=1;
276 }
277 else
278 {
279 MMC5ROMWrProtect[x]=0;
280 MMC5WRAM(0x8000+(x<<13),PRGBanks[x]&7);
281 }
282 MMC5MemIn[4]=1;
283 MMC5ROMWrProtect[3]=1;
284 setprg8(0xE000,PRGBanks[3]&0x7F);
285 break;
286 }
287}
288
289static DECLFW(Mapper5_write)
290{
291 if(A>=0x5120&&A<=0x5127)
292 {
293 ABMode = 0;
294 CHRBanksA[A&7]=V;
295 MMC5CHRA();
296 }
297 else switch(A)
298 {
299 case 0x5105: {
300 int x;
301 for(x=0;x<4;x++)
302 {
303 switch((V>>(x<<1))&3)
304 {
305 case 0:PPUNTARAM|=1<<x;vnapage[x]=NTARAM;break;
306 case 1:PPUNTARAM|=1<<x;vnapage[x]=NTARAM+0x400;break;
307 case 2:PPUNTARAM|=1<<x;vnapage[x]=ExRAM;break;
308 case 3:PPUNTARAM&=~(1<<x);vnapage[x]=MMC5fill;break;
309 }
310 }
311 }
312 NTAMirroring=V;
313 break;
314 case 0x5113: WRAMPage=V;MMC5WRAM(0x6000,V&7);break;
315 case 0x5100: mmc5psize=V;MMC5PRG();break;
316 case 0x5101: mmc5vsize=V;
317 if(!ABMode)
318 { MMC5CHRB();MMC5CHRA();}
319 else
320 { MMC5CHRA();MMC5CHRB();}
321 break;
322 case 0x5114:
323 case 0x5115:
324 case 0x5116:
325 case 0x5117: PRGBanks[A&3]=V;MMC5PRG();break;
326 case 0x5128:
327 case 0x5129:
328 case 0x512a:
329 case 0x512b: ABMode=1;
330 CHRBanksB[A&3]=V;
331 MMC5CHRB();
332 break;
333 case 0x5102: WRAMMaskEnable[0]=V;break;
334 case 0x5103: WRAMMaskEnable[1]=V;break;
335 case 0x5104: CHRMode=V;MMC5HackCHRMode=V&3;break;
336 case 0x5106: if(V!=NTFill)
337 {
338 uint32 t;
339 t=V|(V<<8)|(V<<16)|(V<<24);
340 FCEU_dwmemset(MMC5fill,t,0x3c0);
341 }
342 NTFill=V;
343 break;
344 case 0x5107: if(V!=ATFill)
345 {
346 unsigned char moop;
347 uint32 t;
348 moop=V|(V<<2)|(V<<4)|(V<<6);
349 t=moop|(moop<<8)|(moop<<16)|(moop<<24);
350 FCEU_dwmemset(MMC5fill+0x3c0,t,0x40);
351 }
352 ATFill=V;
353 break;
354 case 0x5200: MMC5HackSPMode=V;break;
355 case 0x5201: MMC5HackSPScroll=(V>>3)&0x1F;break;
356 case 0x5202: MMC5HackSPPage=V&0x3F;break;
357 case 0x5203: X6502_IRQEnd(FCEU_IQEXT);IRQScanline=V;break;
358 case 0x5204: X6502_IRQEnd(FCEU_IQEXT);IRQEnable=V&0x80;break;
359 case 0x5205: mul[0]=V;break;
360 case 0x5206: mul[1]=V;break;
361 }
362}
363
364static DECLFR(MMC5_ReadROMRAM)
365{
366 if(MMC5MemIn[(A-0x6000)>>13])
367 return Page[A>>11][A];
368 else
369 return X.DB;
370}
371
372static DECLFW(MMC5_WriteROMRAM)
373{
374 if(A>=0x8000)
375 if(MMC5ROMWrProtect[(A-0x8000)>>13]) return;
376 if(MMC5MemIn[(A-0x6000)>>13])
377 if(((WRAMMaskEnable[0]&3)|((WRAMMaskEnable[1]&3)<<2)) == 6) Page[A>>11][A]=V;
378}
379
380static DECLFW(MMC5_ExRAMWr)
381{
382 if(MMC5HackCHRMode!=3)
383 ExRAM[A&0x3ff]=V;
384}
385
386static DECLFR(MMC5_ExRAMRd)
387{
388 /* Not sure if this is correct, so I'll comment it out for now. */
389 //if(MMC5HackCHRMode>=2)
390 return ExRAM[A&0x3ff];
391 //else
392 // return(X.DB);
393}
394
395static DECLFR(MMC5_read)
396{
397 switch(A)
398 {
399 case 0x5204: X6502_IRQEnd(FCEU_IQEXT);
400 {
401 uint8 x;
402 x=MMC5IRQR;
403 if(!fceuindbg)
404 MMC5IRQR&=0x40;
405 return x;
406 }
407 case 0x5205: return (mul[0]*mul[1]);
408 case 0x5206: return ((mul[0]*mul[1])>>8);
409 }
410 return(X.DB);
411}
412
413void MMC5Synco(void)
414{
415 int x;
416
417 MMC5PRG();
418 for(x=0;x<4;x++)
419 {
420 switch((NTAMirroring>>(x<<1))&3)
421 {
422 case 0:PPUNTARAM|=1<<x;vnapage[x]=NTARAM;break;
423 case 1:PPUNTARAM|=1<<x;vnapage[x]=NTARAM+0x400;break;
424 case 2:PPUNTARAM|=1<<x;vnapage[x]=ExRAM;break;
425 case 3:PPUNTARAM&=~(1<<x);vnapage[x]=MMC5fill;break;
426 }
427 }
428 MMC5WRAM(0x6000,WRAMPage&7);
429 if(!ABMode)
430 {
431 MMC5CHRB();
432 MMC5CHRA();
433 }
434 else
435 {
436 MMC5CHRA();
437 MMC5CHRB();
438 }
439 {
440 uint32 t;
441 t=NTFill|(NTFill<<8)|(NTFill<<16)|(NTFill<<24);
442 FCEU_dwmemset(MMC5fill,t,0x3c0);
443 }
444 {
445 unsigned char moop;
446 uint32 t;
447 moop=ATFill|(ATFill<<2)|(ATFill<<4)|(ATFill<<6);
448 t=moop|(moop<<8)|(moop<<16)|(moop<<24);
449 FCEU_dwmemset(MMC5fill+0x3c0,t,0x40);
450 }
451 X6502_IRQEnd(FCEU_IQEXT);
452 MMC5HackCHRMode=CHRMode&3;
453}
454
455void MMC5_hb(int scanline)
456{
457 if(scanline==240)
458 {
459 MMC5LineCounter=0;
460 MMC5IRQR=0x40;
461 return;
462 }
463 if(MMC5LineCounter<240)
464 {
465 if(MMC5LineCounter==IRQScanline)
466 {
467 MMC5IRQR|=0x80;
468 if(IRQEnable&0x80)
469 X6502_IRQBegin(FCEU_IQEXT);
470 }
471 MMC5LineCounter++;
472 }
473 if(MMC5LineCounter==240)
474 MMC5IRQR=0;
475}
476
477void MMC5_StateRestore(int version)
478{
479 MMC5Synco();
480}
481
482typedef struct {
483 uint16 wl[2];
484 uint8 env[2];
485 uint8 enable;
486 uint8 running;
487 uint8 raw;
488 uint8 rawcontrol;
489 int32 dcount[2];
490 int32 BC[3];
491 int32 vcount[2];
492} MMC5APU;
493
494static MMC5APU MMC5Sound;
495
496
497static void Do5PCM()
498{
499 int32 V;
500 int32 start,end;
501
502 start=MMC5Sound.BC[2];
503 end=(SOUNDTS<<16)/soundtsinc;
504 if(end<=start) return;
505 MMC5Sound.BC[2]=end;
506
507 if(!(MMC5Sound.rawcontrol&0x40) && MMC5Sound.raw)
508 for(V=start;V<end;V++)
509 Wave[V>>4]+=MMC5Sound.raw<<1;
510}
511
512#if 0
513static void Do5PCMHQ()
514{
515 int32 V;
516 if(!(MMC5Sound.rawcontrol&0x40) && MMC5Sound.raw)
517 for(V=MMC5Sound.BC[2];V<SOUNDTS;V++)
518 WaveHi[V]+=MMC5Sound.raw<<5;
519 MMC5Sound.BC[2]=SOUNDTS;
520}
521#endif
522
523static DECLFW(Mapper5_SW)
524{
525 A&=0x1F;
526
527 GameExpSound.Fill=MMC5RunSound;
528 GameExpSound.HiFill=0;//MMC5RunSoundHQ;
529
530 switch(A)
531 {
532 case 0x10:if(psfun) psfun();MMC5Sound.rawcontrol=V;break;
533 case 0x11:if(psfun) psfun();MMC5Sound.raw=V;break;
534
535 case 0x0:
536 case 0x4://printf("%04x:$%02x\n",A,V&0x30);
537 if(sfun) sfun(A>>2);
538 MMC5Sound.env[A>>2]=V;
539 break;
540 case 0x2:
541 case 0x6: if(sfun) sfun(A>>2);
542 MMC5Sound.wl[A>>2]&=~0x00FF;
543 MMC5Sound.wl[A>>2]|=V&0xFF;
544 break;
545 case 0x3:
546 case 0x7://printf("%04x:$%02x\n",A,V>>3);
547 MMC5Sound.wl[A>>2]&=~0x0700;
548 MMC5Sound.wl[A>>2]|=(V&0x07)<<8;
549 MMC5Sound.running|=1<<(A>>2);
550 break;
551 case 0x15:if(sfun)
552 {
553 sfun(0);
554 sfun(1);
555 }
556 MMC5Sound.running&=V;
557 MMC5Sound.enable=V;
558 //printf("%02x\n",V);
559 break;
560 }
561}
562
563static void Do5SQ(int P)
564{
565 static int tal[4]={1,2,4,6};
566 int32 V,amp,rthresh,wl;
567 int32 start,end;
568
569 start=MMC5Sound.BC[P];
570 end=(SOUNDTS<<16)/soundtsinc;
571 if(end<=start) return;
572 MMC5Sound.BC[P]=end;
573
574 wl=MMC5Sound.wl[P]+1;
575 amp=(MMC5Sound.env[P]&0xF)<<4;
576 rthresh=tal[(MMC5Sound.env[P]&0xC0)>>6];
577
578 if(wl>=8 && (MMC5Sound.running&(P+1)))
579 {
580 int dc,vc;
581
582 wl<<=18;
583 dc=MMC5Sound.dcount[P];
584 vc=MMC5Sound.vcount[P];
585
586 for(V=start;V<end;V++)
587 {
588 if(dc<rthresh)
589 Wave[V>>4]+=amp;
590 vc-=nesincsize;
591 while(vc<=0)
592 {
593 vc+=wl;
594 dc=(dc+1)&7;
595 }
596 }
597 MMC5Sound.dcount[P]=dc;
598 MMC5Sound.vcount[P]=vc;
599 }
600}
601
602#if 0
603static void Do5SQHQ(int P)
604{
605 static int tal[4]={1,2,4,6};
606 int32 V,amp,rthresh,wl;
607
608 wl=MMC5Sound.wl[P]+1;
609 amp=((MMC5Sound.env[P]&0xF)<<8);
610 rthresh=tal[(MMC5Sound.env[P]&0xC0)>>6];
611
612 if(wl>=8 && (MMC5Sound.running&(P+1)))
613 {
614 int dc,vc;
615
616 wl<<=1;
617
618 dc=MMC5Sound.dcount[P];
619 vc=MMC5Sound.vcount[P];
620 for(V=MMC5Sound.BC[P];V<SOUNDTS;V++)
621 {
622 if(dc<rthresh)
623 WaveHi[V]+=amp;
624 vc--;
625 if(vc<=0) /* Less than zero when first started. */
626 {
627 vc=wl;
628 dc=(dc+1)&7;
629 }
630 }
631 MMC5Sound.dcount[P]=dc;
632 MMC5Sound.vcount[P]=vc;
633 }
634 MMC5Sound.BC[P]=SOUNDTS;
635}
636
637void MMC5RunSoundHQ(void)
638{
639 Do5SQHQ(0);
640 Do5SQHQ(1);
641 Do5PCMHQ();
642}
643
644void MMC5HiSync(int32 ts)
645{
646 int x;
647 for(x=0;x<3;x++) MMC5Sound.BC[x]=ts;
648}
649#endif
650
651void MMC5RunSound(int Count)
652{
653 int x;
654 Do5SQ(0);
655 Do5SQ(1);
656 Do5PCM();
657 for(x=0;x<3;x++)
658 MMC5Sound.BC[x]=Count;
659}
660
661void Mapper5_ESI(void)
662{
663 GameExpSound.RChange=Mapper5_ESI;
664 if(FSettings.SndRate)
665 {
666#if 0
667 if(FSettings.soundq>=1)
668 {
669 sfun=Do5SQHQ;
670 psfun=Do5PCMHQ;
671 }
672 else
673#endif
674 {
675 sfun=Do5SQ;
676 psfun=Do5PCM;
677 }
678 }
679 else
680 {
681 sfun=0;
682 psfun=0;
683 }
684 memset(MMC5Sound.BC,0,sizeof(MMC5Sound.BC));
685 memset(MMC5Sound.vcount,0,sizeof(MMC5Sound.vcount));
686 GameExpSound.HiSync=0;//MMC5HiSync;
687}
688
689void NSFMMC5_Init(void)
690{
691 memset(&MMC5Sound,0,sizeof(MMC5Sound));
692 mul[0]=mul[1]=0;
693 ExRAM=(uint8*)FCEU_gmalloc(1024);
694 Mapper5_ESI();
695 SetWriteHandler(0x5c00,0x5fef,MMC5_ExRAMWr);
696 SetReadHandler(0x5c00,0x5fef,MMC5_ExRAMRd);
697 MMC5HackCHRMode=2;
698 SetWriteHandler(0x5000,0x5015,Mapper5_SW);
699 SetWriteHandler(0x5205,0x5206,Mapper5_write);
700 SetReadHandler(0x5205,0x5206,MMC5_read);
701}
702
703void NSFMMC5_Close(void)
704{
705 FCEU_gfree(ExRAM);
706 ExRAM=0;
707}
708
709static void GenMMC5Reset(void)
710{
711 int x;
712
713 for(x=0;x<4;x++) PRGBanks[x]=~0;
714 for(x=0;x<8;x++) CHRBanksA[x]=~0;
715 for(x=0;x<4;x++) CHRBanksB[x]=~0;
716 WRAMMaskEnable[0]=WRAMMaskEnable[1]=~0;
717
718 mmc5psize=mmc5vsize=3;
719 CHRMode=0;
720
721 NTAMirroring=NTFill=ATFill=0xFF;
722
723 MMC5Synco();
724
725 SetWriteHandler(0x4020,0x5bff,Mapper5_write);
726 SetReadHandler(0x4020,0x5bff,MMC5_read);
727
728 SetWriteHandler(0x5c00,0x5fff,MMC5_ExRAMWr);
729 SetReadHandler(0x5c00,0x5fff,MMC5_ExRAMRd);
730
731 SetWriteHandler(0x6000,0xFFFF,MMC5_WriteROMRAM);
732 SetReadHandler(0x6000,0xFFFF,MMC5_ReadROMRAM);
733
734 SetWriteHandler(0x5000,0x5015,Mapper5_SW);
735 SetWriteHandler(0x5205,0x5206,Mapper5_write);
736 SetReadHandler(0x5205,0x5206,MMC5_read);
737
738 //GameHBIRQHook=MMC5_hb;
739 FCEU_CheatAddRAM(8,0x6000,WRAM);
740 FCEU_CheatAddRAM(1,0x5c00,ExRAM);
741}
742
743static SFORMAT MMC5_StateRegs[]={
744 { PRGBanks, 4, "PRGB"},
745 { CHRBanksA, 8, "CHRA"},
746 { CHRBanksB, 4, "CHRB"},
747 { &WRAMPage, 1, "WRMP"},
748 { WRAMMaskEnable, 2, "WRME"},
749 { &ABMode, 1, "ABMD"},
750 { &IRQScanline, 1, "IRQS"},
751 { &IRQEnable, 1, "IRQE"},
752 { &CHRMode, 1, "CHRM"},
753 { &NTAMirroring, 1, "NTAM"},
754 { &NTFill, 1, "NTFL"},
755 { &ATFill, 1, "ATFL"},
756
757 { &MMC5Sound.wl[0], 2|FCEUSTATE_RLSB, "SDW0"},
758 { &MMC5Sound.wl[1], 2|FCEUSTATE_RLSB, "SDW1"},
759 { MMC5Sound.env, 2, "SDEV"},
760 { &MMC5Sound.enable, 1, "SDEN"},
761 { &MMC5Sound.running, 1, "SDRU"},
762 { &MMC5Sound.raw, 1, "SDRW"},
763 { &MMC5Sound.rawcontrol, 1, "SDRC"},
764 {0}
765};
766
767static void GenMMC5_Init(CartInfo *info, int wsize, int battery)
768{
769 if(wsize)
770 {
771 WRAM=(uint8*)FCEU_gmalloc(wsize*1024);
772 SetupCartPRGMapping(0x10,WRAM,wsize*1024,1);
773 AddExState(WRAM, wsize*1024, 0, "WRAM");
774 }
775
776 MMC5fill=(uint8*)FCEU_gmalloc(1024);
777 ExRAM=(uint8*)FCEU_gmalloc(1024);
778
779 AddExState(MMC5_StateRegs, ~0, 0, 0);
780 AddExState(WRAM, wsize*1024, 0, "WRAM");
781 AddExState(ExRAM, 1024, 0, "ERAM");
782 AddExState(&MMC5HackSPMode, 1, 0, "SPLM");
783 AddExState(&MMC5HackSPScroll, 1, 0, "SPLS");
784 AddExState(&MMC5HackSPPage, 1, 0, "SPLP");
785
786 MMC5WRAMsize=wsize/8;
787 BuildWRAMSizeTable();
788 GameStateRestore=MMC5_StateRestore;
789 info->Power=GenMMC5Reset;
790
791 if(battery)
792 {
793 info->SaveGame[0]=WRAM;
794 if(wsize<=16)
795 info->SaveGameLen[0]=8192;
796 else
797 info->SaveGameLen[0]=32768;
798 }
799
800 MMC5HackVROMMask=CHRmask4[0];
801 MMC5HackExNTARAMPtr=ExRAM;
802 MMC5Hack=1;
803 MMC5HackVROMPTR=CHRptr[0];
804 MMC5HackCHRMode=0;
805 MMC5HackSPMode=MMC5HackSPScroll=MMC5HackSPPage=0;
806 Mapper5_ESI();
807}
808
809void Mapper5_Init(CartInfo *info)
810{
811 GenMMC5_Init(info, DetectMMC5WRAMSize(info->CRC32), info->battery);
812}
813
814// ELROM seems to have 0KB of WRAM
815// EKROM seems to have 8KB of WRAM
816// ETROM seems to have 16KB of WRAM
817// EWROM seems to have 32KB of WRAM
818
819// ETROM and EWROM are battery-backed, EKROM isn't.
820
821void ETROM_Init(CartInfo *info)
822{
823 GenMMC5_Init(info, 16,info->battery);
824}
825
826void ELROM_Init(CartInfo *info)
827{
828 GenMMC5_Init(info,0,0);
829}
830
831void EWROM_Init(CartInfo *info)
832{
833 GenMMC5_Init(info,32,info->battery);
834}
835
836void EKROM_Init(CartInfo *info)
837{
838 GenMMC5_Init(info,8,info->battery);
839}