/* FCE Ultra - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 1998 BERO * Copyright (C) 2002 Xodnizel * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include "fceu-types.h" #include "x6502.h" #include "fceu.h" #include "cart.h" #include "ppu.h" #include "ines.h" #include "unif.h" #include "state.h" #include "file.h" #include "general.h" #include "fceu-memory.h" #include "crc32.h" #include "md5.h" #include "cheat.h" #include "vsuni.h" extern SFORMAT FCEUVSUNI_STATEINFO[]; uint8 *trainerpoo = NULL; uint8 *ROM = NULL; uint8 *VROM = NULL; uint8 *ExtraNTARAM = NULL; iNES_HEADER head; CartInfo iNESCart; uint8 Mirroring = 0; uint32 ROM_size = 0; uint32 VROM_size = 0; static int CHRRAMSize = -1; static int iNES_Init(int num); static int MapperNo = 0; static DECLFR(TrainerRead) { return(trainerpoo[A & 0x1FF]); } static void iNES_ExecPower() { if (iNESCart.Power) iNESCart.Power(); if (trainerpoo) { int x; for (x = 0; x < 512; x++) { X6502_DMW(0x7000 + x, trainerpoo[x]); if (X6502_DMR(0x7000 + x) != trainerpoo[x]) { SetReadHandler(0x7000, 0x71FF, TrainerRead); break; } } } } static void iNESGI(int h) { switch (h) { case GI_RESETM2: if (iNESCart.Reset) iNESCart.Reset(); break; case GI_POWER: iNES_ExecPower(); break; case GI_CLOSE: if (iNESCart.Close) iNESCart.Close(); if (ROM) { free(ROM); ROM = NULL; } if (VROM) { free(VROM); VROM = NULL; } if (trainerpoo) { free(trainerpoo); trainerpoo = NULL; } if (ExtraNTARAM) { free(ExtraNTARAM); ExtraNTARAM = NULL; } break; } } uint32 iNESGameCRC32 = 0; struct CRCMATCH { uint32 crc; char *name; }; struct INPSEL { uint32 crc32; int input1; int input2; int inputfc; }; static void SetInput(void) { static struct INPSEL moo[] = { {0x19b0a9f1, SI_GAMEPAD, SI_ZAPPER, SIFC_NONE }, /* 6-in-1 (MGC-023)(Unl)[!] */ {0x29de87af, SI_GAMEPAD, SI_GAMEPAD, SIFC_FTRAINERB }, /* Aerobics Studio */ {0xd89e5a67, SI_UNSET, SI_UNSET, SIFC_ARKANOID }, /* Arkanoid (J) */ {0x0f141525, SI_UNSET, SI_UNSET, SIFC_ARKANOID }, /* Arkanoid 2(J) */ {0x32fb0583, SI_UNSET, SI_ARKANOID, SIFC_NONE }, /* Arkanoid(NES) */ {0x60ad090a, SI_GAMEPAD, SI_GAMEPAD, SIFC_FTRAINERA }, /* Athletic World */ {0x48ca0ee1, SI_GAMEPAD, SI_GAMEPAD, SIFC_BWORLD }, /* Barcode World */ {0x4318a2f8, SI_UNSET, SI_ZAPPER, SIFC_NONE }, /* Barker Bill's Trick Shooting */ {0x6cca1c1f, SI_GAMEPAD, SI_GAMEPAD, SIFC_FTRAINERB }, /* Dai Undoukai */ {0x24598791, SI_UNSET, SI_ZAPPER, SIFC_NONE }, /* Duck Hunt */ {0xd5d6eac4, SI_UNSET, SI_UNSET, SIFC_SUBORKB }, /* Edu (As) */ {0xe9a7fe9e, SI_UNSET, SI_MOUSE, SIFC_NONE }, /* Educational Computer 2000 */ {0x8f7b1669, SI_UNSET, SI_UNSET, SIFC_SUBORKB }, /* FP BASIC 3.3 by maxzhou88 */ {0xf7606810, SI_UNSET, SI_UNSET, SIFC_FKB }, /* Family BASIC 2.0A */ {0x895037bc, SI_UNSET, SI_UNSET, SIFC_FKB }, /* Family BASIC 2.1a */ {0xb2530afc, SI_UNSET, SI_UNSET, SIFC_FKB }, /* Family BASIC 3.0 */ {0xea90f3e2, SI_GAMEPAD, SI_GAMEPAD, SIFC_FTRAINERB }, /* Family Trainer: Running Stadium */ {0xbba58be5, SI_GAMEPAD, SI_GAMEPAD, SIFC_FTRAINERB }, /* Family Trainer: Manhattan Police */ {0x3e58a87e, SI_UNSET, SI_ZAPPER, SIFC_NONE }, /* Freedom Force */ {0xd9f45be9, SI_GAMEPAD, SI_GAMEPAD, SIFC_QUIZKING }, /* Gimme a Break ... */ {0x1545bd13, SI_GAMEPAD, SI_GAMEPAD, SIFC_QUIZKING }, /* Gimme a Break ... 2 */ {0x4e959173, SI_UNSET, SI_ZAPPER, SIFC_NONE }, /* Gotcha! - The Sport! */ {0xbeb8ab01, SI_UNSET, SI_ZAPPER, SIFC_NONE }, /* Gumshoe */ {0xff24d794, SI_UNSET, SI_ZAPPER, SIFC_NONE }, /* Hogan's Alley */ {0x21f85681, SI_GAMEPAD, SI_GAMEPAD, SIFC_HYPERSHOT }, /* Hyper Olympic (Gentei Ban) */ {0x980be936, SI_GAMEPAD, SI_GAMEPAD, SIFC_HYPERSHOT }, /* Hyper Olympic */ {0x915a53a7, SI_GAMEPAD, SI_GAMEPAD, SIFC_HYPERSHOT }, /* Hyper Sports */ {0x9fae4d46, SI_GAMEPAD, SI_GAMEPAD, SIFC_MAHJONG }, /* Ide Yousuke Meijin no Jissen Mahjong */ {0x7b44fb2a, SI_GAMEPAD, SI_GAMEPAD, SIFC_MAHJONG }, /* Ide Yousuke Meijin no Jissen Mahjong 2 */ {0x2f128512, SI_GAMEPAD, SI_GAMEPAD, SIFC_FTRAINERA }, /* Jogging Race */ {0xbb33196f, SI_UNSET, SI_UNSET, SIFC_FKB }, /* Keyboard Transformer */ {0x8587ee00, SI_UNSET, SI_UNSET, SIFC_FKB }, /* Keyboard Transformer */ {0x543ab532, SI_UNSET, SI_UNSET, SIFC_SUBORKB }, /* LIKO Color Lines */ {0x368c19a8, SI_UNSET, SI_UNSET, SIFC_SUBORKB }, /* LIKO Study Cartridge */ {0x5ee6008e, SI_UNSET, SI_ZAPPER, SIFC_NONE }, /* Mechanized Attack */ {0x370ceb65, SI_GAMEPAD, SI_GAMEPAD, SIFC_FTRAINERB }, /* Meiro Dai Sakusen */ {0x3a1694f9, SI_GAMEPAD, SI_GAMEPAD, SIFC_4PLAYER }, /* Nekketsu Kakutou Densetsu */ {0x9d048ea4, SI_GAMEPAD, SI_GAMEPAD, SIFC_OEKAKIDS }, /* Oeka Kids */ {0x2a6559a1, SI_UNSET, SI_ZAPPER, SIFC_NONE }, /* Operation Wolf (J) */ {0xedc3662b, SI_UNSET, SI_ZAPPER, SIFC_NONE }, /* Operation Wolf */ {0x912989dc, SI_UNSET, SI_UNSET, SIFC_FKB }, /* Playbox BASIC */ {0x9044550e, SI_GAMEPAD, SI_GAMEPAD, SIFC_FTRAINERA }, /* Rairai Kyonshizu */ {0xea90f3e2, SI_GAMEPAD, SI_GAMEPAD, SIFC_FTRAINERB }, /* Running Stadium */ {0x851eb9be, SI_GAMEPAD, SI_ZAPPER, SIFC_NONE }, /* Shooting Range */ {0x6435c095, SI_GAMEPAD, SI_POWERPADB, SIFC_UNSET }, /* Short Order/Eggsplode */ {0xc043a8df, SI_UNSET, SI_MOUSE, SIFC_NONE }, /* Shu Qi Yu - Shu Xue Xiao Zhuan Yuan (Ch) */ {0x2cf5db05, SI_UNSET, SI_MOUSE, SIFC_NONE }, /* Shu Qi Yu - Zhi Li Xiao Zhuan Yuan (Ch) */ {0xad9c63e2, SI_GAMEPAD, SI_UNSET, SIFC_SHADOW }, /* Space Shadow */ {0x61d86167, SI_GAMEPAD, SI_POWERPADB, SIFC_UNSET }, /* Street Cop */ {0xabb2f974, SI_UNSET, SI_UNSET, SIFC_SUBORKB }, /* Study and Game 32-in-1 */ {0x41ef9ac4, SI_UNSET, SI_UNSET, SIFC_SUBORKB }, /* Subor */ {0x8b265862, SI_UNSET, SI_UNSET, SIFC_SUBORKB }, /* Subor */ {0x82f1fb96, SI_UNSET, SI_UNSET, SIFC_SUBORKB }, /* Subor 1.0 Russian */ {0x9f8f200a, SI_GAMEPAD, SI_GAMEPAD, SIFC_FTRAINERA }, /* Super Mogura Tataki!! - Pokkun Moguraa */ {0xd74b2719, SI_GAMEPAD, SI_POWERPADB, SIFC_UNSET }, /* Super Team Games */ {0x74bea652, SI_GAMEPAD, SI_ZAPPER, SIFC_NONE }, /* Supergun 3-in-1 */ {0x5e073a1b, SI_UNSET, SI_UNSET, SIFC_SUBORKB }, /* Supor English (Chinese) */ {0x589b6b0d, SI_UNSET, SI_UNSET, SIFC_SUBORKB }, /* SuporV20 */ {0x41401c6d, SI_UNSET, SI_UNSET, SIFC_SUBORKB }, /* SuporV40 */ {0x23d17f5e, SI_GAMEPAD, SI_ZAPPER, SIFC_NONE }, /* The Lone Ranger */ {0xc3c0811d, SI_GAMEPAD, SI_GAMEPAD, SIFC_OEKAKIDS }, /* The two "Oeka Kids" games */ {0xde8fd935, SI_UNSET, SI_ZAPPER, SIFC_NONE }, /* To the Earth */ {0x47232739, SI_GAMEPAD, SI_GAMEPAD, SIFC_TOPRIDER }, /* Top Rider */ {0x8a12a7d9, SI_GAMEPAD, SI_GAMEPAD, SIFC_FTRAINERB }, /* Totsugeki Fuuun Takeshi Jou */ {0xb8b9aca3, SI_UNSET, SI_ZAPPER, SIFC_NONE }, /* Wild Gunman */ {0x5112dc21, SI_UNSET, SI_ZAPPER, SIFC_NONE }, /* Wild Gunman */ {0xaf4010ea, SI_GAMEPAD, SI_POWERPADB, SIFC_UNSET }, /* World Class Track Meet */ {0x00000000, SI_UNSET, SI_UNSET, SIFC_UNSET } }; int x = 0; while (moo[x].input1 >= 0 || moo[x].input2 >= 0 || moo[x].inputfc >= 0) { if (moo[x].crc32 == iNESGameCRC32) { GameInfo->input[0] = moo[x].input1; GameInfo->input[1] = moo[x].input2; GameInfo->inputfc = moo[x].inputfc; break; } x++; } } #define INESB_INCOMPLETE 1 #define INESB_CORRUPT 2 #define INESB_HACKED 4 struct BADINF { uint64 md5partial; uint8 *name; uint32 type; }; static struct BADINF BadROMImages[] = { #include "ines-bad.h" }; void CheckBad(uint64 md5partial) { int32 x = 0; while (BadROMImages[x].name) { if (BadROMImages[x].md5partial == md5partial) { FCEU_PrintError("The copy game you have loaded, \"%s\", is bad, and will not work properly in FCE Ultra.", BadROMImages[x].name); return; } x++; } } struct CHINF { uint32 crc32; int32 mapper; int32 mirror; }; static void CheckHInfo(void) { /* ROM images that have the battery-backed bit set in the header that really don't have battery-backed RAM is not that big of a problem, so I'll treat this differently by only listing games that should have battery-backed RAM. Lower 64 bits of the MD5 hash. */ static uint64 savie[] = { 0xc04361e499748382LL, /* AD&D Heroes of the Lance */ 0xb72ee2337ced5792LL, /* AD&D Hillsfar */ 0x2b7103b7a27bd72fLL, /* AD&D Pool of Radiance */ 0x498c10dc463cfe95LL, /* Battle Fleet */ 0x854d7947a3177f57LL, /* Crystalis */ 0x4a1f5336b86851b6LL, /* DW */ 0xb0bcc02c843c1b79LL, /* DW */ 0x2dcf3a98c7937c22LL, /* DW 2 */ 0x98e55e09dfcc7533LL, /* DW 4*/ 0x733026b6b72f2470LL, /* Dw 3 */ 0x6917ffcaca2d8466LL, /* Famista '90 */ 0x8da46db592a1fcf4LL, /* Faria */ 0xedba17a2c4608d20LL, /* Final Fantasy */ 0x91a6846d3202e3d6LL, /* Final Fantasy */ 0x012df596e2b31174LL, /* Final Fantasy 1+2 */ 0xf6b359a720549ecdLL, /* Final Fantasy 2 */ 0x5a30da1d9b4af35dLL, /* Final Fantasy 3 */ 0xd63dcc68c2b20adcLL, /* Final Fantasy J */ 0x2ee3417ba8b69706LL, /* Hydlide 3*/ 0xebbce5a54cf3ecc0LL, /* Justbreed */ 0x6a858da551ba239eLL, /* Kaijuu Monogatari */ 0x2db8f5d16c10b925LL, /* Kyonshiizu 2 */ 0x04a31647de80fdabLL, /* Legend of Zelda */ 0x94b9484862a26cbaLL, /* Legend of Zelda */ 0xa40666740b7d22feLL, /* Mindseeker */ 0x82000965f04a71bbLL, /* Mirai Shinwa Jarvas */ 0x77b811b2760104b9LL, /* Mouryou Senki Madara */ 0x11b69122efe86e8cLL, /* RPG Jinsei Game */ 0x9aa1dc16c05e7de5LL, /* Startropics */ 0x1b084107d0878bd0LL, /* Startropics 2*/ 0xa70b495314f4d075LL, /* Ys 3 */ 0x836c0ff4f3e06e45LL, /* Zelda 2 */ 0 /* Abandon all hope if the game has 0 in the lower 64-bits of its MD5 hash */ }; static struct CHINF moo[] = { #include "ines-correct.h" }; int32 tofix = 0, x; uint64 partialmd5 = 0; int32 current_mapper = 0; int32 cur_mirr = 0; for (x = 0; x < 8; x++) partialmd5 |= (uint64)iNESCart.MD5[15 - x] << (x * 8); CheckBad(partialmd5); x = 0; do { if (moo[x].crc32 == iNESGameCRC32) { if (moo[x].mapper >= 0) { if (moo[x].mapper & 0x800 && VROM_size) { VROM_size = 0; free(VROM); VROM = NULL; tofix |= 8; } if (MapperNo != (moo[x].mapper & 0xFFF)) { tofix |= 1; current_mapper = MapperNo; MapperNo = moo[x].mapper & 0xFFF; } } if (moo[x].mirror >= 0) { cur_mirr = Mirroring; if (moo[x].mirror == 8) { if (Mirroring == 2) { /* Anything but hard-wired(four screen). */ tofix |= 2; Mirroring = 0; } } else if (Mirroring != moo[x].mirror) { if (Mirroring != (moo[x].mirror & ~4)) if ((moo[x].mirror & ~4) <= 2) /* Don't complain if one-screen mirroring needs to be set(the iNES header can't hold this information). */ tofix |= 2; Mirroring = moo[x].mirror; } } break; } x++; } while (moo[x].mirror >= 0 || moo[x].mapper >= 0); x = 0; while (savie[x] != 0) { if (savie[x] == partialmd5) { if (!(head.ROM_type & 2)) { tofix |= 4; head.ROM_type |= 2; } } x++; } /* Games that use these iNES mappers tend to have the four-screen bit set when it should not be. */ if ((MapperNo == 118 || MapperNo == 24 || MapperNo == 26) && (Mirroring == 2)) { Mirroring = 0; tofix |= 2; } /* Four-screen mirroring implicitly set. */ if (MapperNo == 99) Mirroring = 2; if (tofix) { char gigastr[768]; strcpy(gigastr, "The iNES header contains incorrect information. For now, the information will be corrected in RAM. "); if (tofix & 1) sprintf(gigastr + strlen(gigastr), "Current mapper # is %d. The mapper number should be set to %d. ", current_mapper, MapperNo); if (tofix & 2) { uint8 *mstr[3] = { (uint8_t*)"Horizontal", (uint8_t*)"Vertical", (uint8_t*)"Four-screen" }; sprintf(gigastr + strlen(gigastr), "Current mirroring is %s. Mirroring should be set to \"%s\". ", mstr[cur_mirr & 3], mstr[Mirroring & 3]); } if (tofix & 4) strcat(gigastr, "The battery-backed bit should be set. "); if (tofix & 8) strcat(gigastr, "This game should not have any CHR ROM. "); strcat(gigastr, "\n"); FCEU_printf("%s", gigastr); } } typedef struct { int32 mapper; void (*init)(CartInfo *); } NewMI; typedef struct { uint8 *name; int32 number; void (*init)(CartInfo *); } BMAPPINGLocal; static BMAPPINGLocal bmap[] = { {(uint8_t*)"NROM", 0, NROM_Init}, {(uint8_t*)"MMC1", 1, Mapper1_Init}, {(uint8_t*)"UNROM", 2, UNROM_Init}, {(uint8_t*)"CNROM", 3, CNROM_Init}, {(uint8_t*)"MMC3", 4, Mapper4_Init}, {(uint8_t*)"MMC5", 5, Mapper5_Init}, {(uint8_t*)"FFE Rev. A", 6, Mapper6_Init}, {(uint8_t*)"ANROM", 7, ANROM_Init}, {(uint8_t*)"", 8, Mapper8_Init}, /* Nogaems, it's worthless */ {(uint8_t*)"MMC2", 9, Mapper9_Init}, {(uint8_t*)"MMC4", 10, Mapper10_Init}, {(uint8_t*)"Color Dreams", 11, Mapper11_Init}, {(uint8_t*)"REX DBZ 5", 12, Mapper12_Init}, {(uint8_t*)"CPROM", 13, CPROM_Init}, {(uint8_t*)"REX SL-1632", 14, UNLSL1632_Init}, {(uint8_t*)"100-in-1", 15, Mapper15_Init}, {(uint8_t*)"BANDAI 24C02", 16, Mapper16_Init}, {(uint8_t*)"FFE Rev. B", 17, Mapper17_Init}, {(uint8_t*)"JALECO SS880006", 18, Mapper18_Init}, /* JF-NNX (EB89018-30007) boards */ {(uint8_t*)"Namcot 106", 19, Mapper19_Init}, /* {(uint8_t*)"", 20, Mapper20_Init}, */ {(uint8_t*)"Konami VRC2/VRC4 A", 21, Mapper21_Init}, {(uint8_t*)"Konami VRC2/VRC4 B", 22, Mapper22_Init}, {(uint8_t*)"Konami VRC2/VRC4 C", 23, Mapper23_Init}, {(uint8_t*)"Konami VRC6 Rev. A", 24, Mapper24_Init}, {(uint8_t*)"Konami VRC2/VRC4 D", 25, Mapper25_Init}, {(uint8_t*)"Konami VRC6 Rev. B", 26, Mapper26_Init}, {(uint8_t*)"CC-21 MI HUN CHE", 27, UNLCC21_Init}, /* Former dupe for VRC2/VRC4 mapper, redefined with crc to mihunche boards */ {(uint8_t*)"Action 53", 28, Mapper28_Init}, {(uint8_t*)"", 29, Mapper29_Init}, {(uint8_t*)"UNROM 512", 30, UNROM512_Init}, {(uint8_t*)"infineteNesLives-NSF", 31, Mapper31_Init}, {(uint8_t*)"IREM G-101", 32, Mapper32_Init}, {(uint8_t*)"TC0190FMC/TC0350FMR", 33, Mapper33_Init}, {(uint8_t*)"IREM I-IM/BNROM", 34, Mapper34_Init}, {(uint8_t*)"Wario Land 2", 35, UNLSC127_Init}, {(uint8_t*)"TXC Policeman", 36, Mapper36_Init}, {(uint8_t*)"PAL-ZZ SMB/TETRIS/NWC",37, Mapper37_Init}, {(uint8_t*)"Bit Corp.", 38, Mapper38_Init}, /* Crime Busters */ /* {(uint8_t*)"", 39, Mapper39_Init}, */ {(uint8_t*)"SMB2j FDS", 40, Mapper40_Init}, {(uint8_t*)"CALTRON 6-in-1", 41, Mapper41_Init}, {(uint8_t*)"BIO MIRACLE FDS", 42, Mapper42_Init}, {(uint8_t*)"FDS SMB2j LF36", 43, Mapper43_Init}, {(uint8_t*)"MMC3 BMC PIRATE A", 44, Mapper44_Init}, {(uint8_t*)"MMC3 BMC PIRATE B", 45, Mapper45_Init}, {(uint8_t*)"RUMBLESTATION 15-in-1",46, Mapper46_Init}, {(uint8_t*)"NES-QJ SSVB/NWC", 47, Mapper47_Init}, {(uint8_t*)"TAITO TCxxx", 48, Mapper48_Init}, {(uint8_t*)"MMC3 BMC PIRATE C", 49, Mapper49_Init}, {(uint8_t*)"SMB2j FDS Rev. A", 50, Mapper50_Init}, {(uint8_t*)"11-in-1 BALL SERIES", 51, Mapper51_Init}, /* 1993 year version */ {(uint8_t*)"MMC3 BMC PIRATE D", 52, Mapper52_Init}, {(uint8_t*)"SUPERVISION 16-in-1", 53, Supervision16_Init}, /* {(uint8_t*)"", 54, Mapper54_Init}, */ /* {(uint8_t*)"", 55, Mapper55_Init}, */ {(uint8_t*)"UNLKS202", 56, UNLKS202_Init}, {(uint8_t*)"SIMBPLE BMC PIRATE A", 57, Mapper57_Init}, {(uint8_t*)"SIMBPLE BMC PIRATE B", 58, BMCGK192_Init}, {(uint8_t*)"", 59, Mapper59_Init}, /* Check this out */ {(uint8_t*)"SIMBPLE BMC PIRATE C", 60, BMCD1038_Init}, {(uint8_t*)"20-in-1 KAISER Rev. A",61, Mapper61_Init}, {(uint8_t*)"700-in-1", 62, Mapper62_Init}, {(uint8_t*)"", 63, Mapper63_Init}, {(uint8_t*)"TENGEN RAMBO1", 64, Mapper64_Init}, {(uint8_t*)"IREM-H3001", 65, Mapper65_Init}, {(uint8_t*)"MHROM", 66, MHROM_Init}, {(uint8_t*)"SUNSOFT-FZII", 67, Mapper67_Init}, {(uint8_t*)"Sunsoft Mapper #4", 68, Mapper68_Init}, {(uint8_t*)"SUNSOFT-5/FME-7", 69, Mapper69_Init}, {(uint8_t*)"BA KAMEN DISCRETE", 70, Mapper70_Init}, {(uint8_t*)"CAMERICA BF9093", 71, Mapper71_Init}, {(uint8_t*)"JALECO JF-17", 72, Mapper72_Init}, {(uint8_t*)"KONAMI VRC3", 73, Mapper73_Init}, {(uint8_t*)"TW MMC3+VRAM Rev. A", 74, Mapper74_Init}, {(uint8_t*)"KONAMI VRC1", 75, Mapper75_Init}, {(uint8_t*)"NAMCOT 108 Rev. A", 76, Mapper76_Init}, {(uint8_t*)"IREM LROG017", 77, Mapper77_Init}, {(uint8_t*)"Irem 74HC161/32", 78, Mapper78_Init}, {(uint8_t*)"AVE/C&E/TXC BOARD", 79, Mapper79_Init}, {(uint8_t*)"TAITO X1-005 Rev. A", 80, Mapper80_Init}, /* {(uint8_t*)"", 81, Mapper81_Init}, */ {(uint8_t*)"TAITO X1-017", 82, Mapper82_Init}, {(uint8_t*)"YOKO VRC Rev. B", 83, Mapper83_Init}, /* {(uint8_t*)"", 84, Mapper84_Init}, */ {(uint8_t*)"KONAMI VRC7", 85, Mapper85_Init}, {(uint8_t*)"JALECO JF-13", 86, Mapper86_Init}, {(uint8_t*)"74*139/74 DISCRETE", 87, Mapper87_Init}, {(uint8_t*)"NAMCO 3433", 88, Mapper88_Init}, {(uint8_t*)"SUNSOFT-3", 89, Mapper89_Init}, /* SUNSOFT-2 mapper */ {(uint8_t*)"HUMMER/JY BOARD", 90, Mapper90_Init}, {(uint8_t*)"EARLY HUMMER/JY BOARD",91, Mapper91_Init}, {(uint8_t*)"JALECO JF-19", 92, Mapper92_Init}, {(uint8_t*)"SUNSOFT-3R", 93, SUNSOFT_UNROM_Init},/* SUNSOFT-2 mapper with VRAM, different wiring */ {(uint8_t*)"HVC-UN1ROM", 94, Mapper94_Init}, {(uint8_t*)"NAMCOT 108 Rev. B", 95, Mapper95_Init}, {(uint8_t*)"BANDAI OEKAKIDS", 96, Mapper96_Init}, {(uint8_t*)"IREM TAM-S1", 97, Mapper97_Init}, /* {(uint8_t*)"", 98, Mapper98_Init}, */ {(uint8_t*)"VS Uni/Dual- system", 99, Mapper99_Init}, /* {(uint8_t*)"", 100, Mapper100_Init}, */ {(uint8_t*)"", 101, Mapper101_Init}, /* {(uint8_t*)"", 102, Mapper102_Init}, */ {(uint8_t*)"FDS DOKIDOKI FULL", 103, Mapper103_Init}, {(uint8_t*)"CAMERICA GOLDENFIVE", 104, Mapper104_Init}, {(uint8_t*)"NES-EVENT NWC1990", 105, Mapper105_Init}, {(uint8_t*)"SMB3 PIRATE A", 106, Mapper106_Init}, {(uint8_t*)"MAGIC CORP A", 107, Mapper107_Init}, {(uint8_t*)"FDS UNROM BOARD", 108, Mapper108_Init}, /* {(uint8_t*)"", 109, Mapper109_Init}, */ /* {(uint8_t*)"", 110, Mapper110_Init}, */ /* {(uint8_t*)"", 111, Mapper111_Init}, */ {(uint8_t*)"ASDER/NTDEC BOARD", 112, Mapper112_Init}, {(uint8_t*)"HACKER/SACHEN BOARD", 113, Mapper113_Init}, {(uint8_t*)"MMC3 SG PROT. A", 114, Mapper114_Init}, {(uint8_t*)"MMC3 PIRATE A", 115, Mapper115_Init}, {(uint8_t*)"MMC1/MMC3/VRC PIRATE",116, UNLSL12_Init}, {(uint8_t*)"FUTURE MEDIA BOARD", 117, Mapper117_Init}, {(uint8_t*)"TSKROM", 118, TKSROM_Init}, {(uint8_t*)"NES-TQROM", 119, Mapper119_Init}, {(uint8_t*)"FDS TOBIDASE", 120, Mapper120_Init}, {(uint8_t*)"MMC3 PIRATE PROT. A", 121, Mapper121_Init}, /* {(uint8_t*)"", 122, Mapper122_Init}, */ {(uint8_t*)"MMC3 PIRATE H2288", 123, UNLH2288_Init}, /* {(uint8_t*)"", 124, Mapper124_Init}, */ {(uint8_t*)"FDS LH32", 125, LH32_Init}, {(uint8_t*)"PowerJoy 84-in-1 PJ-008", 126, Mapper126_Init}, /* {(uint8_t*)"", 127, Mapper127_Init}, */ /* {(uint8_t*)"", 128, Mapper128_Init}, */ /* {(uint8_t*)"", 129, Mapper129_Init}, */ /* {(uint8_t*)"", 130, Mapper130_Init}, */ /* {(uint8_t*)"", 131, Mapper131_Init}, */ {(uint8_t*)"TXC/MGENIUS 22111", 132, UNL22211_Init}, {(uint8_t*)"SA72008", 133, SA72008_Init}, {(uint8_t*)"MMC3 BMC PIRATE", 134, Mapper134_Init}, /* {(uint8_t*)"", 135, Mapper135_Init}, */ {(uint8_t*)"TCU02", 136, TCU02_Init}, {(uint8_t*)"S8259D", 137, S8259D_Init}, {(uint8_t*)"S8259B", 138, S8259B_Init}, {(uint8_t*)"S8259C", 139, S8259C_Init}, {(uint8_t*)"JALECO JF-11/14", 140, Mapper140_Init}, {(uint8_t*)"S8259A", 141, S8259A_Init}, {(uint8_t*)"UNLKS7032", 142, UNLKS7032_Init}, {(uint8_t*)"TCA01", 143, TCA01_Init}, {(uint8_t*)"AGCI 50282", 144, Mapper144_Init}, {(uint8_t*)"SA72007", 145, SA72007_Init}, {(uint8_t*)"SA0161M", 146, SA0161M_Init}, {(uint8_t*)"TCU01", 147, TCU01_Init}, {(uint8_t*)"SA0037", 148, SA0037_Init}, {(uint8_t*)"SA0036", 149, SA0036_Init}, {(uint8_t*)"S74LS374N", 150, S74LS374N_Init}, {(uint8_t*)"", 151, Mapper151_Init}, {(uint8_t*)"", 152, Mapper152_Init}, {(uint8_t*)"BANDAI SRAM", 153, Mapper153_Init}, /* Bandai board 16 with SRAM instead of EEPROM */ {(uint8_t*)"", 154, Mapper154_Init}, {(uint8_t*)"", 155, Mapper155_Init}, {(uint8_t*)"", 156, Mapper156_Init}, {(uint8_t*)"BANDAI BARCODE", 157, Mapper157_Init}, {(uint8_t*)"TENGEN 800037", 158, Mapper158_Init}, {(uint8_t*)"BANDAI 24C01", 159, Mapper159_Init}, /* Different type of EEPROM on the bandai board */ {(uint8_t*)"SA009", 160, SA009_Init}, /* {(uint8_t*)"", 161, Mapper161_Init}, */ {(uint8_t*)"", 162, UNLFS304_Init}, {(uint8_t*)"", 163, Mapper163_Init}, {(uint8_t*)"", 164, Mapper164_Init}, {(uint8_t*)"", 165, Mapper165_Init}, {(uint8_t*)"SUBOR Rev. A", 166, Mapper166_Init}, {(uint8_t*)"SUBOR Rev. B", 167, Mapper167_Init}, {(uint8_t*)"", 168, Mapper168_Init}, /* {(uint8_t*)"", 169, Mapper169_Init}, */ {(uint8_t*)"", 170, Mapper170_Init}, {(uint8_t*)"", 171, Mapper171_Init}, {(uint8_t*)"", 172, Mapper172_Init}, {(uint8_t*)"", 173, Mapper173_Init}, /* {(uint8_t*)"", 174, Mapper174_Init}, */ {(uint8_t*)"", 175, Mapper175_Init}, {(uint8_t*)"BMCFK23C", 176, BMCFK23C_Init}, /* zero 26-may-2012 - well, i have some WXN junk games that use 176 for instance ????. i dont know what game uses this BMCFK23C as mapper 176. we'll have to make a note when we find it. */ {(uint8_t*)"", 177, Mapper177_Init}, {(uint8_t*)"", 178, Mapper178_Init}, /* {(uint8_t*)"", 179, Mapper179_Init}, */ {(uint8_t*)"", 180, Mapper180_Init}, {(uint8_t*)"", 181, Mapper181_Init}, /* {(uint8_t*)"", 182, Mapper182_Init}, */ /* Deprecated, dupe of Mapper 114 */ {(uint8_t*)"", 183, Mapper183_Init}, {(uint8_t*)"", 184, Mapper184_Init}, {(uint8_t*)"", 185, Mapper185_Init}, {(uint8_t*)"", 186, Mapper186_Init}, {(uint8_t*)"", 187, Mapper187_Init}, {(uint8_t*)"", 188, Mapper188_Init}, {(uint8_t*)"", 189, Mapper189_Init}, {(uint8_t*)"", 190, Mapper190_Init}, {(uint8_t*)"", 191, Mapper191_Init}, {(uint8_t*)"TW MMC3+VRAM Rev. B", 192, Mapper192_Init}, {(uint8_t*)"NTDEC TC-112", 193, Mapper193_Init}, /* War in the Gulf */ {(uint8_t*)"TW MMC3+VRAM Rev. C", 194, Mapper194_Init}, {(uint8_t*)"TW MMC3+VRAM Rev. D", 195, Mapper195_Init}, {(uint8_t*)"", 196, Mapper196_Init}, {(uint8_t*)"", 197, Mapper197_Init}, {(uint8_t*)"TW MMC3+VRAM Rev. E", 198, Mapper198_Init}, {(uint8_t*)"", 199, Mapper199_Init}, {(uint8_t*)"", 200, Mapper200_Init}, {(uint8_t*)"", 201, Mapper201_Init}, {(uint8_t*)"", 202, Mapper202_Init}, {(uint8_t*)"", 203, Mapper203_Init}, {(uint8_t*)"", 204, Mapper204_Init}, {(uint8_t*)"BMC 15-in-1/3-in-1", 205, Mapper205_Init}, {(uint8_t*)"NAMCOT 108 Rev. C", 206, Mapper206_Init}, /* Deprecated, Used to be "DEIROM" whatever it means, but actually simple version of MMC3 */ {(uint8_t*)"TAITO X1-005 Rev. B", 207, Mapper207_Init}, {(uint8_t*)"", 208, Mapper208_Init}, {(uint8_t*)"HUMMER/JY BOARD", 209, Mapper209_Init}, {(uint8_t*)"", 210, Mapper210_Init}, {(uint8_t*)"HUMMER/JY BOARD", 211, Mapper211_Init}, {(uint8_t*)"", 212, Mapper212_Init}, {(uint8_t*)"", 213, Mapper213_Init}, {(uint8_t*)"", 214, Mapper214_Init}, {(uint8_t*)"UNL-8237", 215, UNL8237_Init}, {(uint8_t*)"", 216, Mapper216_Init}, {(uint8_t*)"", 217, Mapper217_Init}, /* Redefined to a new Discrete BMC mapper */ /* {(uint8_t*)"", 218, Mapper218_Init}, */ {(uint8_t*)"UNLA9746", 219, UNLA9746_Init}, {(uint8_t*)"Debug Mapper", 220, UNLKS7057_Init}, {(uint8_t*)"UNLN625092", 221, UNLN625092_Init}, {(uint8_t*)"", 222, Mapper222_Init}, /* {(uint8_t*)"", 223, Mapper223_Init}, */ {(uint8_t*)"KT-008", 224, Mapper224_Init}, {(uint8_t*)"", 225, Mapper225_Init}, {(uint8_t*)"BMC 22+20-in-1", 226, Mapper226_Init}, {(uint8_t*)"", 227, Mapper227_Init}, {(uint8_t*)"", 228, Mapper228_Init}, {(uint8_t*)"", 229, Mapper229_Init}, {(uint8_t*)"BMC Contra+22-in-1", 230, Mapper230_Init}, {(uint8_t*)"", 231, Mapper231_Init}, {(uint8_t*)"BMC QUATTRO", 232, Mapper232_Init}, {(uint8_t*)"BMC 22+20-in-1 RST", 233, Mapper233_Init}, {(uint8_t*)"BMC MAXI", 234, Mapper234_Init}, {(uint8_t*)"", 235, Mapper235_Init}, /* {(uint8_t*)"", 236, Mapper236_Init}, */ /* {(uint8_t*)"", 237, Mapper237_Init}, */ {(uint8_t*)"UNL6035052", 238, UNL6035052_Init}, /* {(uint8_t*)"", 239, Mapper239_Init}, */ {(uint8_t*)"", 240, Mapper240_Init}, {(uint8_t*)"", 241, Mapper241_Init}, {(uint8_t*)"", 242, Mapper242_Init}, {(uint8_t*)"S74LS374NA", 243, S74LS374NA_Init}, {(uint8_t*)"DECATHLON", 244, Mapper244_Init}, {(uint8_t*)"", 245, Mapper245_Init}, {(uint8_t*)"FONG SHEN BANG", 246, Mapper246_Init}, /* {(uint8_t*)"", 247, Mapper247_Init}, */ /* {(uint8_t*)"", 248, Mapper248_Init}, */ {(uint8_t*)"", 249, Mapper249_Init}, {(uint8_t*)"", 250, Mapper250_Init}, /* {(uint8_t*)"", 251, Mapper251_Init}, */ /* No good dumps for this mapper, use UNIF version */ {(uint8_t*)"SAN GUO ZHI PIRATE", 252, Mapper252_Init}, {(uint8_t*)"DRAGON BALL PIRATE", 253, Mapper253_Init}, {(uint8_t*)"", 254, Mapper254_Init}, {(uint8_t*)"", 255, Mapper255_Init}, /* Duplicate of M225? */ {(uint8_t*)"BMC-HPxx", 260, BMCHPxx_Init}, {(uint8_t*)"UNL-SHERO", 262, UNLSHeroes_Init}, {(uint8_t*)"OK-411", 361, GN45_Init}, /* OK-411 is emulated together with GN-45 */ {(uint8_t*)"HUMMER/JY-052", 281, Mapper281_Init}, {(uint8_t*)"GN-45", 366, GN45_Init}, {(uint8_t*)"DREAMTECH01", 521, DreamTech01_Init}, {(uint8_t*)"", 0, NULL} }; int iNESLoad(const char *name, FCEUFILE *fp) { struct md5_context md5; char* mappername; uint32 mappertest; if (FCEU_fread(&head, 1, 16, fp) != 16) return 0; if (memcmp(&head, "NES\x1a", 4)) { FCEU_PrintError("Missing header or invalid iNES format file!\n"); return 0; } memset(&iNESCart, 0, sizeof(iNESCart)); if (!memcmp((char*)(&head) + 0x7, "DiskDude", 8)) { memset((char*)(&head) + 0x7, 0, 0x9); } if (!memcmp((char*)(&head) + 0x7, "demiforce", 9)) { memset((char*)(&head) + 0x7, 0, 0x9); } if (!memcmp((char*)(&head) + 0xA, "Ni03", 4)) { if (!memcmp((char*)(&head) + 0x7, "Dis", 3)) memset((char*)(&head) + 0x7, 0, 0x9); else memset((char*)(&head) + 0xA, 0, 0x6); } MapperNo = (head.ROM_type >> 4); MapperNo |= (head.ROM_type2 & 0xF0); if (head.ROM_type & 8) { Mirroring = 2; } else Mirroring = (head.ROM_type & 1); if (!head.ROM_size) ROM_size = 256; else ROM_size = uppow2(head.ROM_size); VROM_size = uppow2(head.VROM_size); if ((ROM = (uint8*)FCEU_malloc(ROM_size << 14)) == NULL) return 0; memset(ROM, 0xFF, ROM_size << 14); if (VROM_size) { if ((VROM = (uint8*)FCEU_malloc(VROM_size << 13)) == NULL) { free(ROM); ROM = NULL; return 0; } memset(VROM, 0xFF, VROM_size << 13); } if (head.ROM_type & 4) { /* Trainer */ trainerpoo = (uint8*)FCEU_gmalloc(512); FCEU_fread(trainerpoo, 512, 1, fp); } ResetCartMapping(); ResetExState(0, 0); SetupCartPRGMapping(0, ROM, ROM_size << 14, 0); if (head.ROM_size) FCEU_fread(ROM, 0x4000, head.ROM_size, fp); else FCEU_fread(ROM, 0x4000, ROM_size, fp); if (VROM_size) FCEU_fread(VROM, 0x2000, VROM_size, fp); md5_starts(&md5); if (head.ROM_size) { md5_update(&md5, ROM, head.ROM_size << 14); iNESGameCRC32 = CalcCRC32(0, ROM, head.ROM_size << 14); } else { md5_update(&md5, ROM, ROM_size << 14); iNESGameCRC32 = CalcCRC32(0, ROM, ROM_size << 14); } if (VROM_size) { iNESGameCRC32 = CalcCRC32(iNESGameCRC32, VROM, VROM_size << 13); md5_update(&md5, VROM, VROM_size << 13); } md5_finish(&md5, iNESCart.MD5); memcpy(&GameInfo->MD5, &iNESCart.MD5, sizeof(iNESCart.MD5)); iNESCart.CRC32 = iNESGameCRC32; SetInput(); CheckHInfo(); mappername = "Not Listed"; for (mappertest = 0; mappertest < (sizeof bmap / sizeof bmap[0]) - 1; mappertest++) { if (bmap[mappertest].number == MapperNo) { mappername = (char*)bmap[mappertest].name; break; } } { int x; uint64 partialmd5 = 0; for (x = 0; x < 8; x++) { partialmd5 |= (uint64)iNESCart.MD5[7 - x] << (x * 8); } FCEU_VSUniCheck(partialmd5, &MapperNo, &Mirroring); } /* Must remain here because above functions might change value of * VROM_size and free(VROM). */ if (VROM_size) SetupCartCHRMapping(0, VROM, VROM_size * 0x2000, 0); if (Mirroring == 2) { ExtraNTARAM = (uint8*)FCEU_gmalloc(2048); SetupCartMirroring(4, 1, ExtraNTARAM); } else if (Mirroring >= 0x10) SetupCartMirroring(2 + (Mirroring & 1), 1, 0); else SetupCartMirroring(Mirroring & 1, (Mirroring & 4) >> 2, 0); iNESCart.battery = (head.ROM_type & 2) ? 1 : 0; iNESCart.mirror = Mirroring; FCEU_printf(" ROM CRC32: 0x%08lx\n", iNESGameCRC32); FCEU_printf(" ROM MD5: 0x%s\n", md5_asciistr(iNESCart.MD5)); FCEU_printf(" PRG ROM: %3d x 16KiB\n", head.ROM_size ? head.ROM_size : 256); FCEU_printf(" CHR ROM: %3d x 8KiB\n", head.VROM_size); if (!iNES_Init(MapperNo)) FCEU_PrintError("iNES mapper #%d is not supported at all.", MapperNo); iNESCart.mapper = MapperNo; FCEU_printf(" \n"); FCEU_printf(" Mapper #: %3d\n", MapperNo); FCEU_printf(" Mapper name: %s\n", mappername); FCEU_printf(" Mirroring: %s\n", Mirroring == 2 ? "None (Four-screen)" : Mirroring ? "Vertical" : "Horizontal"); FCEU_printf(" Battery-backed: %s\n", (head.ROM_type & 2) ? "Yes" : "No"); FCEU_printf(" Trained: %s\n", (head.ROM_type & 4) ? "Yes" : "No"); GameInterface = iNESGI; FCEU_printf("\n"); if (strstr(name, "(E)") || strstr(name, "(e)") || strstr(name, "(Europe)") || strstr(name, "(PAL)") || strstr(name, "(F)") || strstr(name, "(f)") || strstr(name, "(G)") || strstr(name, "(g)") || strstr(name, "(I)") || strstr(name, "(i)") || strstr(name, "(S)") || strstr(name, "(s)") || strstr(name, "(France)") || strstr(name, "(Germany)") || strstr(name, "(Italy)") || strstr(name, "(Spain)") || strstr(name, "(Sweden)") || strstr(name, "(Sw)") || strstr(name, "(Australia)") || strstr(name, "(A)") || strstr(name, "(a)")) { FCEUI_SetVidSystem(1); } else FCEUI_SetVidSystem(0); return 1; } static int iNES_Init(int num) { BMAPPINGLocal *tmp = bmap; CHRRAMSize = -1; if (GameInfo->type == GIT_VSUNI) AddExState(FCEUVSUNI_STATEINFO, ~0, 0, 0); while (tmp->init) { if (num == tmp->number) { UNIFchrrama = 0; /* need here for compatibility with UNIF mapper code */ if (!VROM_size) { switch (num) { /* FIXME, mapper or game data base with the board parameters and ROM/RAM sizes */ case 13: CHRRAMSize = 16 * 1024; break; case 6: case 28: case 29: case 30: case 45: case 96: CHRRAMSize = 32 * 1024; break; case 176: CHRRAMSize = 128 * 1024; break; default: CHRRAMSize = 8 * 1024; break; } iNESCart.vram_size = CHRRAMSize; if ((VROM = (uint8*)malloc(CHRRAMSize)) == NULL) return 0; FCEU_MemoryRand(VROM, CHRRAMSize); UNIFchrrama = VROM; SetupCartCHRMapping(0, VROM, CHRRAMSize, 1); AddExState(VROM, CHRRAMSize, 0, "CHRR"); FCEU_printf(" CHR RAM: %3d x 1KiB\n", CHRRAMSize / 1024); } if (head.ROM_type & 8) AddExState(ExtraNTARAM, 2048, 0, "EXNR"); tmp->init(&iNESCart); return 1; } tmp++; } return 0; }