679fb92ad85e8ffe4d6a3f05c03b513074b336da
[fceu.git] / ines.c
1 /* FCE Ultra - NES/Famicom Emulator\r
2  *\r
3  * Copyright notice for this file:\r
4  *  Copyright (C) 1998 BERO\r
5  *  Copyright (C) 2002 Xodnizel\r
6  *\r
7  * This program is free software; you can redistribute it and/or modify\r
8  * it under the terms of the GNU General Public License as published by\r
9  * the Free Software Foundation; either version 2 of the License, or\r
10  * (at your option) any later version.\r
11  *\r
12  * This program is distributed in the hope that it will be useful,\r
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
15  * GNU General Public License for more details.\r
16  *\r
17  * You should have received a copy of the GNU General Public License\r
18  * along with this program; if not, write to the Free Software\r
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
20  */\r
21 \r
22 #include <stdio.h>\r
23 #include <stdlib.h>\r
24 #include <string.h>\r
25 \r
26 #include "types.h"\r
27 #include "x6502.h"\r
28 #include "fce.h"\r
29 #include "cart.h"\r
30 #include "ppu.h"\r
31 \r
32 #define INESPRIV\r
33 #include "ines.h"\r
34 #include "unif.h"\r
35 #include "general.h"\r
36 #include "state.h"\r
37 #include "file.h"\r
38 #include "memory.h"\r
39 #include "crc32.h"\r
40 #include "md5.h"\r
41 #include "cheat.h"\r
42 #include "vsuni.h"\r
43 \r
44 #include "driver.h"\r
45 #include "svga.h"\r
46 \r
47 extern SFORMAT FCEUVSUNI_STATEINFO[];\r
48 \r
49 static uint8 *trainerpoo=0;\r
50 static uint8 *ROM=NULL;\r
51 //static\r
52 uint8 *VROM=NULL;\r
53 \r
54 static CartInfo iNESCart;\r
55 \r
56 uint8 iNESMirroring=0;\r
57 uint16 iNESCHRBankList[8]={0,0,0,0,0,0,0,0};\r
58 int32 iNESIRQLatch=0,iNESIRQCount=0;\r
59 uint8 iNESIRQa=0;\r
60 \r
61 uint32 ROM_size=0;\r
62 uint32 VROM_size=0;\r
63 \r
64 static void iNESPower(void);\r
65 static int NewiNES_Init(int num);\r
66 \r
67 void (*MapClose)(void);\r
68 void (*MapperReset)(void);\r
69 \r
70 static int MapperNo=0;\r
71 \r
72 static iNES_HEADER head;\r
73 \r
74 /*  MapperReset() is called when the NES is reset(with the reset button).\r
75     Mapperxxx_init is called when the NES has been powered on.\r
76 */\r
77 \r
78 static DECLFR(TrainerRead)\r
79 {\r
80  return(trainerpoo[A&0x1FF]);\r
81 }\r
82 \r
83 static void iNESGI(int h)\r
84 {\r
85  switch(h)\r
86  {\r
87   case GI_RESETM2:\r
88                 if(MapperReset)\r
89                  MapperReset();\r
90                 if(iNESCart.Reset)\r
91                  iNESCart.Reset();\r
92                 break;\r
93   case GI_POWER:\r
94                 if(iNESCart.Power)\r
95                  iNESCart.Power();\r
96                 if(trainerpoo)\r
97                 {\r
98                  int x;\r
99                  for(x=0;x<512;x++)\r
100                  {\r
101                   //X6502_DMW(0x7000+x,trainerpoo[x]);\r
102                   //if(X6502_DMR(0x7000+x)!=trainerpoo[x])\r
103                   unsigned int A=0x7000+x;\r
104                   BWrite[A](A,trainerpoo[x]);\r
105                   if(ARead[A](A)!=trainerpoo[x])\r
106                   {\r
107                     SetReadHandler(0x7000,0x71FF,TrainerRead);\r
108                     break;\r
109                   }\r
110                  }\r
111                 }\r
112                 break;\r
113   case GI_CLOSE:\r
114                 {\r
115                  FCEU_SaveGameSave(&iNESCart);\r
116 \r
117                  if(iNESCart.Close) iNESCart.Close();\r
118                  if(ROM) {free(ROM);ROM=0;}\r
119                  if(VROM) {free(VROM);VROM=0;}\r
120                  if(MapClose) MapClose();\r
121                  if(trainerpoo) {FCEU_gfree(trainerpoo);trainerpoo=0;}\r
122                 }\r
123                 break;\r
124      }\r
125 }\r
126 \r
127 uint32 iNESGameCRC32=0;\r
128 \r
129 struct CRCMATCH  {\r
130         uint32 crc;\r
131         char *name;\r
132 };\r
133 \r
134 struct INPSEL {\r
135         uint32 crc32;\r
136         int input1;\r
137         int input2;\r
138         int inputfc;\r
139 };\r
140 \r
141 /* This is mostly for my personal use.  So HA. */\r
142 static void SetInput(void)\r
143 {\r
144  static struct INPSEL moo[]=\r
145         {\r
146          {0x3a1694f9,SI_GAMEPAD,SI_GAMEPAD,SIFC_4PLAYER},       /* Nekketsu Kakutou Densetsu */\r
147 \r
148 #if 0\r
149    {0xc3c0811d,SI_GAMEPAD,SI_GAMEPAD,SIFC_OEKAKIDS},  /* The two "Oeka Kids" games */\r
150    {0x9d048ea4,SI_GAMEPAD,SI_GAMEPAD,SIFC_OEKAKIDS},  /*           */\r
151 \r
152    {0xaf4010ea,SI_GAMEPAD,SI_POWERPADB,-1},  /* World Class Track Meet */\r
153    {0xd74b2719,SI_GAMEPAD,SI_POWERPADB,-1},  /* Super Team Games */\r
154    {0x61d86167,SI_GAMEPAD,SI_POWERPADB,-1},  /* Street Cop */\r
155    {0x6435c095,SI_GAMEPAD,SI_POWERPADB,-1},      /* Short Order/Eggsplode */\r
156 \r
157 \r
158    {0x47232739,SI_GAMEPAD,SI_GAMEPAD,SIFC_TOPRIDER},  /* Top Rider */\r
159 \r
160          {0x48ca0ee1,SI_GAMEPAD,SI_GAMEPAD,SIFC_BWORLD},    /* Barcode World */\r
161          {0x9f8f200a,SI_GAMEPAD,SI_GAMEPAD,SIFC_FTRAINERA}, /* Super Mogura Tataki!! - Pokkun Moguraa */\r
162          {0x9044550e,SI_GAMEPAD,SI_GAMEPAD,SIFC_FTRAINERA}, /* Rairai Kyonshizu */\r
163          {0x2f128512,SI_GAMEPAD,SI_GAMEPAD,SIFC_FTRAINERA}, /* Jogging Race */\r
164          {0x60ad090a,SI_GAMEPAD,SI_GAMEPAD,SIFC_FTRAINERA}, /* Athletic World */\r
165 \r
166          {0x8a12a7d9,SI_GAMEPAD,SI_GAMEPAD,SIFC_FTRAINERB}, /* Totsugeki Fuuun Takeshi Jou */\r
167          {0xea90f3e2,SI_GAMEPAD,SI_GAMEPAD,SIFC_FTRAINERB}, /* Running Stadium */\r
168          {0x370ceb65,SI_GAMEPAD,SI_GAMEPAD,SIFC_FTRAINERB}, /* Meiro Dai Sakusen */\r
169          // Bad dump? {0x69ffb014,SI_GAMEPAD,SI_GAMEPAD,SIFC_FTRAINERB}, /* Fuun Takeshi Jou 2 */\r
170          {0x6cca1c1f,SI_GAMEPAD,SI_GAMEPAD,SIFC_FTRAINERB}, /* Dai Undoukai */\r
171          {0x29de87af,SI_GAMEPAD,SI_GAMEPAD,SIFC_FTRAINERB},  /* Aerobics Studio */\r
172          {0xbba58be5,SI_GAMEPAD,SI_GAMEPAD,SIFC_FTRAINERB},  /* Family Trainer: Manhattan Police */\r
173          {0xea90f3e2,SI_GAMEPAD,SI_GAMEPAD,SIFC_FTRAINERB},  /* Family Trainer:  Running Stadium */\r
174 \r
175          {0xd9f45be9,SI_GAMEPAD,SI_GAMEPAD,SIFC_QUIZKING},  /* Gimme a Break ... */\r
176          {0x1545bd13,SI_GAMEPAD,SI_GAMEPAD,SIFC_QUIZKING},  /* Gimme a Break ... 2 */\r
177 \r
178          {0x7b44fb2a,SI_GAMEPAD,SI_GAMEPAD,SIFC_MAHJONG},  /* Ide Yousuke Meijin no Jissen Mahjong 2 */\r
179          {0x9fae4d46,SI_GAMEPAD,SI_GAMEPAD,SIFC_MAHJONG},  /* Ide Yousuke Meijin no Jissen Mahjong */\r
180 \r
181          {0x980be936,SI_GAMEPAD,SI_GAMEPAD,SIFC_HYPERSHOT}, /* Hyper Olympic */\r
182          {0x21f85681,SI_GAMEPAD,SI_GAMEPAD,SIFC_HYPERSHOT}, /* Hyper Olympic (Gentei Ban) */\r
183          {0x915a53a7,SI_GAMEPAD,SI_GAMEPAD,SIFC_HYPERSHOT}, /* Hyper Sports */\r
184 #endif\r
185    {0xad9c63e2,SI_GAMEPAD,-1,SIFC_SHADOW},  /* Space Shadow */\r
186 \r
187    {0x24598791,-1,SI_ZAPPER,0},  /* Duck Hunt */\r
188          {0xff24d794,-1,SI_ZAPPER,0},   /* Hogan's Alley */\r
189    {0xbeb8ab01,-1,SI_ZAPPER,0},  /* Gumshoe */\r
190    {0xde8fd935,-1,SI_ZAPPER,0},  /* To the Earth */\r
191    {0xedc3662b,-1,SI_ZAPPER,0},  /* Operation Wolf */\r
192    {0x2a6559a1,-1,SI_ZAPPER,0},  /* Operation Wolf (J) */\r
193 \r
194    {0x23d17f5e,SI_GAMEPAD,SI_ZAPPER,0},  /* The Lone Ranger */\r
195          {0xb8b9aca3,-1,SI_ZAPPER,0},  /* Wild Gunman */\r
196          {0x5112dc21,-1,SI_ZAPPER,0},  /* Wild Gunman */\r
197          {0x4318a2f8,-1,SI_ZAPPER,0},  /* Barker Bill's Trick Shooting */\r
198          {0x5ee6008e,-1,SI_ZAPPER,0},  /* Mechanized Attack */\r
199          {0x3e58a87e,-1,SI_ZAPPER,0},  /* Freedom Force */\r
200    {0x851eb9be,SI_GAMEPAD,SI_ZAPPER,0},  /* Shooting Range */\r
201    {0x74bea652,SI_GAMEPAD,SI_ZAPPER,0},  /* Supergun 3-in-1 */\r
202          {0x32fb0583,-1,SI_ARKANOID,0}, /* Arkanoid(NES) */\r
203          {0xd89e5a67,-1,-1,SIFC_ARKANOID}, /* Arkanoid (J) */\r
204          {0x0f141525,-1,-1,SIFC_ARKANOID}, /* Arkanoid 2(J) */\r
205 \r
206    {0x912989dc,-1,-1,SIFC_FKB},  /* Playbox BASIC */\r
207    {0xf7606810,-1,-1,SIFC_FKB},  /* Family BASIC 2.0A */\r
208    {0x895037bc,-1,-1,SIFC_FKB},  /* Family BASIC 2.1a */\r
209    {0xb2530afc,-1,-1,SIFC_FKB},  /* Family BASIC 3.0 */\r
210 #if 0\r
211    {0x82f1fb96,-1,-1,SIFC_SUBORKB},  /* Subor 1.0 Russian */\r
212    {0xabb2f974,-1,-1,SIFC_SUBORKB},  /* Study and Game 32-in-1 */\r
213    {0xd5d6eac4,-1,-1,SIFC_SUBORKB},  /* Edu (As) */\r
214    {0x589b6b0d,-1,-1,SIFC_SUBORKB},  /* SuporV20 */\r
215      {0x5e073a1b,-1,-1,SIFC_SUBORKB},  /* Supor English (Chinese) */\r
216     {0x8b265862,-1,-1,SIFC_SUBORKB},\r
217    {0x41401c6d,-1,-1,SIFC_SUBORKB},  /* SuporV40 */\r
218      {0x41ef9ac4,-1,-1,SIFC_SUBORKB},\r
219      {0x368c19a8,-1,-1,SIFC_SUBORKB},   /* LIKO Study Cartridge */\r
220    {0x543ab532,-1,-1,SIFC_SUBORKB},   /* LIKO Color Lines */\r
221 #endif\r
222          {0,-1,-1,-1}\r
223         };\r
224  int x=0;\r
225 \r
226  while(moo[x].input1>=0 || moo[x].input2>=0 || moo[x].inputfc>=0)\r
227  {\r
228   if(moo[x].crc32==iNESGameCRC32)\r
229   {\r
230    FCEUGameInfo.input[0]=moo[x].input1;\r
231    FCEUGameInfo.input[1]=moo[x].input2;\r
232    FCEUGameInfo.inputfc=moo[x].inputfc;\r
233    break;\r
234   }\r
235   x++;\r
236  }\r
237 }\r
238 \r
239 #define INESB_INCOMPLETE  1\r
240 #define INESB_CORRUPT     2\r
241 #define INESB_HACKED      4\r
242 \r
243 struct BADINF {\r
244         uint64 md5partial;\r
245         char *name;\r
246         uint32 type;\r
247 };\r
248 \r
249 \r
250 static struct BADINF BadROMImages[]=\r
251 {\r
252  #include "ines-bad.h"\r
253 };\r
254 \r
255 void CheckBad(uint64 md5partial)\r
256 {\r
257  int x;\r
258 \r
259  x=0;\r
260  //printf("0x%llx\n",md5partial);\r
261  while(BadROMImages[x].name)\r
262  {\r
263   if(BadROMImages[x].md5partial == md5partial)\r
264   {\r
265    FCEU_PrintError("The copy game you have loaded, \"%s\", is bad, and will not work properly on FCE Ultra.", BadROMImages[x].name);\r
266    return;\r
267   }\r
268   x++;\r
269  }\r
270 \r
271 }\r
272 \r
273 \r
274 struct CHINF {\r
275         uint32 crc32;\r
276         int32 mapper;\r
277         int32 mirror;\r
278 };\r
279 \r
280 static void CheckHInfo(void)\r
281 {\r
282  /* ROM images that have the battery-backed bit set in the header that really\r
283     don't have battery-backed RAM is not that big of a problem, so I'll\r
284     treat this differently by only listing games that should have battery-backed RAM.\r
285 \r
286     Lower 64 bits of the MD5 hash.\r
287  */\r
288 \r
289  static uint64 savie[]=\r
290         {\r
291    0x498c10dc463cfe95LL,  /* Battle Fleet */\r
292    0x6917ffcaca2d8466LL,  /* Famista '90 */\r
293 \r
294          0xd63dcc68c2b20adcLL,    /* Final Fantasy J */\r
295          0x012df596e2b31174LL,    /* Final Fantasy 1+2 */\r
296          0xf6b359a720549ecdLL,    /* Final Fantasy 2 */\r
297          0x5a30da1d9b4af35dLL,    /* Final Fantasy 3 */\r
298 \r
299    0x2ee3417ba8b69706LL,  /* Hydlide 3*/\r
300 \r
301    0xebbce5a54cf3ecc0LL,  /* Justbreed */\r
302 \r
303    0x6a858da551ba239eLL,  /* Kaijuu Monogatari */\r
304    0xa40666740b7d22feLL,  /* Mindseeker */\r
305 \r
306          0x77b811b2760104b9LL,    /* Mouryou Senki Madara */\r
307 \r
308    0x11b69122efe86e8cLL,  /* RPG Jinsei Game */\r
309 \r
310    0xa70b495314f4d075LL,  /* Ys 3 */\r
311 \r
312 \r
313    0xc04361e499748382LL,  /* AD&D Heroes of the Lance */\r
314    0xb72ee2337ced5792LL,  /* AD&D Hillsfar */\r
315    0x2b7103b7a27bd72fLL,  /* AD&D Pool of Radiance */\r
316 \r
317          0x854d7947a3177f57LL,    /* Crystalis */\r
318 \r
319    0xb0bcc02c843c1b79LL,  /* DW */\r
320    0x4a1f5336b86851b6LL,  /* DW */\r
321 \r
322    0x2dcf3a98c7937c22LL,  /* DW 2 */\r
323    0x733026b6b72f2470LL,  /* Dw 3 */\r
324    0x98e55e09dfcc7533LL,  /* DW 4*/\r
325    0x8da46db592a1fcf4LL,  /* Faria */\r
326    0x91a6846d3202e3d6LL,  /* Final Fantasy */\r
327    0xedba17a2c4608d20LL,  /* ""    */\r
328 \r
329          0x94b9484862a26cbaLL,    /* Legend of Zelda */\r
330          0x04a31647de80fdabLL,    /*      ""      */\r
331 \r
332          0x9aa1dc16c05e7de5LL,    /* Startropics */\r
333          0x1b084107d0878bd0LL,    /* Startropics 2*/\r
334 \r
335          0x836c0ff4f3e06e45LL,    /* Zelda 2 */\r
336 \r
337    0      /* Abandon all hope if the game has 0 in the lower 64-bits of its MD5 hash */\r
338         };\r
339 \r
340  static struct CHINF moo[]=\r
341         {\r
342   #include "ines-correct.h"\r
343         };\r
344  int tofix=0;\r
345  int x;\r
346  uint64 partialmd5=0;\r
347 \r
348  for(x=0;x<8;x++)\r
349  {\r
350   partialmd5 |= (uint64)iNESCart.MD5[15-x] << (x*8);\r
351   //printf("%16llx\n",partialmd5);\r
352  }\r
353  CheckBad(partialmd5);\r
354 \r
355  x=0;\r
356 \r
357  do\r
358  {\r
359   if(moo[x].crc32==iNESGameCRC32)\r
360   {\r
361    if(moo[x].mapper>=0)\r
362    {\r
363     if(moo[x].mapper&0x800 && VROM_size)\r
364     {\r
365      VROM_size=0;\r
366      free(VROM);\r
367      VROM=0;\r
368      tofix|=8;\r
369     }\r
370     if(MapperNo!=(moo[x].mapper&0xFF))\r
371     {\r
372      tofix|=1;\r
373      MapperNo=moo[x].mapper&0xFF;\r
374     }\r
375    }\r
376    if(moo[x].mirror>=0)\r
377    {\r
378     if(moo[x].mirror==8)\r
379     {\r
380      if(Mirroring==2)  /* Anything but hard-wired(four screen). */\r
381      {\r
382       tofix|=2;\r
383       Mirroring=0;\r
384      }\r
385     }\r
386     else if(Mirroring!=moo[x].mirror)\r
387     {\r
388      if(Mirroring!=(moo[x].mirror&~4))\r
389       if((moo[x].mirror&~4)<=2)  /* Don't complain if one-screen mirroring\r
390                                    needs to be set(the iNES header can't\r
391                                    hold this information).\r
392                                 */\r
393        tofix|=2;\r
394      Mirroring=moo[x].mirror;\r
395     }\r
396    }\r
397    break;\r
398   }\r
399   x++;\r
400  } while(moo[x].mirror>=0 || moo[x].mapper>=0);\r
401 \r
402  x=0;\r
403  while(savie[x] != 0)\r
404  {\r
405   if(savie[x] == partialmd5)\r
406   {\r
407    if(!(head.ROM_type&2))\r
408    {\r
409     tofix|=4;\r
410     head.ROM_type|=2;\r
411    }\r
412   }\r
413   x++;\r
414  }\r
415 \r
416  /* Games that use these iNES mappers tend to have the four-screen bit set\r
417     when it should not be.\r
418  */\r
419  if((MapperNo==118 || MapperNo==24 || MapperNo==26) && (Mirroring==2))\r
420  {\r
421   Mirroring=0;\r
422   tofix|=2;\r
423  }\r
424 \r
425  /* Four-screen mirroring implicitly set. */\r
426  if(MapperNo==99)\r
427   Mirroring=2;\r
428 \r
429  if(tofix)\r
430  {\r
431   char gigastr[768];\r
432   strcpy(gigastr,"The iNES header contains incorrect information.  For now, the information will be corrected in RAM.  ");\r
433   if(tofix&1)\r
434    sprintf(gigastr+strlen(gigastr),"The mapper number should be set to %d.  ",MapperNo);\r
435   if(tofix&2)\r
436   {\r
437    char *mstr[3]={"Horizontal","Vertical","Four-screen"};\r
438    sprintf(gigastr+strlen(gigastr),"Mirroring should be set to \"%s\".  ",mstr[Mirroring&3]);\r
439   }\r
440   if(tofix&4)\r
441    strcat(gigastr,"The battery-backed bit should be set.  ");\r
442   if(tofix&8)\r
443    strcat(gigastr,"This game should not have any CHR ROM.  ");\r
444   strcat(gigastr,"\n");\r
445   FCEU_printf("%s",gigastr);\r
446  }\r
447 }\r
448 \r
449 typedef struct {\r
450         int mapper;\r
451         void (*init)(CartInfo *);\r
452 } NewMI;\r
453 \r
454 int iNESLoad(const char *name, int fp)\r
455 {\r
456         struct md5_context md5;\r
457 \r
458         if(FCEU_fread(&head,1,16,fp)!=16)\r
459          return 0;\r
460 \r
461         if(memcmp(&head,"NES\x1a",4))\r
462          return 0;\r
463 \r
464         memset(&iNESCart,0,sizeof(iNESCart));\r
465 \r
466         if(!memcmp((char *)(&head)+0x7,"DiskDude",8))\r
467         {\r
468          memset((char *)(&head)+0x7,0,0x9);\r
469         }\r
470 \r
471         if(!memcmp((char *)(&head)+0x7,"demiforce",9))\r
472         {\r
473          memset((char *)(&head)+0x7,0,0x9);\r
474         }\r
475 \r
476         if(!memcmp((char *)(&head)+0xA,"Ni03",4))\r
477         {\r
478          if(!memcmp((char *)(&head)+0x7,"Dis",3))\r
479           memset((char *)(&head)+0x7,0,0x9);\r
480          else\r
481           memset((char *)(&head)+0xA,0,0x6);\r
482         }\r
483 \r
484 //  int ROM_size=0;\r
485         if(!head.ROM_size)\r
486         {\r
487 //   FCEU_PrintError("No PRG ROM!");\r
488 //   return(0);\r
489    ROM_size=256;\r
490          //head.ROM_size++;\r
491         }\r
492   else\r
493    ROM_size=head.ROM_size;\r
494 \r
495 //    ROM_size = head.ROM_size;\r
496         VROM_size = head.VROM_size;\r
497         ROM_size=uppow2(ROM_size);\r
498 \r
499         if(VROM_size)\r
500          VROM_size=uppow2(VROM_size);\r
501 \r
502         MapperNo = (head.ROM_type>>4);\r
503         MapperNo|=(head.ROM_type2&0xF0);\r
504         Mirroring = (head.ROM_type&1);\r
505 \r
506         if(head.ROM_type&8) Mirroring=2;\r
507 \r
508         if(!(ROM=(uint8 *)FCEU_malloc(ROM_size<<14)))\r
509          return 0;\r
510 \r
511   if(VROM_size)\r
512          if(!(VROM=(uint8 *)FCEU_malloc(VROM_size<<13)))\r
513          {\r
514           free(ROM);\r
515           return 0;\r
516          }\r
517 \r
518         memset(ROM,0xFF,ROM_size<<14);\r
519         if(VROM_size) memset(VROM,0xFF,VROM_size<<13);\r
520   if(head.ROM_type&4)   /* Trainer */\r
521         {\r
522          trainerpoo=(uint8 *)FCEU_gmalloc(512);\r
523          FCEU_fread(trainerpoo,512,1,fp);\r
524         }\r
525 \r
526         ResetCartMapping();\r
527         ResetExState(0,0);\r
528 \r
529         SetupCartPRGMapping(0,ROM,ROM_size*0x4000,0);\r
530         SetupCartPRGMapping(1,WRAM,8192,1);\r
531 \r
532         FCEU_fread(ROM,0x4000,head.ROM_size,fp);\r
533 \r
534         if(VROM_size)\r
535          FCEU_fread(VROM,0x2000,head.VROM_size,fp);\r
536 \r
537         md5_starts(&md5);\r
538         md5_update(&md5,ROM,ROM_size<<14);\r
539 \r
540         iNESGameCRC32=CalcCRC32(0,ROM,ROM_size<<14);\r
541 \r
542         if(VROM_size)\r
543         {\r
544          iNESGameCRC32=CalcCRC32(iNESGameCRC32,VROM,VROM_size<<13);\r
545          md5_update(&md5,VROM,VROM_size<<13);\r
546         }\r
547         md5_finish(&md5,iNESCart.MD5);\r
548         memcpy(FCEUGameInfo.MD5,iNESCart.MD5,sizeof(iNESCart.MD5));\r
549 \r
550         iNESCart.CRC32=iNESGameCRC32;\r
551 \r
552         FCEU_printf(" PRG ROM:  %3d x 16KiB\n CHR ROM:  %3d x  8KiB\n ROM CRC32:  0x%08lx\n",\r
553                 head.ROM_size,head.VROM_size,iNESGameCRC32);\r
554 \r
555         {\r
556          int x;\r
557          FCEU_printf(" ROM MD5:  0x");\r
558          for(x=0;x<16;x++)\r
559           FCEU_printf("%02x",iNESCart.MD5[x]);\r
560          FCEU_printf("\n");\r
561         }\r
562         FCEU_printf(" Mapper:  %d\n Mirroring: %s\n", MapperNo,Mirroring==2?"None(Four-screen)":Mirroring?"Vertical":"Horizontal");\r
563         if(head.ROM_type&2) FCEU_printf(" Battery-backed.\n");\r
564         if(head.ROM_type&4) FCEU_printf(" Trained.\n");\r
565 \r
566         SetInput();\r
567         CheckHInfo();\r
568         {\r
569          int x;\r
570          uint64 partialmd5=0;\r
571 \r
572          for(x=0;x<8;x++)\r
573          {\r
574           partialmd5 |= (uint64)iNESCart.MD5[7-x] << (x*8);\r
575          }\r
576 \r
577          FCEU_VSUniCheck(partialmd5, &MapperNo, &Mirroring);\r
578         }\r
579         /* Must remain here because above functions might change value of\r
580            VROM_size and free(VROM).\r
581         */\r
582         if(VROM_size)\r
583          SetupCartCHRMapping(0,VROM,VROM_size*0x2000,0);\r
584 \r
585         if(Mirroring==2)\r
586          SetupCartMirroring(4,1,ExtraNTARAM);\r
587         else if(Mirroring>=0x10)\r
588          SetupCartMirroring(2+(Mirroring&1),1,0);\r
589         else\r
590          SetupCartMirroring(Mirroring&1,(Mirroring&4)>>2,0);\r
591 \r
592         iNESCart.battery=(head.ROM_type&2)?1:0;\r
593         iNESCart.mirror=Mirroring;\r
594 \r
595         //if(MapperNo != 18) {\r
596   //  if(ROM) free(ROM);\r
597   //  if(VROM) free(VROM);\r
598   //  ROM=VROM=0;\r
599   //  return(0);\r
600         // }\r
601 \r
602         if(NewiNES_Init(MapperNo))\r
603         {\r
604 \r
605         }\r
606         else\r
607         {\r
608          iNESCart.Power=iNESPower;\r
609          if(head.ROM_type&2)\r
610          {\r
611           iNESCart.SaveGame[0]=WRAM;\r
612           iNESCart.SaveGameLen[0]=8192;\r
613          }\r
614         }\r
615         FCEU_LoadGameSave(&iNESCart);\r
616 \r
617         GameInterface=iNESGI;\r
618         FCEU_printf("\n");\r
619 \r
620         // since apparently the iNES format doesn't store this information,\r
621         // guess if the settings should be PAL or NTSC from the ROM name\r
622         // TODO: MD5 check against a list of all known PAL games instead?\r
623         if(strstr(name,"(E)") || strstr(name,"(e)")\r
624         || strstr(name,"(F)") || strstr(name,"(f)")\r
625         || strstr(name,"(G)") || strstr(name,"(g)")\r
626         || strstr(name,"(I)") || strstr(name,"(i)"))\r
627                 FCEUI_SetVidSystem(1);\r
628         else\r
629                 FCEUI_SetVidSystem(0);\r
630 \r
631         return 1;\r
632 }\r
633 \r
634 void FASTAPASS(2) VRAM_BANK1(uint32 A, uint8 V)\r
635 {\r
636  V&=7;\r
637  PPUCHRRAM|=(1<<(A>>10));\r
638  CHRBankList[(A)>>10]=V;\r
639  VPage[(A)>>10]=&CHRRAM[V<<10]-(A);\r
640 }\r
641 \r
642 void FASTAPASS(2) VRAM_BANK4(uint32 A, uint32 V)\r
643 {\r
644  V&=1;\r
645  PPUCHRRAM|=(0xF<<(A>>10));\r
646  CHRBankList[(A)>>10]=(V<<2);\r
647  CHRBankList[((A)>>10)+1]=(V<<2)+1;\r
648  CHRBankList[((A)>>10)+2]=(V<<2)+2;\r
649  CHRBankList[((A)>>10)+3]=(V<<2)+3;\r
650  VPage[(A)>>10]=&CHRRAM[V<<10]-(A);\r
651 }\r
652 void FASTAPASS(2) VROM_BANK1(uint32 A,uint32 V)\r
653 {\r
654  setchr1(A,V);\r
655  CHRBankList[(A)>>10]=V;\r
656 }\r
657 \r
658 void FASTAPASS(2) VROM_BANK2(uint32 A,uint32 V)\r
659 {\r
660  setchr2(A,V);\r
661  CHRBankList[(A)>>10]=(V<<1);\r
662  CHRBankList[((A)>>10)+1]=(V<<1)+1;\r
663 }\r
664 \r
665 void FASTAPASS(2) VROM_BANK4(uint32 A, uint32 V)\r
666 {\r
667  setchr4(A,V);\r
668  CHRBankList[(A)>>10]=(V<<2);\r
669  CHRBankList[((A)>>10)+1]=(V<<2)+1;\r
670  CHRBankList[((A)>>10)+2]=(V<<2)+2;\r
671  CHRBankList[((A)>>10)+3]=(V<<2)+3;\r
672 }\r
673 \r
674 void FASTAPASS(1) VROM_BANK8(uint32 V)\r
675 {\r
676  setchr8(V);\r
677  CHRBankList[0]=(V<<3);\r
678  CHRBankList[1]=(V<<3)+1;\r
679  CHRBankList[2]=(V<<3)+2;\r
680  CHRBankList[3]=(V<<3)+3;\r
681  CHRBankList[4]=(V<<3)+4;\r
682  CHRBankList[5]=(V<<3)+5;\r
683  CHRBankList[6]=(V<<3)+6;\r
684  CHRBankList[7]=(V<<3)+7;\r
685 }\r
686 \r
687 void FASTAPASS(2) ROM_BANK8(uint32 A, uint32 V)\r
688 {\r
689  setprg8(A,V);\r
690  if(A>=0x8000)\r
691   PRGBankList[((A-0x8000)>>13)]=V;\r
692 }\r
693 \r
694 void FASTAPASS(2) ROM_BANK16(uint32 A, uint32 V)\r
695 {\r
696  setprg16(A,V);\r
697  if(A>=0x8000)\r
698  {\r
699   PRGBankList[((A-0x8000)>>13)]=V<<1;\r
700   PRGBankList[((A-0x8000)>>13)+1]=(V<<1)+1;\r
701  }\r
702 }\r
703 \r
704 void FASTAPASS(1) ROM_BANK32(uint32 V)\r
705 {\r
706  setprg32(0x8000,V);\r
707  PRGBankList[0]=V<<2;\r
708  PRGBankList[1]=(V<<2)+1;\r
709  PRGBankList[2]=(V<<2)+2;\r
710  PRGBankList[3]=(V<<2)+3;\r
711 }\r
712 \r
713 void FASTAPASS(1) onemir(uint8 V)\r
714 {\r
715         if(Mirroring==2) return;\r
716         if(V>1)\r
717          V=1;\r
718         Mirroring=0x10|V;\r
719         setmirror(MI_0+V);\r
720 }\r
721 \r
722 void FASTAPASS(1) MIRROR_SET2(uint8 V)\r
723 {\r
724         if(Mirroring==2) return;\r
725         Mirroring=V;\r
726         setmirror(V);\r
727 }\r
728 \r
729 void FASTAPASS(1) MIRROR_SET(uint8 V)\r
730 {\r
731         if(Mirroring==2) return;\r
732         V^=1;\r
733         Mirroring=V;\r
734         setmirror(V);\r
735 }\r
736 \r
737 static void NONE_init(void)\r
738 {\r
739         ROM_BANK16(0x8000,0);\r
740         ROM_BANK16(0xC000,~0);\r
741 \r
742         if(VROM_size)\r
743          VROM_BANK8(0);\r
744         else\r
745          setvram8(CHRRAM);\r
746 }\r
747 \r
748 void (*MapInitTab[256])(void)=\r
749 {\r
750     0,0,\r
751 //    Mapper2_init,Mapper3_init,\r
752     0,0,\r
753     0,0,\r
754     Mapper6_init,Mapper7_init,Mapper8_init,Mapper9_init,\r
755     Mapper10_init,Mapper11_init,\r
756     0,\r
757 //    Mapper13_init,\r
758     0,\r
759     0,\r
760     Mapper15_init,Mapper16_init,Mapper17_init,Mapper18_init,\r
761     0,0,\r
762         Mapper21_init,Mapper22_init,Mapper23_init,Mapper24_init,\r
763     Mapper25_init,Mapper26_init,Mapper27_init,\r
764     0,0,0,0,\r
765     Mapper32_init,Mapper33_init,Mapper34_init,\r
766     0,0,0,0,0,\r
767     Mapper40_init,Mapper41_init,Mapper42_init,Mapper43_init,\r
768     0,0,\r
769     Mapper46_init,\r
770     0,\r
771     Mapper48_init,\r
772     0,\r
773     Mapper50_init,Mapper51_init,\r
774     0,0,0,0,0,\r
775     Mapper57_init,Mapper58_init,Mapper59_init,Mapper60_init,\r
776     Mapper61_init,Mapper62_init,\r
777     0,\r
778     Mapper64_init,Mapper65_init,Mapper66_init,Mapper67_init,\r
779     Mapper68_init,Mapper69_init,Mapper70_init,Mapper71_init,\r
780     Mapper72_init,Mapper73_init,\r
781     0,\r
782     Mapper75_init,Mapper76_init,Mapper77_init,Mapper78_init,\r
783     Mapper79_init,Mapper80_init,\r
784     0,\r
785     Mapper82_init,Mapper83_init,\r
786     0,\r
787         Mapper85_init,Mapper86_init,Mapper87_init,Mapper88_init,\r
788     Mapper89_init,\r
789     0,\r
790     Mapper91_init,Mapper92_init,Mapper93_init,Mapper94_init,\r
791     0,\r
792     Mapper96_init,Mapper97_init,\r
793     0,\r
794     Mapper99_init,\r
795     0,0,0,0,0,0,0,\r
796     Mapper107_init,\r
797     0,0,0,0,\r
798     0,Mapper113_init,\r
799     0,0,0,\r
800     Mapper117_init,\r
801     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\r
802     Mapper140_init,\r
803     0,0,0,\r
804     Mapper144_init,\r
805     0,0,0,0,0,0,\r
806     Mapper151_init,Mapper152_init,Mapper153_init,Mapper154_init,\r
807     0,\r
808     Mapper156_init,Mapper157_init,Mapper158_init,0,\r
809     0,0,0,0,0,0,\r
810     Mapper166_init,Mapper167_init,\r
811     0,0,0,0,0,0,0,0,0,0,0,0,\r
812     Mapper180_init,\r
813     0,0,0,\r
814     Mapper184_init,Mapper185_init,\r
815     0,0,0,\r
816     Mapper189_init,\r
817     0,\r
818 //    Mapper191_init,\r
819     0,\r
820     0,\r
821     Mapper193_init,\r
822     0,0,0,0,0,0,\r
823     Mapper200_init,Mapper201_init,Mapper202_init,Mapper203_init,\r
824     Mapper204_init,\r
825     0,0,\r
826     Mapper207_init,\r
827     0,0,0,\r
828     Mapper211_init,Mapper212_init,Mapper213_init,Mapper214_init,\r
829     0,0,0,0,0,0,0,0,0,0,\r
830     Mapper225_init,Mapper226_init,Mapper227_init,Mapper228_init,\r
831     Mapper229_init,Mapper230_init,Mapper231_init,Mapper232_init,\r
832     0,\r
833     Mapper234_init,Mapper235_init,\r
834     0,0,0,0,\r
835     Mapper240_init,Mapper241_init,Mapper242_init,0,\r
836     Mapper244_init,\r
837     0,\r
838     Mapper246_init,\r
839     0,0,0,0,0,0,0,0,\r
840     Mapper255_init\r
841 };\r
842 \r
843 static DECLFW(BWRAM)\r
844 {\r
845                 WRAM[A-0x6000]=V;\r
846 }\r
847 \r
848 static DECLFR(AWRAM)\r
849 {\r
850                 return WRAM[A-0x6000];\r
851 }\r
852 \r
853 #ifdef DEBUG_MAPPER\r
854 static DECLFW(WriteHandler)\r
855 {\r
856  FCEU_printf("$%04x:$%02x\n",A,V);\r
857 }\r
858 #endif\r
859 \r
860 void (*MapStateRestore)(int version);\r
861 void iNESStateRestore(int version)\r
862 {\r
863  int x;\r
864 \r
865  if(!MapperNo) return;\r
866 \r
867  for(x=0;x<4;x++)\r
868   setprg8(0x8000+x*8192,PRGBankList[x]);\r
869 \r
870  if(VROM_size)\r
871   for(x=0;x<8;x++)\r
872     setchr1(0x400*x,CHRBankList[x]);\r
873 \r
874 if(0) switch(Mirroring)\r
875  {\r
876    case 0:setmirror(MI_H);break;\r
877    case 1:setmirror(MI_V);break;\r
878    case 0x12:\r
879    case 0x10:setmirror(MI_0);break;\r
880    case 0x13:\r
881    case 0x11:setmirror(MI_1);break;\r
882  }\r
883  if(MapStateRestore) MapStateRestore(version);\r
884 }\r
885 \r
886 static void iNESPower(void)\r
887 {\r
888         int x;\r
889         int type=MapperNo;\r
890 \r
891         SetReadHandler(0x8000,0xFFFF,CartBR);\r
892         GameStateRestore=iNESStateRestore;\r
893         MapClose=0;\r
894         MapperReset=0;\r
895         MapStateRestore=0;\r
896 \r
897         setprg8r(1,0x6000,0);\r
898 \r
899         SetReadHandler(0x6000,0x7FFF,AWRAM);\r
900         SetWriteHandler(0x6000,0x7FFF,BWRAM);\r
901         FCEU_CheatAddRAM(8,0x6000,WRAM);\r
902 \r
903     #ifdef DEBUG_MAPPER\r
904     if(type==0) SetWriteHandler(0x4020,0xFFFF,WriteHandler);\r
905     #endif\r
906 \r
907         /* This statement represents atrocious code.  I need to rewrite\r
908            all of the iNES mapper code... */\r
909         IRQCount=IRQLatch=IRQa=0;\r
910         if(head.ROM_type&2)\r
911          memset(GameMemBlock+8192,0,sizeof(GameMemBlock)-8192);\r
912         else\r
913          memset(GameMemBlock,0,sizeof(GameMemBlock));\r
914 \r
915         NONE_init();\r
916 \r
917         ResetExState(0,0);\r
918         if(FCEUGameInfo.type == GIT_VSUNI)\r
919          AddExState(FCEUVSUNI_STATEINFO, ~0, 0, 0);\r
920 \r
921         AddExState(WRAM, 8192, 0, "WRAM");\r
922         if(type==19 || type==6 || type==69 || type==85 || type==96)\r
923          AddExState(MapperExRAM, 32768, 0, "MEXR");\r
924     if((!VROM_size || type==6 || type==19) && (type!=13 && type!=96))\r
925          AddExState(CHRRAM, 8192, 0, "CHRR");\r
926         if(head.ROM_type&8)\r
927          AddExState(ExtraNTARAM, 2048, 0, "EXNR");\r
928 \r
929         /* Exclude some mappers whose emulation code handle save state stuff\r
930            themselves. */\r
931         if(type && type!=13 && type!=96)\r
932         {\r
933          AddExState(mapbyte1, 32, 0, "MPBY");\r
934          AddExState(&Mirroring, 1, 0, "MIRR");\r
935          AddExState(&IRQCount, 4, 1, "IRQC");\r
936          AddExState(&IRQLatch, 4, 1, "IQL1");\r
937          AddExState(&IRQa, 1, 0, "IRQA");\r
938          AddExState(PRGBankList, 4, 0, "PBL");\r
939          for(x=0;x<8;x++)\r
940          {\r
941           char tak[8];\r
942           sprintf(tak,"CBL%d",x);\r
943           AddExState(&CHRBankList[x], 2, 1,tak);\r
944          }\r
945         }\r
946 \r
947         if(MapInitTab[type]) MapInitTab[type]();\r
948         else if(type)\r
949         {\r
950          FCEU_PrintError("iNES mapper #%d is not supported at all.",type);\r
951         }\r
952 }\r
953 \r
954 \r
955 typedef struct {\r
956            int number;\r
957            void (*init)(CartInfo *);\r
958 } BMAPPING;\r
959 \r
960 static BMAPPING bmap[] = {\r
961     {1,   Mapper1_Init},\r
962     {2,   UNROM_Init},\r
963     {3,   CNROM_Init},\r
964     {4,   Mapper4_Init},\r
965     {5,   Mapper5_Init},\r
966     {12,  Mapper12_Init},\r
967     {13,  CPROM_Init},\r
968     {19,  Mapper19_Init},\r
969     {44,  Mapper44_Init},\r
970     {45,  Mapper45_Init},\r
971     {47,  Mapper47_Init},\r
972     {49,  Mapper49_Init},\r
973     {52,  Mapper52_Init},\r
974     {74,  Mapper74_Init},\r
975     {90,  Mapper90_Init},\r
976     {95,  Mapper95_Init},\r
977     {105, Mapper105_Init},\r
978     {112, Mapper112_Init},\r
979     {114, Mapper114_Init},\r
980         {115, Mapper115_Init},\r
981         {116, Mapper116_Init},\r
982         {118, Mapper118_Init},\r
983     {119, Mapper119_Init},\r
984     {133, SA72008_Init},\r
985     {137, S8259D_Init},\r
986     {138, S8259B_Init},\r
987     {139, S8259C_Init},\r
988     {141, S8259A_Init},\r
989     {143, TCA01_Init},\r
990     {145, SA72007_Init},\r
991     {146, SA0161M_Init},\r
992     {147, TCU01_Init},\r
993     {148, SA0037_Init},\r
994     {149, SA0036_Init},\r
995     {150, S74LS374N_Init},\r
996         {155, Mapper155_Init},\r
997     {160, Mapper90_Init},\r
998     {163, Mapper163_Init},\r
999         {164, Mapper164_Init},\r
1000     {165, Mapper165_Init},\r
1001     {182, Mapper182_Init},\r
1002     {183, Mapper183_Init},\r
1003     {186, Mapper186_Init},\r
1004         {187, Mapper187_Init},\r
1005         {188, Mapper188_Init},\r
1006     {191, Mapper191_Init},\r
1007     {205, Mapper205_Init},\r
1008     {206, DEIROM_Init},\r
1009         {208, Mapper208_Init},\r
1010     {209, Mapper209_Init},\r
1011         {210, Mapper210_Init},\r
1012     {215, Mapper215_Init},\r
1013     {216, Mapper216_Init},\r
1014     {217, Mapper217_Init},\r
1015     {243, S74LS374NA_Init},\r
1016         {245, Mapper245_Init},\r
1017         {249, Mapper249_Init},\r
1018         {250, Mapper250_Init},\r
1019     {254, Mapper254_Init},\r
1020     {  0,        0}\r
1021 };\r
1022 \r
1023 static int NewiNES_Init(int num)\r
1024 {\r
1025  BMAPPING *tmp=bmap;\r
1026 \r
1027  if(FCEUGameInfo.type == GIT_VSUNI)\r
1028   AddExState(FCEUVSUNI_STATEINFO, ~0, 0, 0);\r
1029 \r
1030  while(tmp->init)\r
1031  {\r
1032   if(num==tmp->number)\r
1033   {\r
1034    UNIFchrrama=0; // need here for compatibility with UNIF mapper code\r
1035    if(!VROM_size)\r
1036    {\r
1037     int CHRRAMSize;\r
1038     if(num==13)\r
1039       CHRRAMSize=16384;\r
1040     else\r
1041       CHRRAMSize=8192;\r
1042     VROM=(uint8 *)malloc(CHRRAMSize);\r
1043     UNIFchrrama=VROM;\r
1044     SetupCartCHRMapping(0,VROM,CHRRAMSize,1);\r
1045     AddExState(VROM,CHRRAMSize, 0, "CHRR");\r
1046    }\r
1047    if(head.ROM_type&8)\r
1048     AddExState(ExtraNTARAM, 2048, 0, "EXNR");\r
1049    tmp->init(&iNESCart);\r
1050    return(1);\r
1051   }\r
1052   tmp++;\r
1053  }\r
1054  return(0);\r
1055 }\r