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