1 /* Mednafen - Multi-system Emulator
2  *
3  * Copyright notice for this file:
4  *  Copyright (C) 1998 BERO
5  *  Copyright (C) 2002 Xodnizel
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 "nes.h"
23 
24 #include <zlib.h>
25 
26 #include "x6502.h"
27 #include "cart.h"
28 #include "ppu/ppu.h"
29 
30 #define INESPRIV
31 #include "ines.h"
32 #include "unif.h"
33 #include "vsuni.h"
34 #include "input.h"
35 
36 namespace MDFN_IEN_NES
37 {
38 
39 static uint8 ExtraNTARAM[0x800];
40 static uint32 CHRRAMSize;
41 
42 static uint8 trainerpoo[512], TrainerRAM[512];
43 static uint8 *WRAM = NULL; // External RAM used for ROM images using mappers that nominally don't support external RAM
44 static uint8 *ROM = NULL;
45 static uint8 *VROM = NULL;
46 static CartInfo iNESCart;
47 
48 static int Mirroring;
49 
50 static uint32 ROM_size;
51 static uint32 VROM_size;
52 
53 static void NewiNES_Init(int num) MDFN_COLD;
54 
55 static int MapperNo;
56 
57 static iNES_HEADER head;
58 
DECLFR(TrainerRead)59 static DECLFR(TrainerRead)
60 {
61  return(TrainerRAM[A&0x1FF]);
62 }
63 
DECLFW(TrainerWrite)64 static DECLFW(TrainerWrite)
65 {
66  TrainerRAM[A & 0x1FF] = V;
67 }
68 
iNES_StateAction(StateMem * sm,const unsigned load,const bool data_only)69 static void iNES_StateAction(StateMem *sm, const unsigned load, const bool data_only)
70 {
71  SFORMAT StateRegs[] =
72  {
73   SFPTR8(ExtraNTARAM, head.ROM_type & 8 ? 2048 : 0),
74   SFPTR8(VROM, VROM_size ? 0 : CHRRAMSize),
75   SFPTR8(TrainerRAM, (head.ROM_type & 4) ? 0x200 : 0),
76   SFPTR8(WRAM, WRAM ? 8192 : 0),
77   SFEND
78  };
79 
80  if(NESIsVSUni)
81   MDFNNES_VSUNIStateAction(sm,load, data_only);
82 
83  if(head.ROM_type & 8 || !VROM_size)
84   MDFNSS_StateAction(sm, load, data_only, StateRegs, "iNES");
85 
86  if(iNESCart.StateAction)	// Call after loading/saving VS Uni and iNES sections.
87   iNESCart.StateAction(sm, load, data_only);
88 }
iNESFree(void)89 static MDFN_COLD void iNESFree(void)
90 {
91 	if(ROM)
92 	{
93 	 delete[] ROM;
94 	 ROM = NULL;
95 	}
96 
97 	if(VROM)
98 	{
99 	 delete[] VROM;
100 	 VROM = NULL;
101 	}
102 
103 	if(WRAM)
104 	{
105 	 delete[] WRAM;
106 	 WRAM = NULL;
107 	}
108 }
109 
iNES_Reset(void)110 static MDFN_COLD void iNES_Reset(void)
111 {
112         if(head.ROM_type & 4)
113          memcpy(TrainerRAM, trainerpoo, 512);
114 
115 	if(iNESCart.Reset)
116 	 iNESCart.Reset(&iNESCart);
117 }
118 
iNES_Power(void)119 static MDFN_COLD void iNES_Power(void)
120 {
121 	if(!VROM_size)
122 	 memset(VROM, 0xFF, CHRRAMSize);
123 
124 	if(head.ROM_type & 8)
125 	 memset(ExtraNTARAM, 0xFF, 2048);
126 
127         if(head.ROM_type & 4)
128          memcpy(TrainerRAM, trainerpoo, 512);
129 
130 	if(WRAM)
131 	 setprg8r(0x10, 0x6000, 0);
132 
133 	if(iNESCart.Power)
134 	 iNESCart.Power(&iNESCart);
135 }
136 
iNES_SaveNV(void)137 static void iNES_SaveNV(void)
138 {
139 	MDFN_SaveGameSave(&iNESCart);
140 }
141 
iNES_Kill(void)142 static MDFN_COLD void iNES_Kill(void)
143 {
144 	if(iNESCart.Close) iNESCart.Close();
145 
146 	iNESFree();
147 }
148 
149 #ifdef WANT_DEBUGGER
iNES_GetAddressSpaceBytes(const char * name,uint32 Address,uint32 Length,uint8 * Buffer)150 static void iNES_GetAddressSpaceBytes(const char *name, uint32 Address, uint32 Length, uint8 *Buffer)
151 {
152  if(!strcmp(name, "prgrom"))
153  {
154   while(Length--)
155   {
156    Address &= (ROM_size << 14) - 1;
157    *Buffer = ROM[Address];
158    Address++;
159    Buffer++;
160   }
161  }
162  else if(!strcmp(name, "chrrom") && VROM_size)
163  {
164   while(Length--)
165   {
166    Address &= (VROM_size << 13) - 1;
167    *Buffer = VROM[Address];
168    Address++;
169    Buffer++;
170   }
171  }
172  else if(!strcmp(name, "chrram") && !VROM_size && CHRRAMSize)
173  {
174   while(Length--)
175   {
176    Address &= CHRRAMSize - 1;
177    *Buffer = VROM[Address];
178    Address++;
179    Buffer++;
180   }
181  }
182  else if(!strcmp(name, "wram") && WRAM)
183  {
184   while(Length--)
185   {
186    Address &= 0x1FFF;
187    *Buffer = WRAM[Address];
188    Address++;
189    Buffer++;
190   }
191  }
192 }
193 
iNES_PutAddressSpaceBytes(const char * name,uint32 Address,uint32 Length,uint32 Granularity,bool hl,const uint8 * Buffer)194 static void iNES_PutAddressSpaceBytes(const char *name, uint32 Address, uint32 Length, uint32 Granularity, bool hl, const uint8 *Buffer)
195 {
196  if(!strcmp(name, "prgrom"))
197  {
198   while(Length--)
199   {
200    Address &= (ROM_size << 14) - 1;
201    ROM[Address] = *Buffer;
202    Address++;
203    Buffer++;
204   }
205  }
206  else if(!strcmp(name, "chrrom") && VROM_size)
207  {
208   while(Length--)
209   {
210    Address &= (VROM_size << 13) - 1;
211    VROM[Address] = *Buffer;
212    Address++;
213    Buffer++;
214   }
215  }
216  else if(!strcmp(name, "chrram") && !VROM_size && CHRRAMSize)
217  {
218   while(Length--)
219   {
220    Address &= CHRRAMSize - 1;
221    VROM[Address] = *Buffer;
222    Address++;
223    Buffer++;
224   }
225  }
226  else if(!strcmp(name, "wram") && WRAM)
227  {
228   while(Length--)
229   {
230    Address &= 0x1FFF;
231    WRAM[Address] = *Buffer;
232    Address++;
233    Buffer++;
234   }
235  }
236 }
237 #endif
238 
239 
240 uint32 iNESGameCRC32;
241 
SetInput(void)242 static void SetInput(void)
243 {
244  static const struct
245  {
246   uint32 crc32;
247   const char* input1;
248   const char* input2;
249   const char* inputfc;
250  } InputDB[]=
251  {
252 	 {0x62c67984, "gamepad", "gamepad", "4player" },	// Nekketsu Koukou Dodgeball-bu
253 
254          {0x3a1694f9,"gamepad","gamepad","4player"},       /* Nekketsu Kakutou Densetsu */
255 
256 	 {0xc3c0811d,"gamepad","gamepad","oekakids"},	/* The two "Oeka Kids" games */
257 	 {0x9d048ea4,"gamepad","gamepad","oekakids"},	/*			     */
258 
259 	 {0xaf4010ea,"gamepad","powerpadb", NULL},	/* World Class Track Meet */
260 	 {0xd74b2719,"gamepad","powerpadb", NULL},	/* Super Team Games */
261 	 {0x61d86167,"gamepad","powerpadb", NULL},	/* Street Cop */
262 	 {0x6435c095,"gamepad","powerpadb", NULL},	    /* Short Order/Eggsplode */
263 
264 
265 	 {0x48ca0ee1,"gamepad","gamepad", "bworld"},    /* Barcode World */
266 	 {0x9f8f200a,"gamepad","gamepad","ftrainera"}, /* Super Mogura Tataki!! - Pokkun Moguraa */
267 	 {0x9044550e,"gamepad","gamepad","ftrainera"}, /* Rairai Kyonshizu */
268 	 {0x2f128512,"gamepad","gamepad","ftrainera"}, /* Jogging Race */
269 	 {0x60ad090a,"gamepad","gamepad","ftrainera"}, /* Athletic World */
270 
271 	 {0x8a12a7d9,"gamepad","gamepad","ftrainerb"}, /* Totsugeki Fuuun Takeshi Jou */
272 	 {0xea90f3e2,"gamepad","gamepad","ftrainerb"}, /* Running Stadium */
273 	 {0x370ceb65,"gamepad","gamepad","ftrainerb"}, /* Meiro Dai Sakusen */
274 	 // Bad dump? {0x69ffb014,"gamepad","gamepad","ftrainerb"}, /* Fuun Takeshi Jou 2 */
275 	 {0x6cca1c1f,"gamepad","gamepad","ftrainerb"}, /* Dai Undoukai */
276 	 {0x29de87af,"gamepad","gamepad","ftrainerb"},  /* Aerobics Studio */
277          {0xbba58be5,"gamepad","gamepad","ftrainerb"},  /* Family Trainer: Manhattan Police */
278 	 {0xea90f3e2,"gamepad","gamepad","ftrainerb"},  /* Family Trainer:  Running Stadium */
279 
280 	 {0xd9f45be9,"gamepad","gamepad","partytap"},  /* Gimme a Break ... */
281 	 {0x1545bd13,"gamepad","gamepad","partytap"},  /* Gimme a Break ... 2 */
282 
283 	 {0x7b44fb2a,"gamepad","gamepad","mahjong"},  /* Ide Yousuke Meijin no Jissen Mahjong 2 */
284 	 {0x9fae4d46,"gamepad","gamepad","mahjong"},  /* Ide Yousuke Meijin no Jissen Mahjong */
285 
286 	 {0x980be936,"gamepad","gamepad","hypershot"}, /* Hyper Olympic */
287 	 {0x21f85681,"gamepad","gamepad","hypershot"}, /* Hyper Olympic (Gentei Ban) */
288 	 {0x915a53a7,"gamepad","gamepad","hypershot"}, /* Hyper Sports */
289 	 {0xad9c63e2,"gamepad",NULL,"shadow"},	/* Space Shadow */
290 
291 	 {0x4d68cfb1, NULL, "zapper", "none"},	/* Crime Busters */
292 	 {0xbbe40dc4,NULL,"zapper", "none"},	/* Baby Boomer */
293 	 {0x24598791,NULL,"zapper", "none"},	/* Duck Hunt */
294 	 {0xff24d794,NULL,"zapper", "none"},   /* Hogan's Alley */
295 	 {0xbeb8ab01,NULL,"zapper", "none"},	/* Gumshoe */
296 	 {0xde8fd935,NULL,"zapper", "none"},	/* To the Earth */
297 	 {0xedc3662b,NULL,"zapper", "none"},	/* Operation Wolf */
298 	 {0x2a6559a1,NULL,"zapper", "none"},	/* Operation Wolf (J) */
299 
300 	 {0x23d17f5e,"gamepad","zapper", "none"},	/* The Lone Ranger */
301 	 {0xb8b9aca3,NULL,"zapper", "none"},  /* Wild Gunman */
302 	 {0x5112dc21,NULL,"zapper", "none"},  /* Wild Gunman */
303 	 {0x4318a2f8,NULL,"zapper", "none"},  /* Barker Bill's Trick Shooting */
304 	 {0x5ee6008e,NULL,"zapper", "none"},  /* Mechanized Attack */
305 	 {0x3e58a87e,NULL,"zapper", "none"},  /* Freedom Force */
306 	 {0x851eb9be,"gamepad","zapper", "none"},	/* Shooting Range */
307 	 {0x74bea652,"gamepad","zapper", "none"},	/* Supergun 3-in-1 */
308 	 {0x32fb0583,NULL,"arkanoid","none"}, /* Arkanoid(NES) */
309 	 {0xd89e5a67,NULL,NULL,"arkanoid"}, /* Arkanoid (J) */
310 	 {0x0f141525,NULL,NULL,"arkanoid"}, /* Arkanoid 2(J) */
311 
312 	 {0x912989dc,NULL,NULL,"fkb"},	/* Playbox BASIC */
313 	 {0xf7606810,NULL,NULL,"fkb"},	/* Family BASIC 2.0A */
314 	 {0x895037bc,NULL,NULL,"fkb"},	/* Family BASIC 2.1a */
315 	 {0xb2530afc,NULL,NULL,"fkb"},	/* Family BASIC 3.0 */
316  };
317 
318  for(auto const& moo : InputDB)
319  {
320   if(moo.crc32 == iNESGameCRC32)
321   {
322    MDFNGameInfo->DesiredInput.clear();
323    MDFNGameInfo->DesiredInput.push_back(moo.input1);
324    MDFNGameInfo->DesiredInput.push_back(moo.input2);
325    MDFNGameInfo->DesiredInput.push_back("gamepad");
326    MDFNGameInfo->DesiredInput.push_back("gamepad");
327    MDFNGameInfo->DesiredInput.push_back(moo.inputfc);
328    break;
329   }
330  }
331 }
332 
CheckBad(uint64 md5partial)333 void CheckBad(uint64 md5partial)
334 {
335  #define INESB_INCOMPLETE        1
336  #define INESB_CORRUPT           2
337  #define INESB_HACKED            4
338  static const struct
339  {
340   uint64 md5partial;
341   const char* name;
342   uint32 type;
343  } BadROMImages[]=
344  {
345   #include "ines-bad.inc"
346  };
347 
348  for(auto const& bade : BadROMImages)
349  {
350   if(bade.md5partial == md5partial)
351   {
352    MDFN_Notify(MDFN_NOTICE_ERROR, _("The copy of the game you have loaded, \"%s\", is bad, and will not work properly on Mednafen."), bade.name);
353    return;
354   }
355  }
356 }
357 
358 struct CHINF {
359         uint32 crc32;
360         int32 mapper;
361         int32 mirror;
362 	uint64 pmd5;
363 };
364 
CheckHInfo(void)365 static void CheckHInfo(void)
366 {
367  /* ROM images that have the battery-backed bit set in the header that really
368     don't have battery-backed RAM is not that big of a problem, so I'll
369     treat this differently by only listing games that should have battery-backed RAM.
370 
371     Lower 64 bits of the MD5 hash.
372  */
373 
374  static const uint64 savie[]=
375  {
376 	 0x58abd7c8990c4e25ULL, /* Taito Grand Prix - Eikou e no License */
377 	 0x82000965f04a71bbULL, /* Mirai Shinwa Jarvas */
378 	 0x38ed9483242b252dULL, /* Honoo no Toukyuuji - Dodge Danpei 2 */
379 	 0x01c6be88b105e2dbULL,	/* Barcode World */
380 
381          0x498c10dc463cfe95ULL,  /* Battle Fleet */
382          0x6917ffcaca2d8466ULL,  /* Famista '90 */
383 
384          0xd63dcc68c2b20adcULL,    /* Final Fantasy J */
385          0x012df596e2b31174ULL,    /* Final Fantasy 1+2 */
386          0xf6b359a720549ecdULL,    /* Final Fantasy 2 */
387          0x5a30da1d9b4af35dULL,    /* Final Fantasy 3 */
388 
389          0x2ee3417ba8b69706ULL,  /* Hydlide 3*/
390 
391          0xebbce5a54cf3ecc0ULL,  /* Justbreed */
392 
393          0x6a858da551ba239eULL,  /* Kaijuu Monogatari */
394          0xa40666740b7d22feULL,  /* Mindseeker */
395 
396          0x77b811b2760104b9ULL,    /* Mouryou Senki Madara */
397 
398          0x11b69122efe86e8cULL,  /* RPG Jinsei Game */
399 
400          0xa70b495314f4d075ULL,  /* Ys 3 */
401 
402 
403          0xc04361e499748382ULL,  /* AD&D Heroes of the Lance */
404          0xb72ee2337ced5792ULL,  /* AD&D Hillsfar */
405          0x2b7103b7a27bd72fULL,  /* AD&D Pool of Radiance */
406 
407          0x854d7947a3177f57ULL,    /* Crystalis */
408 
409          0xb0bcc02c843c1b79ULL,  /* DW */
410          0x4a1f5336b86851b6ULL,  /* DW */
411 
412          0x2dcf3a98c7937c22ULL,  /* DW 2 */
413          0x733026b6b72f2470ULL,  /* Dw 3 */
414          0x98e55e09dfcc7533ULL,  /* DW 4*/
415          0x8da46db592a1fcf4ULL,  /* Faria */
416          0x91a6846d3202e3d6ULL,  /* Final Fantasy */
417          0xedba17a2c4608d20ULL,  /* ""           */
418 
419          0x94b9484862a26cbaULL,    /* Legend of Zelda */
420          0x04a31647de80fdabULL,    /*      ""      */
421 
422          0x9aa1dc16c05e7de5ULL,    /* Startropics */
423          0x1b084107d0878bd0ULL,    /* Startropics 2*/
424 
425          0x836c0ff4f3e06e45ULL,    /* Zelda 2 */
426 
427          0                      /* Abandon all hope if the game has 0 in the lower 64-bits of its MD5 hash */
428  };
429 
430  static struct CHINF moo[]=
431  {
432   #include "ines-correct.inc"
433  };
434  int tofix=0;
435  int x;
436  uint64 partialmd5=0;
437 
438  for(x=0;x<8;x++)
439  {
440   partialmd5 |= (uint64)iNESCart.MD5[15-x] << (x*8);
441   //printf("%16llx\n", partialmd5);
442  }
443  CheckBad(partialmd5);
444  x=0;
445 
446  do
447  {
448   if((moo[x].crc32 && moo[x].crc32 == iNESGameCRC32) || (moo[x].pmd5 && moo[x].pmd5 == partialmd5))
449   {
450    if(moo[x].mapper >= 0)
451    {
452     if((moo[x].mapper & 0x800) && VROM_size)
453     {
454      VROM_size=0;
455      delete[] VROM;
456      VROM = NULL;
457      tofix|=8;
458     }
459     if(MapperNo != (moo[x].mapper & 0xFF))
460     {
461      tofix|=1;
462      MapperNo=moo[x].mapper&0xFF;
463     }
464    }
465    if(moo[x].mirror>=0)
466    {
467     if(moo[x].mirror==8)
468     {
469      if(Mirroring==2)   /* Anything but hard-wired(four screen). */
470      {
471       tofix|=2;
472       Mirroring=0;
473      }
474     }
475     else if(Mirroring!=moo[x].mirror)
476     {
477      if(Mirroring!=(moo[x].mirror&~4))
478       if((moo[x].mirror&~4)<=2) /* Don't complain if one-screen mirroring
479                                    needs to be set(the iNES header can't
480                                    hold this information).
481                                 */
482        tofix|=2;
483      Mirroring=moo[x].mirror;
484     }
485    }
486    break;
487   }
488   x++;
489  } while(moo[x].mirror>=0 || moo[x].mapper>=0);
490 
491  x=0;
492  while(savie[x] != 0)
493  {
494   if(savie[x] == partialmd5)
495   {
496    if(!(head.ROM_type&2))
497    {
498     tofix|=4;
499     head.ROM_type|=2;
500    }
501   }
502   x++;
503  }
504 
505  /* Games that use these iNES mappers tend to have the four-screen bit set
506     when it should not be.
507  */
508  if((MapperNo==118 || MapperNo==24 || MapperNo==26) && (Mirroring==2))
509  {
510   Mirroring=0;
511   tofix|=2;
512  }
513 
514  /* Four-screen mirroring implicitly set. */
515  if(MapperNo==99)
516   Mirroring=2;
517 
518  if(tofix)
519  {
520   MDFN_printf(_("The iNES header contains incorrect information.  For now, the information will be corrected in RAM:\n"));
521   MDFN_indent(1);
522   if(tofix&1)
523    MDFN_printf(_("The mapper number should be set to %d.\n"), MapperNo);
524 
525   if(tofix&2)
526   {
527    const char *mstr[3] = {
528 			  _("Horizontal"), _("Vertical"), _("Four-screen")
529 		 	 };
530    MDFN_printf(_("Mirroring should be set to \"%s\".\n"), mstr[Mirroring & 3]);
531   }
532   if(tofix&4)
533   {
534    MDFN_printf(_("The battery-backed bit should be set.\n"));
535   }
536   if(tofix&8)
537   {
538    MDFN_printf(_("This game should not have any CHR ROM.  "));
539   }
540   MDFN_indent(-1);
541  }
542 }
543 
544 
545 
iNES_TestMagic(Stream * fp)546 bool iNES_TestMagic(Stream *fp)
547 {
548  uint8 header[16];
549 
550  if(fp->read(header, 16, false) != 16 || memcmp(header, "NES\x1a", 4))
551   return false;
552 
553  return true;
554 }
555 
iNESLoad(Stream * fp,NESGameType * gt)556 MDFN_COLD void iNESLoad(Stream *fp, NESGameType *gt)
557 {
558   try
559   {
560 	const uint64 raw_size = fp->size();
561         md5_context md5;
562 
563 	fp->read(head.raw, 16);
564 
565 	if(memcmp(head.ID, "NES\x1a", 4))
566 	 throw MDFN_Error(0, _("Not a valid iNES format file."));
567 
568 	{
569 	 const uint64 needed_size = 16 + (head.ROM_size ? head.ROM_size : 256) * 0x4000 + head.VROM_size * 0x2000 + ((head.ROM_type & 4) ? 512 : 0);
570 
571 	 if(raw_size < needed_size)
572 	  throw MDFN_Error(0, _("iNES format file is too small by %llu bytes to contain all data specified by header!"), (unsigned long long)needed_size - raw_size);
573 
574 	 if(raw_size > needed_size)
575 	  MDFN_printf(_("Warning: iNES format file has %llu bytes of unused trailing data.\n"), (unsigned long long)(raw_size - needed_size));
576 	}
577 
578 	memset(&iNESCart, 0, sizeof(iNESCart));
579 
580 	/* Do some fixes to common strings found in
581 	   old iNES-format headers.
582 	*/
583         if(!memcmp(&head.raw[0x7], "DiskDude", 8))
584         {
585          memset(&head.raw[0x7], 0, 0x9);
586         }
587 
588         if(!memcmp(&head.raw[0x7], "demiforce", 9))
589         {
590          memset(&head.raw[0x7], 0, 0x9);
591         }
592 
593         if(!memcmp(&head.raw[0xA], "Ni03", 4))
594         {
595          if(!memcmp(&head.raw[0x7], "Dis", 3))
596           memset(&head.raw[0x7], 0, 0x9);
597          else
598           memset(&head.raw[0xA], 0, 0x6);
599         }
600 
601         ROM_size = round_up_pow2((head.ROM_size ? head.ROM_size : 256));
602         VROM_size = head.VROM_size;
603 
604         if(VROM_size)
605 	 VROM_size = round_up_pow2(VROM_size);
606 
607         MapperNo = (head.ROM_type>>4);
608         MapperNo|=(head.ROM_type2&0xF0);
609         Mirroring = (head.ROM_type&1);
610 
611 	if(head.ROM_type&8) Mirroring=2;
612 
613         ROM = new uint8[ROM_size << 14];
614 
615 	#ifdef WANT_DEBUGGER
616 	ASpace_Add(iNES_GetAddressSpaceBytes, iNES_PutAddressSpaceBytes, "prgrom", "PRG ROM", (unsigned int)(log(ROM_size << 14) / log(2)));
617 	#endif
618 
619         if(VROM_size)
620 	{
621          VROM = new uint8[VROM_size << 13];
622 	 #ifdef WANT_DEBUGGER
623 	 ASpace_Add(iNES_GetAddressSpaceBytes, iNES_PutAddressSpaceBytes, "chrrom", "CHR ROM", (unsigned int)(log(VROM_size << 13) / log(2)));
624 	 #endif
625 	}
626 
627         memset(ROM, 0xFF, ROM_size << 14);
628 
629         if(VROM_size)
630          memset(VROM, 0xFF, VROM_size << 13);
631 
632         if(head.ROM_type&4)     /* Trainer */
633 	{
634          fp->read(trainerpoo, 512);
635 	}
636 
637 	ResetCartMapping();
638 
639 	SetupCartPRGMapping(0, ROM, ROM_size * 0x4000, 0);
640 
641         fp->read(ROM, 0x4000 * (head.ROM_size ? head.ROM_size : 256));
642 
643 	if(VROM_size)
644 	{
645 	 fp->read(VROM, 0x2000 * head.VROM_size);
646 	}
647 
648         md5.starts();
649         md5.update(ROM,ROM_size<<14);
650 
651 	iNESGameCRC32 = crc32(0,ROM,ROM_size<<14);
652 
653 	if(VROM_size)
654 	{
655 	 iNESGameCRC32 = crc32(iNESGameCRC32,VROM,VROM_size<<13);
656          md5.update(VROM,VROM_size<<13);
657 	}
658 	md5.finish(iNESCart.MD5);
659 	memcpy(MDFNGameInfo->MD5,iNESCart.MD5,sizeof(iNESCart.MD5));
660 
661 	iNESCart.CRC32 = iNESGameCRC32;
662 
663         MDFN_printf(_("PRG ROM:  %3d x 16KiB\n"), (head.ROM_size ? head.ROM_size : 256));
664 	MDFN_printf(_("CHR ROM:  %3d x  8KiB\n"), head.VROM_size);
665 	MDFN_printf(_("ROM CRC32:  0x%08x\n"), iNESGameCRC32);
666 
667         MDFN_printf(_("ROM MD5:  0x%s\n"), md5_context::asciistr(iNESCart.MD5, 0).c_str());
668 	MDFN_printf(_("Mapper:  %d\n"), MapperNo);
669 	MDFN_printf(_("Mirroring: %s\n"), Mirroring==2?_("None(Four-screen)"):Mirroring?_("Vertical"):_("Horizontal"));
670 
671         if(head.ROM_type&2) MDFN_printf(_("Battery-backed.\n"));
672         if(head.ROM_type&4) MDFN_printf(_("Trained.\n"));
673 
674 	SetInput();
675 	CheckHInfo();
676 	{
677 	 int x;
678 	 uint64 partialmd5=0;
679 
680 	 for(x=0;x<8;x++)
681 	 {
682 	  partialmd5 |= (uint64)iNESCart.MD5[7-x] << (x*8);
683 	 }
684 
685 	 MDFN_VSUniCheck(partialmd5, &MapperNo, &Mirroring);
686 	}
687 	/* Must remain here because above functions might change value of
688 	   VROM_size and delete[] VROM.
689 	*/
690 	if(VROM_size)
691          SetupCartCHRMapping(0,VROM,VROM_size*0x2000,0);
692 
693         if(Mirroring==2)
694          SetupCartMirroring(4,1,ExtraNTARAM);
695         else if(Mirroring>=0x10)
696 	 SetupCartMirroring(2+(Mirroring&1),1,0);
697 	else
698          SetupCartMirroring(Mirroring&1,(Mirroring&4)>>2,0);
699 
700 	iNESCart.battery = (head.ROM_type&2)?1:0;
701 	iNESCart.mirror = Mirroring;
702 
703 	NewiNES_Init(MapperNo);
704 
705 	MDFN_LoadGameSave(&iNESCart);
706 
707 	gt->Power = iNES_Power;
708 	gt->Reset = iNES_Reset;
709 	gt->SaveNV = iNES_SaveNV;
710 	gt->Kill = iNES_Kill;
711 	gt->StateAction = iNES_StateAction;
712 
713 	if(iNESCart.CartExpSound.HiFill)
714 	 GameExpSound.push_back(iNESCart.CartExpSound);
715 
716 	if(head.ROM_type & 4)
717 	{
718          SetReadHandler(0x7000, 0x71FF, TrainerRead);
719 	 SetWriteHandler(0x7000, 0x71FF, TrainerWrite);
720 	}
721   }
722   catch(...)
723   {
724    iNESFree();
725    throw;
726   }
727 }
728 
729 
730 #define BMAPF_32KCHRR		1	// 32KB CHR RAM
731 #define BMAPF_INESWRAMOK	2	// Ok to emulate WRAM here(ines.cpp) if the battery-backed bit is set.
732 
733 typedef struct {
734            int number;
735            int (*init)(CartInfo *);
736 	   uint32 flags;
737 } BMAPPING;
738 
739 static const BMAPPING bmap[] = {
740 	{ 0, NROM256_Init, BMAPF_INESWRAMOK },
741 	{ 1, Mapper1_Init, 0 },
742 	{ 2, UNROM_Init, BMAPF_INESWRAMOK },
743 	{ 3, CNROM_Init, BMAPF_INESWRAMOK },
744 	{ 4, Mapper4_Init, 0},
745 	{ 5, Mapper5_Init, 0},
746 	{ 6, Mapper6_Init,  BMAPF_32KCHRR},
747 	{ 7, AOROM_Init, 0},
748 	{ 8, Mapper8_Init, 0},
749 	{ 9, PNROM_Init, 0},
750 	{ 10, MMC4_Init, 0},
751 	{ 11, Mapper11_Init, 0},
752 	{ 12, Mapper12_Init, 0},
753 	{ 13, CPROM_Init, BMAPF_32KCHRR},
754 	{ 15, Mapper15_Init, 0 },
755 	{ 16, Mapper16_Init, 0},
756 	{ 17, Mapper17_Init, 0},
757 	{ 18, Mapper18_Init, 0},
758 	{ 19, Mapper19_Init, 0},
759 	{ 21, Mapper21_Init, 0},
760 	{ 22, Mapper22_Init, 0},
761 	{ 23, Mapper23_Init, 0},
762 	{ 24, Mapper24_Init, 0},
763 	{ 25, Mapper25_Init, 0},
764 	{ 26, Mapper26_Init, 0},
765 	{ 30, Mapper30_Init, BMAPF_32KCHRR },
766 	{ 32, Mapper32_Init, 0},
767 	{ 33, Mapper33_Init, 0},
768 	{ 34, Mapper34_Init, 0},
769 	{ 37, Mapper37_Init, 0},
770 	{ 38, Mapper38_Init, 0},
771 	{ 40, Mapper40_Init, 0},
772         { 41, Mapper41_Init, 0},
773 	{ 42, BioMiracleA_Init, 0},
774         { 44, Mapper44_Init, 0},
775         { 45, Mapper45_Init, 0},
776         { 46, Mapper46_Init, 0},
777         { 47, Mapper47_Init, 0},
778 	{ 48, Mapper48_Init, 0},
779         { 49, Mapper49_Init, 0},
780 	{ 51, Mapper51_Init, 0},
781         { 52, Mapper52_Init, 0},
782 	{ 64, Mapper64_Init, 0},
783 	{ 65, Mapper65_Init, 0},
784 	{ 66, GNROM_Init, 0},
785 	{ 67, Mapper67_Init, 0},
786 	{ 68, Mapper68_Init, 0},
787 	{ 69, BTR_Init, 0},
788 	{ 70, Mapper70_Init, 0},
789 	{ 71, Mapper71_Init, 0},
790 	{ 72, Mapper72_Init, 0},
791 	{ 73, Mapper73_Init, 0},
792         { 74, Mapper74_Init, 0},
793 	{ 75, Mapper75_Init, 0},
794 	{ 76, Mapper76_Init, 0},
795 	{ 77, Mapper77_Init, 0},
796 	{ 78, Mapper78_Init, 0},
797 	{ 79, NINA06_Init, 0},
798         { 80, Mapper80_Init, 0},
799         { 82, Mapper82_Init, 0},
800 	{ 85, Mapper85_Init, 0},
801         { 86, Mapper86_Init, 0},
802 	{ 87, Mapper87_Init, 0},
803         { 88, Mapper88_Init, 0},
804         { 89, Mapper89_Init, 0},
805 	{ 90, Mapper90_Init, 0},
806 	{ 92, Mapper92_Init, 0},
807 	{ 93, Mapper93_Init, 0},
808 	{ 94, Mapper94_Init, 0},
809         { 95, Mapper95_Init, 0},
810 	{ 96, Mapper96_Init, 0},
811 	{ 97, Mapper97_Init, 0},
812 	{ 99, Mapper99_Init, 0},
813 	{ 101, Mapper101_Init, 0},
814 	{ 105, Mapper105_Init, 0},
815 	{ 107, Mapper107_Init, 0},
816 	{ 112, Mapper112_Init, 0},
817 	{ 113, Mapper113_Init, 0},
818 	{ 114, Mapper114_Init, 0},
819         { 115, Mapper115_Init, 0},
820         { 116, Mapper116_Init, 0},
821 	{ 117, Mapper117_Init, 0},
822 	{ 118, Mapper118_Init, 0},
823 	{ 119, Mapper119_Init, 0},	/* Has CHR ROM and CHR RAM by default.  Hmm. */
824 	{ 133, SA72008_Init, 0},
825 	{ 134, S74LS374N_Init, 0},
826 	{ 135, S8259A_Init, 0},
827 	{ 140, Mapper140_Init, 0},
828 	{ 144, AGCI50282_Init, 0},
829 	{ 150, BIC62_Init, 0},
830 	{ 151, Mapper151_Init, 0},
831 	{ 152, Mapper152_Init, 0},
832 	{ 153, Mapper153_Init, 0},
833 	{ 154, Mapper154_Init, 0},
834 	{ 155, Mapper155_Init, 0},
835 	{ 156, Mapper156_Init, 0},
836 	{ 157, Mapper157_Init, 0},
837 	{ 158, Mapper158_Init, 0},
838         { 159, Mapper159_Init, 0 },
839         { 160, Mapper90_Init, 0},
840 	{ 163, Mapper163_Init, 0 },
841 	{ 180, Mapper180_Init, 0},
842 	{ 182, Mapper182_Init, 0},
843 	{ 184, Mapper184_Init, 0},
844 	{ 185, Mapper185_Init, 0},
845         { 187, Mapper187_Init, 0},
846 	{ 189, Mapper189_Init, 0},
847 	{ 190, Mapper190_Init, 0 },
848 	{ 193, Mapper193_Init, 0},
849 	{ 206, Mapper206_Init, 0},
850 	{ 207, Mapper207_Init, 0},
851         { 208, Mapper208_Init, 0},
852         { 209, Mapper209_Init, 0},
853 	{ 210, Mapper210_Init, 0},
854 	{ 215, Mapper215_Init, 0},
855 	{ 217, Mapper217_Init, 0},
856 	{ 222, Mapper222_Init, 0},
857 	{ 228, Mapper228_Init, 0},
858 	{ 232, BIC48_Init, 0},
859 	{ 234, Mapper234_Init, 0},
860         { 240, Mapper240_Init, 0},
861 	{ 241, Mapper241_Init, 0},
862 	{ 242, Mapper242_Init, 0},
863 	{ 243, S74LS374N_Init, 0},
864         { 244, Mapper244_Init, 0},
865         { 245, Mapper245_Init, 0},
866 	{ 246, Mapper246_Init, 0},
867 	{ 248, Mapper248_Init, 0},
868         { 249, Mapper249_Init, 0},
869         { 250, Mapper250_Init, 0},
870 	{ 0, NULL, 0}
871 };
872 
NewiNES_Init(int num)873 static void NewiNES_Init(int num)
874 {
875  const BMAPPING *tmp=bmap;
876 
877  while(tmp->init)
878  {
879   if(num == tmp->number)
880   {
881    if(!VROM_size)
882    {
883     if(tmp->flags & BMAPF_32KCHRR)
884      CHRRAMSize = 32768;
885     else
886      CHRRAMSize = 8192;
887 
888     VROM = new uint8[CHRRAMSize];
889 
890     SetupCartCHRMapping(0x0,VROM,CHRRAMSize,1);
891 
892     #ifdef WANT_DEBUGGER
893     ASpace_Add(iNES_GetAddressSpaceBytes, iNES_PutAddressSpaceBytes, "chrram", "CHR RAM", (unsigned int)(log(CHRRAMSize) / log(2)));
894     #endif
895    }
896 
897    if(iNESCart.battery && (tmp->flags & BMAPF_INESWRAMOK))
898    {
899     WRAM = new uint8[8192];
900 
901     memset(WRAM, 0x00, 8192);
902 
903     SetupCartPRGMapping(0x10, WRAM, 8192, 1);
904     SetReadHandler(0x6000, 0x7FFF, CartBR);
905     SetWriteHandler(0x6000, 0x7FFF, CartBW);
906     iNESCart.SaveGame[0] = WRAM;
907     iNESCart.SaveGameLen[0] = 8192;
908 
909     #ifdef WANT_DEBUGGER
910     ASpace_Add(iNES_GetAddressSpaceBytes, iNES_PutAddressSpaceBytes, "wram", "WRAM", 13);
911     #endif
912    }
913 
914    tmp->init(&iNESCart);
915    return;
916   }
917   tmp++;
918  }
919 
920  throw MDFN_Error(0, _("iNES mapper %d is not supported!"), num);
921 }
922 
923 }
924