updated bords/mappers/stuff to 0.98.15, lots of them got broken, asmcore support...
[fceu.git] / boards / mmc5.c
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
25 static void (*sfun)(int P);
26 static void (*psfun)(void);
27
28 void MMC5RunSound(int Count);
29 //void MMC5RunSoundHQ(void);
30
31 static 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
40 static INLINE void MMC5BGVROM_BANK1(uint32 A,uint32 V) {if(CHRptr[0]){V&=CHRmask1[0];MMC5BGVPage[(A)>>10]=&CHRptr[0][(V)<<10]-(A);}}
41
42 static 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);}}
43 static 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
45 static 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);}}
46 static 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
48 static 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];}}
49 static 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
51 static uint8 PRGBanks[4];
52 static uint8 WRAMPage;
53 static uint8 CHRBanksA[8], CHRBanksB[4];
54 static uint8 WRAMMaskEnable[2];
55 static uint8 ABMode;                /* A=0, B=1 */
56
57 static uint8 IRQScanline,IRQEnable;
58 static uint8 CHRMode, NTAMirroring, NTFill, ATFill;
59
60 static uint8 MMC5IRQR;
61 static uint8 MMC5LineCounter;
62 static uint8 mmc5psize, mmc5vsize;
63 static uint8 mul[2];
64
65 static uint8 *WRAM=NULL;
66 static uint8 *MMC5fill=NULL;
67 static uint8 *ExRAM=NULL;
68
69 static uint8 MMC5WRAMsize;
70 static uint8 MMC5WRAMIndex[8];
71
72 static uint8 MMC5ROMWrProtect[4];
73 static uint8 MMC5MemIn[5];
74
75 static void MMC5CHRA(void);
76 static void MMC5CHRB(void);
77
78 typedef 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
88 cartdata 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
114 int 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
126 static 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
141 static 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
172 static 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
203 static 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
216 static 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
289 static 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
364 static DECLFR(MMC5_ReadROMRAM)
365 {
366         if(MMC5MemIn[(A-0x6000)>>13])
367          return Page[A>>11][A];
368         else
369          return X.DB;
370 }
371
372 static 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
380 static DECLFW(MMC5_ExRAMWr)
381 {
382  if(MMC5HackCHRMode!=3)
383   ExRAM[A&0x3ff]=V;
384 }
385
386 static 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
395 static 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
413 void 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
455 void 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
477 void MMC5_StateRestore(int version)
478 {
479  MMC5Synco();
480 }
481
482 typedef 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
494 static MMC5APU MMC5Sound;
495
496
497 static 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
513 static 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
523 static 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
563 static 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
603 static 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
637 void MMC5RunSoundHQ(void)
638 {
639   Do5SQHQ(0);
640   Do5SQHQ(1);
641   Do5PCMHQ();
642 }
643
644 void MMC5HiSync(int32 ts)
645 {
646  int x;
647  for(x=0;x<3;x++) MMC5Sound.BC[x]=ts;
648 }
649 #endif
650
651 void 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
661 void 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
689 void 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
703 void NSFMMC5_Close(void)
704 {
705  FCEU_gfree(ExRAM);
706  ExRAM=0;
707 }
708
709 static 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
743 static 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
767 static 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
809 void 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
821 void ETROM_Init(CartInfo *info)
822 {
823  GenMMC5_Init(info, 16,info->battery);
824 }
825
826 void ELROM_Init(CartInfo *info)
827 {
828  GenMMC5_Init(info,0,0);
829 }
830
831 void EWROM_Init(CartInfo *info)
832 {
833  GenMMC5_Init(info,32,info->battery);
834 }
835
836 void EKROM_Init(CartInfo *info)
837 {
838  GenMMC5_Init(info,8,info->battery);
839 }