gpfce patch
[fceu.git] / ines.c
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 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25
26 #include "types.h"
27 #include "x6502.h"
28 #include "fce.h"
29 #define INESPRIV
30 #include "ines.h"
31 #include "version.h"
32 #include "svga.h"
33 #include "general.h"
34 #include "state.h"
35 #include "file.h"
36 #include "memory.h"
37 #include "cart.h"
38 #include "crc32.h"
39 #include "cheat.h"
40
41 static DECLFR(VSRead);
42
43 static uint8 *trainerpoo=0;
44 static uint8 *ROM=NULL;
45 uint8 *VROM=NULL;
46
47
48 static uint32 ROM_size;
49 uint32 VROM_size;
50
51 static void CheckVSUni(void);
52 static int MMC_init(int type);
53 void (*MapClose)(void);
54 void (*MapperReset)(void);
55
56 static int MapperNo;
57 static int SaveGame=0;
58
59 static iNES_HEADER head;
60
61 /*  MapperReset() is called when the NES is reset(with the reset button).  
62     Mapperxxx_init is called when the NES has been powered on.
63 */
64
65 static void iNESGI(int h)
66 {
67  switch(h)
68  {
69   case GI_RESETM2:
70                 if(MapperReset)
71                  MapperReset();
72                 break;
73   case GI_POWER:
74                 SetReadHandler(0x8000,0xFFFF,CartBR);
75                 MMC_init(MapperNo);
76                 break;
77   case GI_CLOSE:
78                 {
79                  FILE *sp;
80                 
81                  if(ROM) {free(ROM);ROM=0;}
82                  if(VROM) {free(VROM);VROM=0;}
83
84                  if(SaveGame)
85                  {
86                   char *soot;
87                   SaveGame=0;
88                   soot=FCEU_MakeFName(FCEUMKF_SAV,0,"sav");
89                   sp=fopen(soot,"wb");
90                   if (sp==NULL)
91                    FCEU_PrintError("WRAM file \"%s\" cannot be written to.\n",soot);
92                   else
93                   {
94                    void *ptr;
95                    uint32 amount;
96                    ptr=WRAM;
97                    amount=8192;
98
99                    if(MapperNo==1)
100                    {
101                      extern uint8 MMC1WRAMsize;
102                      if(MMC1WRAMsize==2) ptr=WRAM+8192;
103                    }
104                    else if(MapperNo==5)
105                    {
106                     extern uint8 MMC5WRAMsize;
107                     if(MMC5WRAMsize==4)
108                      amount=32768;
109                    }
110
111                    fwrite(ptr,1,amount,sp);
112                    fclose(sp);
113                   }
114                  }
115                  if(MapClose) MapClose();
116                  if(trainerpoo) {free(trainerpoo);trainerpoo=0;}
117                 }
118                 break;
119      }
120 }
121
122 uint32 iNESGameCRC32;
123
124 struct CRCMATCH {
125         uint32 crc;
126         char *name;
127 };
128
129 static void CheckBad(void)
130 {
131  int x;
132  #define CRCNT  7
133  struct CRCMATCH tab[CRCNT]={
134         {0x28d183ac,"Antarctic Adventure"},
135         {0x7095ac65,"Akumajo Densetsu"},
136         {0x1bd7ed5a,"Gradius 2"},
137         {0x81c3aa66,"Crisis Force"},
138         {0xfe3088df,"Fire Emblem Gaiden"},
139         {0xfa8339a5,"Bucky O'Hare"},
140         {0x3c539d78,"Ganbare Goemon 2"},
141         };
142   for(x=0;x<CRCNT;x++)
143    if(tab[x].crc == iNESGameCRC32)
144    {
145     FCEU_PrintError("The copy of the game you have loaded, %s, is a bad dump, has been hacked, or both.  It will not work correctly on FCE Ultra.  Use a good copy of the ROM image instead.",tab[x].name);
146     break;
147    }
148 }
149
150 struct INPSEL {
151         uint32 crc32;
152         int input1;
153         int input2;
154         int inputfc;
155 };
156
157 /* This is mostly for my personal use.  So HA. */
158 static void SetInput(void)
159 {
160  static struct INPSEL moo[]=
161         {
162          {0xad9c63e2,SI_GAMEPAD,-1,SIFC_SHADOW},        /* Space Shadow */
163          {0x24598791,-1,SI_ZAPPER,0},   /* Duck Hunt */
164          {0xff24d794,-1,SI_ZAPPER,0},   /* Hogan's Alley */
165          {0xbeb8ab01,-1,SI_ZAPPER,0},   /* Gumshoe */
166          {0xde8fd935,-1,SI_ZAPPER,0},   /* To the Earth */
167          {0xedc3662b,-1,SI_ZAPPER,0},   /* Operation Wolf */
168          {0x23d17f5e,SI_GAMEPAD,SI_ZAPPER,0},   /* The Lone Ranger */
169          {0xb8b9aca3,-1,SI_ZAPPER,0},  /* Wild Gunman */
170          {0x5112dc21,-1,SI_ZAPPER,0},  /* Wild Gunman */
171          {0x4318a2f8,-1,SI_ZAPPER,0},  /* Barker Bill's Trick Shooting */
172          {0x5ee6008e,-1,SI_ZAPPER,0},  /* Mechanized Attack */
173          {0x3e58a87e,-1,SI_ZAPPER,0},  /* Freedom Force */
174          {0x851eb9be,SI_GAMEPAD,SI_ZAPPER,0},   /* Shooting Range */
175          {0x74bea652,SI_GAMEPAD,SI_ZAPPER,0},   /* Supergun 3-in-1 */
176          {0x32fb0583,-1,SI_ARKANOID,0}, /* Arkanoid(NES) */
177          {0xd89e5a67,-1,-1,SIFC_ARKANOID}, /* Arkanoid (J) */
178          {0x0f141525,-1,-1,SIFC_ARKANOID}, /* Arkanoid 2(J) */
179
180          {0xf7606810,-1,-1,SIFC_FKB},   /* Family BASIC 2.0A */
181          {0x895037bc,-1,-1,SIFC_FKB},   /* Family BASIC 2.1a */
182          {0xb2530afc,-1,-1,SIFC_FKB},   /* Family BASIC 3.0 */
183          {0,-1,-1,-1}
184         };
185  int x=0;
186
187  while(moo[x].input1>=0 || moo[x].input2>=0 || moo[x].inputfc>=0)
188  {
189   if(moo[x].crc32==iNESGameCRC32)
190   {
191    FCEUGameInfo.input[0]=moo[x].input1;
192    FCEUGameInfo.input[1]=moo[x].input2;
193    FCEUGameInfo.inputfc=moo[x].inputfc;
194    break;
195   }
196   x++;
197  }
198 }
199
200 struct CHINF {
201         uint32 crc32;
202         int32 mapper;
203         int32 mirror;
204 };
205
206 #define SAVCNT  14
207 static void CheckHInfo(void)
208 {
209  /* ROM images that have the battery-backed bit set in the header that really
210     don't have battery-backed RAM is not that big of a problem, so I'll
211     treat this differently.
212  */
213
214  static uint32 savie[SAVCNT]=
215         {
216          0x7cab2e9b,0x3ee43cda,0xe1383deb,      /* Mouryou Senki Madara */
217          0x3b3f88f0,0x2545214c,                 /* Dragon Warrior PRG 0 and 1 */
218          0x8c5a784e,    /* DW 2 */
219          0xa86a5318,    /* DW 3 */
220          0x506e259d,    /* DW 4 */
221          0xcebd2a31,0xb8b88130, /* Final Fantasy */
222          0x466efdc2,    /* FF(J) */
223          0xc9556b36,    /* FF1+2*/
224          0xd29db3c7,    /* FF2 */
225          0x57e220d0,    /* FF3 */
226         };
227
228  static struct CHINF moo[]=
229         {
230          {0xc68363f6,180,0},    /* Crazy Climber */
231          {0xbe939fce,9,1},      /* Punchout*/
232          {0x5e66eaea,13,1},     /* Videomation */
233          {0xaf5d7aa2,-1,0},     /* Clu Clu Land */
234
235          {0xc2730c30,34,0},     /* Deadly Towers */
236          {0x932ff06e,34,1},     /* Classic Concentration */
237          {0x4c7c1af3,34,1},     /* Caesar's Palace */
238          {0x9ea1dc76,2,0},      /* Rainbow Islands */
239          
240          {0x9eefb4b4,4,8},      /* Pachi Slot Adventure 2 */
241          {0x5337f73c,4,8},      /* Niji no Silk Road */
242          {0x7474ac92,4,8},      /* Kabuki: Quantum Fighter */
243
244          {0x970bd9c2,1,8},      /* Hanjuku Hero */
245
246          {0xbb7c5f7a,89,8},     /* Mito Koumon or something similar */
247          /* Probably a Namco MMC3-workalike */
248          {0xa5e6baf9,4,1|4},    /* Dragon Slayer 4 */
249          {0xe40b4973,4,1|4},    /* Metro Cross */
250          {0xd97c31b0,4,1|4},    /* Rasaaru Ishii no Childs Quest */
251
252          {0x84382231,9,0},      /* Punch Out (J) */
253
254          {0xfcdaca80,0,0},      /* Elevator Action */
255          {0xe492d45a,0,0},      /* Zippy Race */
256          {0x32fa246f,0,0},      /* Tag Team Pro Wrestling */
257          {0x6d65cac6,2,0},      /* Terra Cresta */
258          {0x28c11d24,2,1},      /* Sukeban Deka */
259          {0x02863604,2,1},      /* Sukeban Deka */
260          {0x2bb6a0f8,2,1},      /* Sherlock Holmes */
261          {0x55773880,2,1},      /* Gilligan's Island */
262          {0x419461d0,2,1},      /* Super Cars */
263          {0x6e0eb43e,2,1},      /* Puss n Boots */
264          {0xfc3e5c86,2,1},      /* Trojan */
265
266          {0x291bcd7d,1,8},      /* Pachio Kun 2 */
267          {0xf74dfc91,1,-1},     /* Win, Lose, or Draw */
268
269          {0x59280bec,4,8},      /* Jackie Chan */
270
271          {0xfe364be5,1,8},      /* Deep Dungeon 4 */
272          {0xd8ee7669,1,8},      /* Adventures of Rad Gravity */
273          {0xa5e8d2cd,1,8},      /* Breakthru */
274          {0xf6fa4453,1,8},      /* Bigfoot */
275          {0x37ba3261,1,8},      /* Back to the Future 2 and 3 */
276          {0x934db14a,1,-1},     /* All-Pro Basketball */
277          {0xe94d5181,1,8},      /* Mirai Senshi - Lios */
278          {0x7156cb4d,1,8},      /* Muppet Adventure Carnival thingy */
279          {0x5b6ca654,1,8},      /* Barbie rev X*/
280          {0x57c12280,1,8},      /* Demon Sword */
281
282          {0xcf322bb3,3,1},      /* John Elway's Quarterback */
283          {0x9bde3267,3,1},      /* Adventures of Dino Riki */
284          {0x02cc3973,3,8},      /* Ninja Kid */
285          {0xb5d28ea2,3,1},      /* Mystery Quest - mapper 3?*/
286          {0xbc065fc3,3,1},      /* Pipe Dream */
287
288          {0x5b837e8d,1,8},      /* Alien Syndrome */
289          {0x283ad224,32,8},     /* Ai Sensei no Oshiete */
290          {0x5555fca3,32,8},     /* "" ""                */
291          {0x243a8735,32,0x10|4}, /* Major League */
292
293          {0x6bc65d7e,66,1},     /* Youkai Club*/
294          {0xc2df0a00,66,1},     /* Bio Senshi Dan(hacked) */
295          {0xbde3ae9b,66,1},     /* Doraemon */
296          {0xd26efd78,66,1},     /* SMB Duck Hunt */
297          {0x811f06d9,66,1},     /* Dragon Power */
298
299          {0x3293afea,66,1},     /* Mississippi Satsujin Jiken */
300          {0xe84274c5,66,1},     /* "" "" */
301
302
303          {0x6e68e31a,16,8},     /* Dragon Ball 3*/
304
305          {0xba51ac6f,78,2},
306          {0x3d1c3137,78,8},
307
308          {0xbda8f8e4,152,8},    /* Gegege no Kitarou 2 */
309          {0x026c5fca,152,8},    /* Saint Seiya Ougon Densetsu */
310          {0x0f141525,152,8},    /* Arkanoid 2 (Japanese) */
311          {0xb1a94b82,152,8},    /* Pocket Zaurus */
312
313          {0x3f15d20d,153,8},    /* Famicom Jump 2 */
314
315          {0xbba58be5,70,-1},    /* Family Trainer - Manhattan Police */
316          {0x370ceb65,70,-1},    /* Family Trainer - Meiro Dai Sakusen */
317          {0xdd8ed0f7,70,1},     /* Kamen Rider Club */
318
319          {0x90c773c1,118,-1},   /* Goal! 2 */
320          {0xb9b4d9e0,118,-1},   /* NES Play Action Football */
321          {0x78b657ac,118,-1},   /* Armadillo */
322          {0x37b62d04,118,-1},   /* Ys 3 */
323          {0x07d92c31,118,-1},   /* RPG Jinsei Game */
324          {0x2705eaeb,234,-1},   /* Maxi 15 */
325          {0x404b2e8b,4,2},      /* Rad Racer 2 */
326
327          {0x1356f6a6,4,8},      /* "Cattou Ninden Teyandee" English tranlation.
328                                     Should I have even bothered to do this? */
329          {0x50fd4fd6,4,8},      /* "" "" */
330
331          {0xa912b064,51|0x800,8},       /* 11-in-1 Ball Games(has CHR ROM when it shouldn't) */
332          {0,-1,-1}
333         };
334  int tofix=0;
335  int x=0;
336
337  do
338  {
339   if(moo[x].crc32==iNESGameCRC32)
340   {
341    if(moo[x].mapper>=0)
342    {
343     if(moo[x].mapper&0x800 && VROM_size)
344     {
345      VROM_size=0;
346      free(VROM);
347      tofix|=8;
348     }
349     if(MapperNo!=(moo[x].mapper&0xFF))
350     {
351      tofix|=1;
352      MapperNo=moo[x].mapper&0xFF;
353     }
354    }
355    if(moo[x].mirror>=0)
356    {
357     if(moo[x].mirror==8)
358     {
359      if(Mirroring==2)   /* Anything but hard-wired(four screen). */
360      {
361       tofix|=2;
362       Mirroring=0;
363      }
364     }
365     else if(Mirroring!=moo[x].mirror)
366     {
367      if(Mirroring!=(moo[x].mirror&~4))
368       if((moo[x].mirror&~4)<=2) /* Don't complain if one-screen mirroring
369                                    needs to be set(the iNES header can't
370                                    hold this information).
371                                 */
372        tofix|=2;
373      Mirroring=moo[x].mirror;
374     }
375    }
376    break;
377   }
378   x++;
379  } while(moo[x].mirror>=0 || moo[x].mapper>=0);
380
381  for(x=0;x<SAVCNT;x++)
382  {
383   if(savie[x]==iNESGameCRC32)
384   {
385    if(!(head.ROM_type&2))
386    {
387     tofix|=4;
388     head.ROM_type|=2;
389    }
390   }
391  }
392
393  /* Games that use these iNES mappers tend to have the four-screen bit set
394     when it should not be.
395  */
396  if((MapperNo==118 || MapperNo==24 || MapperNo==26) && (Mirroring==2))
397  {
398   Mirroring=0;
399   tofix|=2;
400  }
401
402  if(tofix)
403  {
404   char gigastr[768];
405   strcpy(gigastr,"The iNES header contains incorrect information.  For now, the information will be corrected in RAM.  ");
406   if(tofix&1)
407    sprintf(gigastr+strlen(gigastr),"The mapper number should be set to %d.  ",MapperNo);
408   if(tofix&2)
409   {
410    char *mstr[3]={"Horizontal","Vertical","Four-screen"};
411    sprintf(gigastr+strlen(gigastr),"Mirroring should be set to \"%s\".  ",mstr[Mirroring&3]);
412   }
413   if(tofix&4)
414    strcat(gigastr,"The battery-backed bit should be set.  ");  
415   if(tofix&8)
416    strcat(gigastr,"This game should not have any CHR ROM.  ");
417   strcat(gigastr,"\n");
418   FCEUD_PrintError(gigastr);
419  }
420 }
421
422 int iNESLoad(char *name, int fp)
423 {
424         FILE *sp;
425
426         if(FCEU_fread(&head,1,16,fp)!=16)
427          return 0;
428
429         if(memcmp(&head,"NES\x1a",4))
430          return 0;
431
432         if(!memcmp((char *)(&head)+0x7,"DiskDude",8))
433         {
434          memset((char *)(&head)+0x7,0,0x9);
435         }
436
437         if(!memcmp((char *)(&head)+0x7,"demiforce",9))
438         {
439          memset((char *)(&head)+0x7,0,0x9);
440         }
441
442         if(!memcmp((char *)(&head)+0xA,"Ni03",4))
443         {
444          if(!memcmp((char *)(&head)+0x7,"Dis",3))
445           memset((char *)(&head)+0x7,0,0x9);
446          else
447           memset((char *)(&head)+0xA,0,0x6);
448         }
449
450         if(!head.ROM_size)
451          head.ROM_size++;
452
453         ROM_size = head.ROM_size;
454         VROM_size = head.VROM_size;
455         ROM_size=uppow2(ROM_size);
456
457         if(VROM_size)
458          VROM_size=uppow2(VROM_size);
459
460         MapperNo = (head.ROM_type>>4);
461         MapperNo|=(head.ROM_type2&0xF0);
462
463         Mirroring = (head.ROM_type&1);
464         if(head.ROM_type&8) Mirroring=2;
465
466         if(!(ROM=(uint8 *)FCEU_malloc(ROM_size<<14)))
467          return 0;
468                 
469         if (VROM_size) 
470          if(!(VROM=(uint8 *)FCEU_malloc(VROM_size<<13)))
471          {
472           free(ROM);
473           return 0;
474          }
475
476         memset(ROM,0xFF,ROM_size<<14);
477         if(VROM_size) memset(VROM,0xFF,VROM_size<<13);
478         if(head.ROM_type&4)     /* Trainer */
479         {
480          if(!(trainerpoo=FCEU_malloc(512)))
481           return(0);
482          FCEU_fread(trainerpoo,512,1,fp);
483         }
484         ResetCartMapping();
485         SetupCartPRGMapping(0,ROM,ROM_size*0x4000,0);
486         SetupCartPRGMapping(1,WRAM,8192,1);
487
488         FCEU_fread(ROM,0x4000,head.ROM_size,fp);
489
490         if(VROM_size)
491          FCEU_fread(VROM,0x2000,head.VROM_size,fp);
492
493         printf("File %s loaded.\n",name);
494
495         iNESGameCRC32=CalcCRC32(0,ROM,ROM_size<<14);
496         if(VROM_size)
497          iNESGameCRC32=CalcCRC32(iNESGameCRC32,VROM,VROM_size<<13);
498         printf("\n PRG ROM:  %3d x 16k\n CHR ROM:  %3d x  8k\n ROM CRC32:  %08lx\n Mapper:  %d\n Mirroring: %s\n",head.ROM_size,head.VROM_size,iNESGameCRC32,MapperNo,Mirroring==2?"None(Four-screen)":Mirroring?"Vertical":"Horizontal");
499         if(head.ROM_type&2) puts(" Battery-backed.");
500         if(head.ROM_type&4) puts(" Trained.");
501         puts("");
502
503         CheckBad();
504         SetInput();
505         CheckHInfo();
506         CheckVSUni();
507         //if(MapperNo!=4 && MapperNo!=118 && MapperNo!=119) exit(1); // Testing
508
509         /* Must remain here because above functions might change value of
510            VROM_size and free(VROM).
511         */
512         if(VROM_size)
513          SetupCartCHRMapping(0,VROM,VROM_size*0x2000,0);
514
515         if(Mirroring==2)
516          SetupCartMirroring(4,1,ExtraNTARAM);
517         else if(Mirroring>=0x10)
518          SetupCartMirroring(2+(Mirroring&1),1,0);
519         else
520          SetupCartMirroring(Mirroring&1,(Mirroring&4)>>2,0);
521
522         if(MapperNo==5) DetectMMC5WRAMSize();
523         else if(MapperNo==1) DetectMMC1WRAMSize();
524
525         if(head.ROM_type&2)
526         {         
527          char *soot;
528
529          SaveGame=1;
530          soot=FCEU_MakeFName(FCEUMKF_SAV,0,"sav");
531          sp=fopen(soot,"rb");
532          if(sp!=NULL)
533          {
534           void *ptr;
535           uint32 amount;
536
537           ptr=WRAM;
538           amount=8192;
539           if(MapperNo==1)
540           {
541            extern uint8 MMC1WRAMsize;
542            if(MMC1WRAMsize==2) ptr=WRAM+8192;
543           }
544           else if(MapperNo==5)
545           {
546            extern uint8 MMC5WRAMsize;
547            if(MMC5WRAMsize==4)
548             amount=32768;
549           }
550           if(fread(ptr,1,amount,sp)==amount)
551            printf("  WRAM Save File \"%s\" loaded...\n",soot);
552           fclose(sp);
553          }
554
555    }
556         GameInterface=iNESGI;
557         return 1;
558 }
559
560 #include        "banksw.h"
561
562
563 void FASTAPASS(1) onemir(uint8 V)
564 {
565         if(Mirroring==2) return;
566         if(V>1)
567          V=1;
568         Mirroring=0x10|V;
569         setmirror(MI_0+V);
570 }
571
572 void FASTAPASS(1) MIRROR_SET2(uint8 V)
573 {
574         if(Mirroring==2) return;
575         Mirroring=V;
576         setmirror(V);
577 }
578
579 void FASTAPASS(1) MIRROR_SET(uint8 V)
580 {
581         if(Mirroring==2) return;
582         V^=1;
583         Mirroring=V;
584         setmirror(V);
585 }
586
587 static void NONE_init(void)
588 {
589         ROM_BANK16(0x8000,0);
590         ROM_BANK16(0xC000,~0);
591
592         if(VROM_size) 
593          VROM_BANK8(0);
594         else
595          setvram8(CHRRAM);
596 }
597
598 static uint8 secdata[2][32]=
599 {
600  {
601   0xff, 0xbf, 0xb7, 0x97, 0x97, 0x17, 0x57, 0x4f,
602   0x6f, 0x6b, 0xeb, 0xa9, 0xb1, 0x90, 0x94, 0x14,
603   0x56, 0x4e, 0x6f, 0x6b, 0xeb, 0xa9, 0xb1, 0x90,
604   0xd4, 0x5c, 0x3e, 0x26, 0x87, 0x83, 0x13, 0x00
605  },
606  {
607   0x00, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00,
608   0x00, 0x6F, 0x00, 0x00, 0x00, 0x00, 0x94, 0x00,
609   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
610   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
611  }
612 };
613
614 static uint8 *secptr;
615
616 static void CheckVSUni(void)
617 {
618         FCEUGameInfo.type=GIT_VSUNI;
619         
620         /* FCE Ultra doesn't complain when headers for these games are bad. */
621         secptr=0;
622         switch(iNESGameCRC32)
623         {
624          default:FCEUGameInfo.type=0;break;
625
626          case 0xffbef374: pale=1;break; /* Castlevania */
627
628          case 0x98e3c75a: 
629          case 0x7cff0f84: pale=2;break; /* SMB */
630         
631          case 0xef7af338: pale=2;break; /* Ice Climber */
632          case 0xabe1a0c2: FCEUGameInfo.input[0]=SI_ZAPPER;break; /*Duck hunt */
633          case 0x16aa4e2d: pale=7;FCEUGameInfo.input[0]=SI_ZAPPER;break; /* hoganal ^_^ */
634          case 0x2b85420e: pale=3;break; /* Dr Mario */
635
636          case 0xfb0ddde7: pale=2;break;
637          case 0xc95321a8: pale=6;break; /* Excitebike */
638          case 0xb1c4c508: pale=1;break; /* Golf */
639
640          case 0x66471efe: break;
641          case 0xca3e9b1a: pale=7;break; /* Pinball*/
642
643          case 0xf735d926: pale=7; break; /* Gradius */
644
645          case 0x2019fe65:
646          case 0x31678411:MapperNo=68;pale=7;break; /* Platoon */
647
648          case 0x74f713b4:pale=4;break; /* Goonies */
649          case 0x9ae2baa0:pale=5;break; /* Slalom */
650          case 0xe45485a5:secptr=secdata[1];vsdip=0x20;MapperNo=4;break; /* RBI Baseball */
651          case 0x21a653c7:vsdip=0x20;MapperNo=4;break; /* Super Sky Kid */
652          case 0xe9a6f17d:vsdip=0x20;break; /* Tetris */
653
654          case 0x159ef3c1:break; /* Star Luster */
655          case 0x9768e5e0:break; /* Stroke and Match Golf */
656         
657          /* FCE Ultra doesn't have correct palettes for the following games. */
658          case 0x0fa322c2:pale=2;break; /* Clu Clu Land */
659
660          case 0x766c2cac:       /* Soccer */
661          case 0x01357944:       /* Battle City */
662          case 0xb2816bf9:break; /* Battle City (Bootleg) */
663
664          case 0x832cf592:FCEUGameInfo.input[0]=SI_ZAPPER;break; /* Freedom Force */
665          case 0x63abf889:break; /* Ladies Golf */
666          case 0x8c0c2df5:pale=2;MapperNo=1;Mirroring=1;break; /* Top Gun */
667          case 0x52c501d0:vsdip=0x80;MapperNo=4;secptr=secdata[0];break; 
668                         /* TKO Boxing */
669         }
670
671         if(MapperNo==99)
672          Mirroring=2;
673 }
674
675
676 static int VSindex;
677
678 static DECLFR(VSRead)
679 {
680  //printf("$%04x, $%04x\n",A,X.PC);
681  switch(A)
682  {
683   default:
684   case 0x5e00: VSindex=0;return 0xFF;
685   case 0x5e01: return(secptr[(VSindex++)&0x1F]);
686  }
687 }
688
689 static void DoVSHooks(void)
690 {
691  if(secptr)
692   SetReadHandler(0x5e00,0x5e01,VSRead);
693 }
694
695 void (*MapInitTab[256])(void)=
696 {
697         0,
698         Mapper1_init,Mapper2_init,Mapper3_init,Mapper4_init,
699         Mapper5_init,Mapper6_init,Mapper7_init,Mapper8_init,
700         Mapper9_init,Mapper10_init,Mapper11_init,0,
701         Mapper13_init,0,Mapper15_init,Mapper16_init,
702         Mapper17_init,Mapper18_init,Mapper19_init,0,
703         Mapper21_init,Mapper22_init,Mapper23_init,Mapper24_init,
704         Mapper25_init,Mapper26_init,0,0,
705         0,0,0,Mapper32_init,
706         Mapper33_init,Mapper34_init,0,0,
707         0,0,0,Mapper40_init,
708         Mapper41_init,Mapper42_init,Mapper43_init,Mapper44_init,
709         Mapper45_init,Mapper46_init,Mapper47_init,Mapper33_init,Mapper49_init,0,Mapper51_init,Mapper52_init,
710         0,0,0,0,0,0,0,0,
711         0,0,0,Mapper64_init,
712         Mapper65_init,Mapper66_init,Mapper67_init,Mapper68_init,
713         Mapper69_init,Mapper70_init,Mapper71_init,Mapper72_init,
714         Mapper73_init,0,Mapper75_init,Mapper76_init,
715         Mapper77_init,Mapper78_init,Mapper79_init,Mapper80_init,
716         0,Mapper82_init,Mapper83_init,0,
717         Mapper85_init,Mapper86_init,Mapper87_init,Mapper88_init,
718         Mapper89_init,Mapper90_init,0,Mapper92_init,
719         Mapper93_init,Mapper94_init,Mapper95_init,Mapper96_init,
720         Mapper97_init,0,Mapper99_init,0,
721         0,0,0,0,Mapper105_init,0,0,0,
722         0,0,0,Mapper112_init,Mapper113_init,0,0,0,
723         Mapper117_init,Mapper118_init,Mapper119_init,0,0,0,0,0,
724         0,0,0,0,0,0,0,0,
725         0,0,0,0,0,0,0,Mapper140_init,
726         0,0,0,0,0,0,0,0,
727         0,0,Mapper151_init,Mapper152_init,Mapper153_init,0,0,0,
728         0,0,0,0,0,0,0,0,
729         0,0,0,0,0,0,0,0,
730         0,0,0,0,0,0,0,Mapper180_init,
731         0,Mapper182_init,0,Mapper184_init,Mapper185_init,0,0,0,
732         Mapper189_init,0,0,0,0,0,0,0,
733         0,0,0,0,0,0,0,0,
734         0,0,0,0,0,0,0,0,
735         0,0,0,0,0,0,0,0,
736         0,0,0,0,Mapper225_init,Mapper226_init,Mapper227_init,Mapper228_init,
737         Mapper229_init,0,0,Mapper232_init,0,Mapper234_init,Mapper43_init,0,
738         0,0,0,Mapper240_init,0,Mapper242_init,0,0,
739         Mapper245_init,Mapper246_init,0,Mapper248_init,Mapper249_init,Mapper250_init,0,0,0,0,0
740 };
741
742 static DECLFW(BWRAM)
743 {
744                 WRAM[A-0x6000]=V;
745 }
746
747 static DECLFR(AWRAM)
748 {
749                 return WRAM[A-0x6000];
750 }
751
752 void (*MapStateRestore)(int version);
753 void iNESStateRestore(int version)
754 {
755  int x;
756  
757  if(!MapperNo) return;
758
759  for(x=0;x<4;x++)
760   setprg8(0x8000+x*8192,PRGBankList[x]);
761
762  if(VROM_size)
763   for(x=0;x<8;x++) 
764     setchr1(0x400*x,CHRBankList[x]);
765
766  switch(Mirroring)
767  {
768    case 0:setmirror(MI_H);break;
769    case 1:setmirror(MI_V);break;
770    case 0x12:
771    case 0x10:setmirror(MI_0);break;
772    case 0x13:
773    case 0x11:setmirror(MI_1);break;
774  }
775  if(MapStateRestore) MapStateRestore(version);
776 }
777
778 static int MMC_init(int type)
779 {
780         int x;
781
782         GameStateRestore=iNESStateRestore;
783         MapClose=0;
784         MapperReset=0;
785         MapStateRestore=0;
786
787         setprg8r(1,0x6000,0);
788
789         SetReadHandler(0x6000,0x7FFF,AWRAM);
790         SetWriteHandler(0x6000,0x7FFF,BWRAM);
791         FCEU_CheatAddRAM(8,0x6000,WRAM);
792
793         /* This statement represents atrocious code.  I need to rewrite
794            all of the iNES mapper code... */
795         IRQCount=IRQLatch=IRQa=0;
796         if(head.ROM_type&2)
797         {
798          extern uint8 MMC5WRAMsize,MMC1WRAMsize;
799          if(type==5 && MMC5WRAMsize==4)
800           memset(GameMemBlock+32768,0,sizeof(GameMemBlock)-32768);
801          else if(type==1 && MMC1WRAMsize==2)
802          {
803           memset(GameMemBlock,0,8192);
804           memset(GameMemBlock+16384,0,sizeof(GameMemBlock)-16384);
805          }
806          else
807           memset(GameMemBlock+8192,0,sizeof(GameMemBlock)-8192);
808         }
809         else
810          memset(GameMemBlock,0,sizeof(GameMemBlock));
811         if(head.ROM_type&4)
812          memcpy(WRAM+4096,trainerpoo,512);
813
814         NONE_init();
815
816         if(FCEUGameInfo.type==GIT_VSUNI)
817          DoVSHooks();
818         if(type==5)
819         {
820           MMC5HackVROMMask=CHRmask4[0];
821           MMC5HackExNTARAMPtr=MapperExRAM+0x6000;
822           MMC5Hack=1;
823           MMC5HackVROMPTR=VROM;
824           MMC5HackCHRMode=0;
825         }
826         ResetExState();
827         AddExState(WRAM, 8192, 0, "WRAM");
828         if(type==19 || type==5 || type==6 || type==69 || type==85)
829          AddExState(MapperExRAM, 32768, 0, "MEXR");
830         if((!VROM_size || type==6 || type==19 || type==119) &&
831            (type!=13 && type!=96))
832          AddExState(CHRRAM, 8192, 0, "CHRR");
833         if(head.ROM_type&8)
834          AddExState(ExtraNTARAM, 2048, 0, "EXNR");
835
836         /* Exclude some mappers whose emulation code handle save state stuff 
837            themselves. */
838         if(type && type!=13 && type!=96)
839         {
840          AddExState(mapbyte1, 32, 0, "MPBY");
841          AddExState(&Mirroring, 1, 0, "MIRR");
842          AddExState(&IRQCount, 4, 1, "IRQC");
843          AddExState(&IRQLatch, 4, 1, "IQL1");
844          AddExState(&IRQa, 1, 0, "IRQA");
845          AddExState(PRGBankList, 4, 0, "PBL");
846          for(x=0;x<8;x++)
847          {
848           char tak[8];
849           sprintf(tak,"CBL%d",x);         
850           AddExState(&CHRBankList[x], 2, 1,tak);
851          }
852         }
853
854         if(MapInitTab[type]) MapInitTab[type]();
855         else if(type)
856         {
857          FCEU_PrintError("iNES mapper #%d is not supported at all.",type);
858         }
859         return 1;
860 }