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