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