initial fce ultra 0.81 import
[fceu.git] / mbshare / mmc5.c
1 /* FCE Ultra - NES/Famicom Emulator
2  *
3  * Copyright notice for this file:
4  *  Copyright (C) 2002 Ben Parnell
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 void MMC5Sound(int Count);
26 void Do5SQ(int P);
27
28 static INLINE void MMC5SPRVROM_BANK1(uint32 A,uint32 V) 
29 {
30  if(CHRptr[0])
31  {
32   V&=CHRmask1[0];
33   MMC5SPRVPage[(A)>>10]=&CHRptr[0][(V)<<10]-(A);
34  }
35 }
36
37 static INLINE void MMC5BGVROM_BANK1(uint32 A,uint32 V) {if(CHRptr[0]){V&=CHRmask1[0];MMC5BGVPage[(A)>>10]=&CHRptr[0][(V)<<10]-(A);}}
38
39 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);}}
40 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);}}
41
42 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);}}
43 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);}}
44
45 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];}}
46 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];}}
47
48 static int32 inc;
49 uint8 MMC5fill[0x400];
50
51 #define MMC5IRQR        mapbyte3[4]
52 #define MMC5LineCounter mapbyte3[5]
53 #define mmc5psize mapbyte1[0]
54 #define mmc5vsize mapbyte1[1]
55
56 uint8 MMC5WRAMsize;
57 uint8 MMC5WRAMIndex[8];
58
59 uint8 MMC5ROMWrProtect[4];
60 uint8 MMC5MemIn[5];
61
62 static void MMC5CHRA(void);
63 static void MMC5CHRB(void);
64
65 typedef struct __cartdata {
66         unsigned long crc32;
67         unsigned char size;
68 } cartdata;
69
70
71 // ETROM seems to have 16KB of WRAM, ELROM seems to have 8KB
72 // EWROM seems to have 32KB of WRAM
73
74 #define MMC5_NOCARTS 14
75 cartdata MMC5CartList[MMC5_NOCARTS]=
76 {
77  {0x9c18762b,2},         /* L'Empereur */
78  {0x26533405,2},
79  {0x6396b988,2},
80
81  {0xaca15643,2},        /* Uncharted Waters */
82  {0xfe3488d1,2},        /* Dai Koukai Jidai */
83
84  {0x15fe6d0f,2},        /* BKAC             */
85  {0x39f2ce4b,2},        /* Suikoden              */
86
87  {0x8ce478db,2},        /* Nobunaga's Ambition 2 */
88  {0xeee9a682,2},
89
90  {0x1ced086f,2},        /* Ishin no Arashi */
91
92  {0xf540677b,4},        /* Nobunaga...Bushou Fuuun Roku */
93
94  {0x6f4e4312,4},        /* Aoki Ookami..Genchou */
95
96  {0xf011e490,4},        /* Romance of the 3 Kingdoms 2 */
97  {0x184c2124,4},        /* Sangokushi 2 */
98 };
99
100
101 // Called by iNESLoad()
102 void DetectMMC5WRAMSize(void)
103 {
104  int x;
105
106  MMC5WRAMsize=1;
107
108  for(x=0;x<MMC5_NOCARTS;x++)
109   if(iNESGameCRC32==MMC5CartList[x].crc32)
110    {
111    MMC5WRAMsize=MMC5CartList[x].size;
112    break;
113    }
114 }
115
116 static void BuildWRAMSizeTable(void)
117 {
118  int x;
119
120  for(x=0;x<8;x++)
121  {
122   switch(MMC5WRAMsize)
123   {
124     default:
125     case 1:MMC5WRAMIndex[x]=(x>3)?255:0;break;
126     case 2:MMC5WRAMIndex[x]=(x&4)>>2;break;
127     case 4:MMC5WRAMIndex[x]=(x>3)?255:(x&3);break;
128   }
129  }
130 }
131
132 static void MMC5CHRA(void)
133 {
134         int x;
135         switch(mapbyte1[1]&3)
136         {
137          case 0:MMC5SPRVROM_BANK8(mapbyte2[7]);
138                 setchr8(mapbyte2[7]);
139                 break;
140          case 1:MMC5SPRVROM_BANK4(0x0000,mapbyte2[3]);
141                 MMC5SPRVROM_BANK4(0x1000,mapbyte2[7]);
142                 setchr4(0x0000,mapbyte2[3]);
143                 setchr4(0x1000,mapbyte2[7]);
144                 break;
145          case 2:MMC5SPRVROM_BANK2(0x0000,mapbyte2[1]);
146                 MMC5SPRVROM_BANK2(0x0800,mapbyte2[3]);
147                 MMC5SPRVROM_BANK2(0x1000,mapbyte2[5]);
148                 MMC5SPRVROM_BANK2(0x1800,mapbyte2[7]);
149                 setchr2(0x0000,mapbyte2[1]);
150                 setchr2(0x0800,mapbyte2[3]);
151                 setchr2(0x1000,mapbyte2[5]);
152                 setchr2(0x1800,mapbyte2[7]);
153                 break;
154          case 3:
155                 for(x=0;x<8;x++)
156                 {
157                  setchr1(x<<10,mapbyte2[x]);
158                  MMC5SPRVROM_BANK1(x<<10,mapbyte2[x]);
159                 }
160                 break;
161  }
162 }
163
164 static void MMC5CHRB(void)
165 {
166 int x;
167 switch(mapbyte1[1]&3)
168  {
169  case 0:MMC5BGVROM_BANK8(mapbyte3[3]);
170         setchr8(mapbyte3[3]);
171         break;
172  case 1:
173         MMC5BGVROM_BANK4(0x0000,mapbyte3[3]);
174         MMC5BGVROM_BANK4(0x1000,mapbyte3[3]);
175         setchr4(0x0000,mapbyte3[3]);
176         setchr4(0x1000,mapbyte3[3]);
177         break;
178  case 2:MMC5BGVROM_BANK2(0x0000,mapbyte3[1]);
179         MMC5BGVROM_BANK2(0x0800,mapbyte3[3]);
180         MMC5BGVROM_BANK2(0x1000,mapbyte3[1]);
181         MMC5BGVROM_BANK2(0x1800,mapbyte3[3]);
182         setchr2(0x0000,mapbyte3[1]);
183         setchr2(0x0800,mapbyte3[3]);
184         setchr2(0x1000,mapbyte3[1]);
185         setchr2(0x1800,mapbyte3[3]);
186         break;
187  case 3:
188         for(x=0;x<8;x++)
189         {
190          setchr1(x<<10,mapbyte3[x&3]);
191          MMC5BGVROM_BANK1(x<<10,mapbyte3[x&3]);
192         }
193         break;
194  }
195 }
196
197 static void FASTAPASS(2) MMC5WRAM(uint32 A, uint32 V)
198 {
199    V=MMC5WRAMIndex[V&7];
200    if(V!=255)
201    {
202     setprg8r(0x10,A,V);
203     MMC5MemIn[(A-0x6000)>>13]=1;
204    }
205    else
206     MMC5MemIn[(A-0x6000)>>13]=0;
207 }
208
209 static void MMC5PRG(void)
210 {
211  int x;
212
213  switch(mapbyte1[0]&3)
214   {
215   case 0:
216            MMC5ROMWrProtect[0]=MMC5ROMWrProtect[1]=
217            MMC5ROMWrProtect[2]=MMC5ROMWrProtect[3]=1;
218            setprg32(0x8000,((mapbyte1[5]&0x7F)>>2));
219            for(x=0;x<4;x++)
220             MMC5MemIn[1+x]=1;
221            break;
222   case 1:
223          if(mapbyte1[5]&0x80)
224           {
225            MMC5ROMWrProtect[0]=MMC5ROMWrProtect[1]=1;
226            setprg16(0x8000,(mapbyte1[5]>>1));
227            MMC5MemIn[1]=MMC5MemIn[2]=1;
228           }
229          else
230           {
231            MMC5ROMWrProtect[0]=MMC5ROMWrProtect[1]=0;
232            MMC5WRAM(0x8000,mapbyte1[5]&7&0xFE);
233            MMC5WRAM(0xA000,(mapbyte1[5]&7&0xFE)+1);
234           }
235           MMC5MemIn[3]=MMC5MemIn[4]=1;
236           MMC5ROMWrProtect[2]=MMC5ROMWrProtect[3]=1;
237           setprg16(0xC000,(mapbyte1[7]&0x7F)>>1);
238          break;
239   case 2:
240          if(mapbyte1[5]&0x80)
241           {
242            MMC5MemIn[1]=MMC5MemIn[2]=1;
243            MMC5ROMWrProtect[0]=MMC5ROMWrProtect[1]=1;
244            setprg16(0x8000,(mapbyte1[5]&0x7F)>>1);
245           }
246          else
247           {
248            MMC5ROMWrProtect[0]=MMC5ROMWrProtect[1]=0;
249            MMC5WRAM(0x8000,mapbyte1[5]&7&0xFE);
250            MMC5WRAM(0xA000,(mapbyte1[5]&7&0xFE)+1);
251           }
252          if(mapbyte1[6]&0x80)
253           {MMC5ROMWrProtect[2]=1;MMC5MemIn[3]=1;setprg8(0xC000,mapbyte1[6]&0x7F);}
254          else
255           {MMC5ROMWrProtect[2]=0;MMC5WRAM(0xC000,mapbyte1[6]&7);}
256          MMC5MemIn[4]=1;
257          MMC5ROMWrProtect[3]=1;
258          setprg8(0xE000,mapbyte1[7]&0x7F);
259          break;
260   case 3:
261          for(x=0;x<3;x++)
262           if(mapbyte1[4+x]&0x80)
263           {
264            MMC5ROMWrProtect[0]=1;
265            setprg8(0x8000+(x<<13),mapbyte1[4+x]&0x7F);
266            MMC5MemIn[1+x]=1;
267           }
268           else
269           {
270            MMC5ROMWrProtect[0]=0;
271            MMC5WRAM(0x8000+(x<<13),mapbyte1[4+x]&7);
272           }
273          MMC5MemIn[4]=1;
274          MMC5ROMWrProtect[3]=1;
275          setprg8(0xE000,mapbyte1[7]&0x7F);
276          break;
277   }
278 }
279
280 #define mul1 mapbyte3[6]
281 #define mul2 mapbyte3[7]
282
283 static DECLFW(Mapper5_write)
284 {
285  switch(A)
286   {
287    default:break;
288    case 0x5105:
289                 {
290                 int x;
291                 for(x=0;x<4;x++)
292                 {
293                  switch((V>>(x<<1))&3)
294                  {
295                   case 0:PPUNTARAM|=1<<x;vnapage[x]=NTARAM;break;
296                   case 1:PPUNTARAM|=1<<x;vnapage[x]=NTARAM+0x400;break;
297                   case 2:PPUNTARAM|=1<<x;vnapage[x]=MapperExRAM+0x6000;break;
298                   case 3:PPUNTARAM&=~(1<<x);vnapage[x]=MMC5fill;break;
299                  }
300                 }
301                }
302                mapbyte4[3]=V;
303                break;
304
305    case 0x5113:mapbyte4[6]=V;MMC5WRAM(0x6000,V&7);break;
306    case 0x5100:mapbyte1[0]=V;MMC5PRG();break;
307    case 0x5101:mapbyte1[1]=V;
308                if(!mapbyte4[7])
309                 {MMC5CHRB();MMC5CHRA();}
310                else
311                 {MMC5CHRA();MMC5CHRB();}
312                break;
313
314    case 0x5114:
315    case 0x5115:
316    case 0x5116:
317    case 0x5117:
318                mapbyte1[A&7]=V;MMC5PRG();break;
319
320    case 0x5120:
321    case 0x5121:
322    case 0x5122:
323    case 0x5123:
324    case 0x5124:
325    case 0x5125:
326    case 0x5126:
327    case 0x5127:mapbyte4[7]=0;
328                mapbyte2[A&7]=V;MMC5CHRA();break;
329    case 0x5128:
330    case 0x5129:
331    case 0x512a:
332    case 0x512b:mapbyte4[7]=1;
333                mapbyte3[A&3]=V;MMC5CHRB();break;
334    case 0x5102:mapbyte4[0]=V;break;
335    case 0x5103:mapbyte4[1]=V;break;
336    case 0x5104:mapbyte4[2]=V;MMC5HackCHRMode=V&3;break;
337    case 0x5106:if(V!=mapbyte4[4])
338                {
339                 uint32 t;
340                 t=V|(V<<8)|(V<<16)|(V<<24);
341                 FCEU_dwmemset(MMC5fill,t,0x3c0);
342                }
343                mapbyte4[4]=V;
344                break;
345    case 0x5107:if(V!=mapbyte4[5])
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                mapbyte4[5]=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);IRQCount=V;break;
359    case 0x5204:X6502_IRQEnd(FCEU_IQEXT);IRQa=V&0x80;break;
360    case 0x5205:mul1=V;break;
361    case 0x5206:mul2=V;break;
362   }
363 }
364
365 DECLFR(MMC5_ReadROMRAM)
366 {
367         if(MMC5MemIn[(A-0x6000)>>13])
368          return Page[A>>11][A];
369         else
370          return X.DB;
371 }
372
373 DECLFW(MMC5_WriteROMRAM)
374 {
375        if(A>=0x8000)
376         if(MMC5ROMWrProtect[(A-0x8000)>>13])
377          return;
378        if(MMC5MemIn[(A-0x6000)>>13])
379         if(((mapbyte4[0]&3)|((mapbyte4[1]&3)<<2)) == 6)
380          Page[A>>11][A]=V;
381 }
382
383 static DECLFW(MMC5_ExRAMWr)
384 {
385  if(MMC5HackCHRMode!=3)
386   (MapperExRAM+0x6000)[A&0x3ff]=V;
387 }
388
389 static DECLFR(MMC5_ExRAMRd)
390 {
391  /* Not sure if this is correct, so I'll comment it out for now. */
392  //if(MMC5HackCHRMode>=2)
393   return (MapperExRAM+0x6000)[A&0x3ff];
394  //else
395  // return(X.DB);
396 }
397
398 static DECLFR(MMC5_read)
399 {
400  switch(A)
401  {
402   //default:printf("$%04x\n",A);break;
403   case 0x5204:X6502_IRQEnd(FCEU_IQEXT);
404               {
405                 uint8 x;
406                 x=MMC5IRQR;
407                 MMC5IRQR&=0x40;
408                 return x;
409               }
410   case 0x5205:return (mul1*mul2);
411   case 0x5206:return ((mul1*mul2)>>8);
412  }
413  return(X.DB);
414 }
415
416 uint8 dorko[0x400];
417
418 void MMC5Synco(void)
419 {
420  int x;
421
422  MMC5PRG();
423  for(x=0;x<4;x++)
424  {
425   switch((mapbyte4[3]>>(x<<1))&3)
426    {
427     case 0:PPUNTARAM|=1<<x;vnapage[x]=NTARAM;break;
428     case 1:PPUNTARAM|=1<<x;vnapage[x]=NTARAM+0x400;break;
429     case 2:PPUNTARAM|=1<<x;vnapage[x]=MapperExRAM+0x6000;break;
430     case 3:PPUNTARAM&=~(1<<x);vnapage[x]=MMC5fill;break;
431    }
432  }
433  MMC5WRAM(0x6000,mapbyte4[6]&7);
434  if(!mapbyte4[7])
435  {
436   MMC5CHRB();
437   MMC5CHRA();
438  }
439  else
440  {
441    MMC5CHRA();
442    MMC5CHRB();
443  }
444   {
445     uint32 t;
446     t=mapbyte4[4]|(mapbyte4[4]<<8)|(mapbyte4[4]<<16)|(mapbyte4[4]<<24);
447     FCEU_dwmemset(MMC5fill,t,0x3c0);
448   }
449   {
450    unsigned char moop;
451    uint32 t;
452    moop=mapbyte4[5]|(mapbyte4[5]<<2)|(mapbyte4[5]<<4)|(mapbyte4[5]<<6);
453    t=moop|(moop<<8)|(moop<<16)|(moop<<24);
454    FCEU_dwmemset(MMC5fill+0x3c0,t,0x40);
455   }
456   X6502_IRQEnd(FCEU_IQEXT);
457   MMC5HackCHRMode=mapbyte4[2]&3;
458 }
459
460 void MMC5_hbo(void)
461 {
462   if(scanline==0)
463    MMC5LineCounter=0;
464
465   if(MMC5LineCounter<245)
466   {
467    MMC5LineCounter++;
468    if(MMC5LineCounter==IRQCount) MMC5IRQR|=0x80;
469    if((MMC5LineCounter==IRQCount && IRQa&0x80))
470     X6502_IRQBegin(FCEU_IQEXT);
471   }
472   if(MMC5LineCounter>=239)
473     MMC5IRQR|=0x40;
474 }
475
476 void MMC5_hb(void)
477 {
478   if(scanline==240)
479   {
480    MMC5LineCounter=0;
481    MMC5IRQR=0x40;
482    return;
483   }
484
485   if(MMC5LineCounter<240)
486   {
487    MMC5LineCounter++;
488    if(MMC5LineCounter==IRQCount) 
489    {
490     MMC5IRQR|=0x80;
491     if(IRQa&0x80)
492      X6502_IRQBegin(FCEU_IQEXT);
493    }
494   }
495 //  printf("%d:%d\n",MMC5LineCounter,scanline);
496  if(MMC5LineCounter==240)
497    MMC5IRQR=0;
498 }
499
500 void Mapper5_StateRestore(int version)
501 {
502  if(version<=70)
503  {
504   uint8 tmp[8192];
505
506   FCEU_memmove(tmp,MapperExRAM,8192);
507   FCEU_memmove(MapperExRAM,MapperExRAM+8192,16384+8192);
508   FCEU_memmove(MapperExRAM+16384+8192,tmp,8192);
509  }
510  MMC5Synco();
511 }
512
513 #define MMC5PSG         (MapperExRAM+0x640B+8)
514
515 static int C5BC[3]={0,0,0};
516
517 static void Do5PCM(void)
518 {
519    int32 V;
520    int32 start,end;
521
522    start=C5BC[2];
523    end=(timestamp<<16)/soundtsinc;
524    if(end<=start) return;
525    C5BC[2]=end;
526    
527    if(!(MMC5PSG[0x10]&0x40) && MMC5PSG[0x11])
528     for(V=start;V<end;V++)
529      Wave[V>>4]+=MMC5PSG[0x11]<<2;
530 }
531
532 DECLFW(Mapper5_SW)
533 {
534  GameExpSound.Fill=MMC5Sound;
535  A&=0x1F;
536
537  switch(A)
538  {
539   case 0x10:
540   case 0x11:Do5PCM();break;
541
542   case 0x0:Do5SQ(0);break;
543   case 0x2:Do5SQ(0);break;
544   case 0x3:Do5SQ(0);break;
545   case 0x4:Do5SQ(1);break;
546   case 0x6:Do5SQ(1);break;
547   case 0x7:Do5SQ(1);break;
548   case 0x15:
549           {
550            int t=V^MMC5PSG[0x15];
551            if(t&1)
552             Do5SQ(0);
553            if(t&2)
554             Do5SQ(1);
555           }
556           break;
557  }
558  MMC5PSG[A]=V;
559 }
560
561 static int32 vcount[2];
562 void Do5SQ(int P)
563 {
564     int32 start,end;
565     int V;
566     int32 freq;
567
568     start=C5BC[P];
569     end=(timestamp<<16)/soundtsinc;
570     if(end<=start) return;
571     C5BC[P]=end;
572
573
574
575     if(MMC5PSG[0x15]&(P+1))
576     {
577      unsigned long dcycs;
578      unsigned char amplitude;
579      long vcoo;
580
581      freq=(((MMC5PSG[(P<<2)+0x2]|((MMC5PSG[(P<<2)+0x3]&7)<<8))));
582
583      if(freq<8) goto mmc5enda;
584      freq+=1;
585      inc=(long double)((unsigned long)((FSettings.SndRate OVERSAMPLE)<<12))/((long double)PSG_base/freq);
586
587      switch(MMC5PSG[P<<2]&0xC0)
588      {
589      default:
590      case 0x00:dcycs=inc>>3;break;
591      case 0x40:dcycs=inc>>2;break;
592      case 0x80:dcycs=inc>>1;break;
593      case 0xC0:dcycs=(inc+inc+inc)>>2;break;
594      }
595
596       amplitude=(MMC5PSG[P<<2]&15)<<4;
597
598       vcoo=vcount[P];
599              for(V=start;V<end;V++)
600               {
601                if(vcoo<dcycs)
602                 Wave[V>>4]+=amplitude;
603                vcoo+=0x1000;
604                if(vcoo>=inc) vcoo-=inc;
605                }
606       vcount[P]=vcoo;
607     }
608   mmc5enda:; // semi-colon must be here for MSVC
609 }
610
611 void MMC5Sound(int Count)
612 {
613   int x;
614   Do5SQ(0);
615   Do5SQ(1);
616   Do5PCM();
617   for(x=0;x<3;x++)
618    C5BC[x]=Count;
619 }
620
621 static void MMC5SoundC(void)
622 {
623  if(FSettings.SndRate)
624   Mapper5_ESI();
625  else
626   SetWriteHandler(0x5000,0x5015,0); 
627 }
628
629 void Mapper5_ESI(void)
630 {
631  GameExpSound.RChange=MMC5SoundC;
632
633  if(FSettings.SndRate)
634  {
635   SetWriteHandler(0x5000,0x5015,Mapper5_SW);
636   SetWriteHandler(0x5205,0x5206,Mapper5_write);
637   SetReadHandler(0x5205,0x5206,MMC5_read);
638  }
639  if(FCEUGameInfo.type==GIT_NSF)
640  {
641   SetWriteHandler(0x5c00,0x5fef,MMC5_ExRAMWr);
642   SetReadHandler(0x5c00,0x5fef,MMC5_ExRAMRd);
643   MMC5HackCHRMode=2;
644  }
645  else
646   GameHBIRQHook=MMC5_hb;
647 }
648
649 static void GenMMC5Reset(void)
650 {
651  mapbyte1[4]=mapbyte1[5]=mapbyte1[6]=mapbyte1[7]=~0;
652  mapbyte1[0]=mapbyte1[1]=3;
653  mapbyte4[2]=0;
654
655  mapbyte4[3]=mapbyte4[4]=mapbyte4[5]=0xFF;
656
657  MMC5Synco();
658
659  SetWriteHandler(0x4020,0x5bff,Mapper5_write);
660  SetReadHandler(0x4020,0x5bff,MMC5_read);
661
662  SetWriteHandler(0x5c00,0x5fff,MMC5_ExRAMWr);
663  SetReadHandler(0x5c00,0x5fff,MMC5_ExRAMRd);
664
665  SetWriteHandler(0x6000,0xFFFF,MMC5_WriteROMRAM);
666  SetReadHandler(0x6000,0xFFFF,MMC5_ReadROMRAM);
667
668  Mapper5_ESI();
669
670  GameHBIRQHook=MMC5_hb;
671  FCEU_CheatAddRAM(8,0x6000,WRAM);
672  FCEU_CheatAddRAM(1,0x5c00,MapperExRAM+0x6000);
673 }
674
675 void Mapper5_init(void)
676 {
677  AddExState(&MMC5HackSPMode, 1, 0, "SPLM");
678  AddExState(&MMC5HackSPScroll, 1, 0, "SPLS");
679  AddExState(&MMC5HackSPPage, 1, 0, "SPLP");
680  SetupCartPRGMapping(0x10,WRAM,32768,1);
681  GenMMC5Reset();
682  BuildWRAMSizeTable();
683  GameStateRestore=Mapper5_StateRestore;
684 }
685
686 static int m5boo;
687 static void GenMMC5_Close(void)
688 {
689  UNIFOpenWRAM(UOW_WR,0,1);
690  if(m5boo<=16)
691   UNIFWriteWRAM(WRAM,8192);
692  else
693   UNIFWriteWRAM(WRAM,32768);
694  UNIFCloseWRAM();
695 }
696
697 static void GenMMC5_Init(int wsize, int battery)
698 {
699  SetupCartPRGMapping(0x10,WRAM,32768,1);
700  AddExState(WRAM, 8192, 0, "WRAM");
701  AddExState(MapperExRAM, 32768, 0, "MEXR");
702  AddExState(&IRQCount, 4, 1, "IRQC");
703  AddExState(&IRQa, 1, 0, "IRQA");
704  AddExState(mapbyte1, 32, 0, "MPBY");
705  AddExState(&MMC5HackSPMode, 1, 0, "SPLM");
706  AddExState(&MMC5HackSPScroll, 1, 0, "SPLS");
707  AddExState(&MMC5HackSPPage, 1, 0, "SPLP");
708
709  MMC5WRAMsize=wsize/8; 
710  BuildWRAMSizeTable();
711  GameStateRestore=Mapper5_StateRestore;
712  BoardPower=GenMMC5Reset;
713
714  if(battery)
715  {
716   UNIFOpenWRAM(UOW_RD,0,1);
717   if(wsize<=16)
718    UNIFReadWRAM(WRAM,8192);
719   else
720    UNIFReadWRAM(WRAM,32768);
721   UNIFCloseWRAM();
722   BoardClose=GenMMC5_Close;
723   m5boo=wsize;
724  }
725
726  MMC5HackVROMMask=CHRmask4[0];
727  MMC5HackExNTARAMPtr=MapperExRAM+0x6000;
728  MMC5Hack=1;
729  MMC5HackVROMPTR=CHRptr[0];
730  MMC5HackCHRMode=0;
731  MMC5HackSPMode=MMC5HackSPScroll=MMC5HackSPPage=0;
732
733 }
734
735 // ETROM seems to have 16KB of WRAM, ELROM seems to have 8KB
736 // EWROM seems to have 32KB of WRAM
737
738 // ETROM and EWROM are battery-backed, ELROM isn't.
739
740 void ETROM_Init(void)
741 {
742  GenMMC5_Init(16,1);
743 }
744
745 void ELROM_Init(void)
746 {
747  GenMMC5_Init(8,0);
748 }
749
750 void EWROM_Init(void)
751 {
752  GenMMC5_Init(32,1);
753 }
754
755 void EKROM_Init(void)
756 {
757  GenMMC5_Init(8,1);
758 }