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