mirror of
https://github.com/dborth/fceugx.git
synced 2024-11-01 06:55:05 +01:00
1106 lines
37 KiB
C++
1106 lines
37 KiB
C++
/* 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 "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 "utils/general.h"
|
|
#include "utils/memory.h"
|
|
#include "utils/crc32.h"
|
|
#include "utils/md5.h"
|
|
#include "utils/xstring.h"
|
|
#include "cheat.h"
|
|
#include "vsuni.h"
|
|
#include "driver.h"
|
|
|
|
#include <cstdio>
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
|
|
extern SFORMAT FCEUVSUNI_STATEINFO[];
|
|
|
|
//mbg merge 6/29/06 - these need to be global
|
|
uint8 *trainerpoo = NULL;
|
|
uint8 *ROM = NULL;
|
|
uint8 *VROM = NULL;
|
|
uint8 *ExtraNTARAM = NULL;
|
|
iNES_HEADER head;
|
|
|
|
#ifdef GEKKO
|
|
CartInfo iNESCart;
|
|
#else
|
|
static CartInfo iNESCart;
|
|
#endif
|
|
|
|
uint8 Mirroring = 0;
|
|
uint32 ROM_size = 0;
|
|
uint32 VROM_size = 0;
|
|
char LoadedRomFName[2048]; //mbg merge 7/17/06 added
|
|
|
|
static int CHRRAMSize = -1;
|
|
static int iNES_Init(int num);
|
|
|
|
static int MapperNo = 0;
|
|
|
|
int iNES2 = 0;
|
|
|
|
static DECLFR(TrainerRead) {
|
|
return(trainerpoo[A & 0x1FF]);
|
|
}
|
|
|
|
static void iNES_ExecPower() {
|
|
if (CHRRAMSize != -1)
|
|
FCEU_MemoryRand(VROM, CHRRAMSize);
|
|
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void iNESGI(GI h) { //bbit edited: removed static keyword
|
|
switch (h) {
|
|
case GI_RESETSAVE:
|
|
FCEU_ClearGameSave(&iNESCart);
|
|
break;
|
|
|
|
case GI_RESETM2:
|
|
if (iNESCart.Reset)
|
|
iNESCart.Reset();
|
|
break;
|
|
case GI_POWER:
|
|
iNES_ExecPower();
|
|
break;
|
|
case GI_CLOSE:
|
|
{
|
|
FCEU_SaveGameSave(&iNESCart);
|
|
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;
|
|
ESI input1;
|
|
ESI input2;
|
|
ESIFC 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 (bad dump)
|
|
{0xc7bcc981, 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
|
|
{0x67b126b9, SI_GAMEPAD, SI_GAMEPAD, SIFC_FAMINETSYS }, // Famicom Network System
|
|
{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;
|
|
const char *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 FCEUX.", BadROMImages[x].name);
|
|
return;
|
|
}
|
|
x++;
|
|
}
|
|
}
|
|
|
|
|
|
struct CHINF {
|
|
uint32 crc32;
|
|
int32 mapper;
|
|
int32 mirror;
|
|
const char* params;
|
|
};
|
|
|
|
static const TMasterRomInfo sMasterRomInfo[] = {
|
|
{ 0x62b51b108a01d2beULL, "bonus=0" }, //4-in-1 (FK23C8021)[p1][!].nes
|
|
{ 0x8bb48490d8d22711ULL, "bonus=0" }, //4-in-1 (FK23C8033)[p1][!].nes
|
|
{ 0xc75888d7b48cd378ULL, "bonus=0" }, //4-in-1 (FK23C8043)[p1][!].nes
|
|
{ 0xf81a376fa54fdd69ULL, "bonus=0" }, //4-in-1 (FK23Cxxxx, S-0210A PCB)[p1][!].nes
|
|
{ 0xa37eb9163e001a46ULL, "bonus=0" }, //4-in-1 (FK23C8026) [p1][!].nes
|
|
{ 0xde5ce25860233f7eULL, "bonus=0" }, //4-in-1 (FK23C8045) [p1][!].nes
|
|
{ 0x5b3aa4cdc484a088ULL, "bonus=0" }, //4-in-1 (FK23C8056) [p1][!].nes
|
|
{ 0x9342bf9bae1c798aULL, "bonus=0" }, //4-in-1 (FK23C8079) [p1][!].nes
|
|
{ 0x164eea6097a1e313ULL, "busc=1" }, //Cybernoid - The Fighting Machine (U)[!].nes -- needs bus conflict emulation
|
|
};
|
|
const TMasterRomInfo* MasterRomInfo;
|
|
TMasterRomInfoParams MasterRomInfoParams;
|
|
|
|
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[] =
|
|
{
|
|
0xc04361e499748382ULL, /* AD&D Heroes of the Lance */
|
|
0xb72ee2337ced5792ULL, /* AD&D Hillsfar */
|
|
0x2b7103b7a27bd72fULL, /* AD&D Pool of Radiance */
|
|
0x498c10dc463cfe95ULL, /* Battle Fleet */
|
|
0x854d7947a3177f57ULL, /* Crystalis */
|
|
0xfad22d265cd70820ULL, /* Downtown Special: Kunio-kun no Jidaigeki Dayo Zenin Shuugou! */
|
|
0x4a1f5336b86851b6ULL, /* DW */
|
|
0xb0bcc02c843c1b79ULL, /* DW */
|
|
0x2dcf3a98c7937c22ULL, /* DW 2 */
|
|
0x98e55e09dfcc7533ULL, /* DW 4*/
|
|
0x733026b6b72f2470ULL, /* Dw 3 */
|
|
0x6917ffcaca2d8466ULL, /* Famista '90 */
|
|
0x8da46db592a1fcf4ULL, /* Faria */
|
|
0xedba17a2c4608d20ULL, /* Final Fantasy */
|
|
0x91a6846d3202e3d6ULL, /* Final Fantasy */
|
|
0x012df596e2b31174ULL, /* Final Fantasy 1+2 */
|
|
0xf6b359a720549ecdULL, /* Final Fantasy 2 */
|
|
0x5a30da1d9b4af35dULL, /* Final Fantasy 3 */
|
|
0xd63dcc68c2b20adcULL, /* Final Fantasy J */
|
|
0x2ee3417ba8b69706ULL, /* Hydlide 3*/
|
|
0xebbce5a54cf3ecc0ULL, /* Justbreed */
|
|
0x6a858da551ba239eULL, /* Kaijuu Monogatari */
|
|
0x2db8f5d16c10b925ULL, /* Kyonshiizu 2 */
|
|
0x04a31647de80fdabULL, /* Legend of Zelda */
|
|
0x94b9484862a26cbaULL, /* Legend of Zelda */
|
|
0xa40666740b7d22feULL, /* Mindseeker */
|
|
0x82000965f04a71bbULL, /* Mirai Shinwa Jarvas */
|
|
0x77b811b2760104b9ULL, /* Mouryou Senki Madara */
|
|
0x11b69122efe86e8cULL, /* RPG Jinsei Game */
|
|
0x9aa1dc16c05e7de5ULL, /* Startropics */
|
|
0x1b084107d0878bd0ULL, /* Startropics 2*/
|
|
0xa70b495314f4d075ULL, /* Ys 3 */
|
|
0x836c0ff4f3e06e45ULL, /* 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, mask;
|
|
uint64 partialmd5 = 0;
|
|
|
|
for (x = 0; x < 8; x++)
|
|
partialmd5 |= (uint64)iNESCart.MD5[15 - x] << (x * 8);
|
|
CheckBad(partialmd5);
|
|
|
|
MasterRomInfo = NULL;
|
|
for (int i = 0; i < ARRAY_SIZE(sMasterRomInfo); i++) {
|
|
const TMasterRomInfo& info = sMasterRomInfo[i];
|
|
if (info.md5lower != partialmd5)
|
|
continue;
|
|
|
|
MasterRomInfo = &info;
|
|
if (!info.params) break;
|
|
|
|
std::vector<std::string> toks = tokenize_str(info.params, ",");
|
|
for (int j = 0; j < (int)toks.size(); j++) {
|
|
std::vector<std::string> parts = tokenize_str(toks[j], "=");
|
|
MasterRomInfoParams[parts[0]] = parts[1];
|
|
}
|
|
break;
|
|
}
|
|
|
|
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 (moo[x].mapper & 0x1000)
|
|
mask = 0xFFF;
|
|
else
|
|
mask = 0xFF;
|
|
if (MapperNo != (moo[x].mapper & mask)) {
|
|
tofix |= 1;
|
|
MapperNo = moo[x].mapper & mask;
|
|
}
|
|
}
|
|
if (moo[x].mirror >= 0) {
|
|
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), "The mapper number should be set to %d. ", MapperNo);
|
|
if (tofix & 2) {
|
|
const char *mstr[3] = { "Horizontal", "Vertical", "Four-screen" };
|
|
sprintf(gigastr + strlen(gigastr), "Mirroring should be set to \"%s\". ", 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;
|
|
|
|
//this is for games that is not the a power of 2
|
|
//mapper based for now...
|
|
//not really accurate but this works since games
|
|
//that are not in the power of 2 tends to come
|
|
//in obscure mappers themselves which supports such
|
|
//size
|
|
//Cah4e3 25.10.19: iNES 2.0 attempts to cover all
|
|
// boards including UNIF boards with non power 2
|
|
// total rom size (a lot of them with a couple of
|
|
// roms different sizes (may vary a lot)
|
|
// so we need either add here ALL ines 2.0 mappers
|
|
// with not power2 roms or change logic here
|
|
// to something more unified for ines 2.0 specific
|
|
static int not_power2[] =
|
|
{
|
|
53, 198, 228, 547
|
|
};
|
|
|
|
BMAPPINGLocal bmap[] = {
|
|
{"NROM", 0, NROM_Init},
|
|
{"MMC1", 1, Mapper1_Init},
|
|
{"UNROM", 2, UNROM_Init},
|
|
{"CNROM", 3, CNROM_Init},
|
|
{"MMC3", 4, Mapper4_Init},
|
|
{"MMC5", 5, Mapper5_Init},
|
|
{"FFE Rev. A", 6, Mapper6_Init},
|
|
{"ANROM", 7, ANROM_Init},
|
|
{"", 8, Mapper8_Init}, // Nogaems, it's worthless
|
|
{"MMC2", 9, Mapper9_Init},
|
|
{"MMC4", 10, Mapper10_Init},
|
|
{"Color Dreams", 11, Mapper11_Init},
|
|
{"REX DBZ 5", 12, Mapper12_Init},
|
|
{"CPROM", 13, CPROM_Init},
|
|
{"REX SL-1632", 14, UNLSL1632_Init},
|
|
{"100-in-1", 15, Mapper15_Init},
|
|
{"BANDAI 24C02", 16, Mapper16_Init},
|
|
{"FFE Rev. B", 17, Mapper17_Init},
|
|
{"JALECO SS880006", 18, Mapper18_Init}, // JF-NNX (EB89018-30007) boards
|
|
{"Namcot 106", 19, Mapper19_Init},
|
|
// {"", 20, Mapper20_Init},
|
|
{"Konami VRC2/VRC4 A", 21, Mapper21_Init},
|
|
{"Konami VRC2/VRC4 B", 22, Mapper22_Init},
|
|
{"Konami VRC2/VRC4 C", 23, Mapper23_Init},
|
|
{"Konami VRC6 Rev. A", 24, Mapper24_Init},
|
|
{"Konami VRC2/VRC4 D", 25, Mapper25_Init},
|
|
{"Konami VRC6 Rev. B", 26, Mapper26_Init},
|
|
{"CC-21 MI HUN CHE", 27, UNLCC21_Init}, // Former dupe for VRC2/VRC4 mapper, redefined with crc to mihunche boards
|
|
{"", 28, Mapper28_Init},
|
|
{"RET-CUFROM", 29, Mapper29_Init},
|
|
{"UNROM 512", 30, UNROM512_Init},
|
|
{"infiniteneslives-NSF", 31, Mapper31_Init},
|
|
{"IREM G-101", 32, Mapper32_Init},
|
|
{"TC0190FMC/TC0350FMR", 33, Mapper33_Init},
|
|
{"IREM I-IM/BNROM", 34, Mapper34_Init},
|
|
{"Wario Land 2", 35, UNLSC127_Init},
|
|
{"TXC Policeman", 36, Mapper36_Init},
|
|
{"PAL-ZZ SMB/TETRIS/NWC",37, Mapper37_Init},
|
|
{"Bit Corp.", 38, Mapper38_Init}, // Crime Busters
|
|
// {"", 39, Mapper39_Init},
|
|
{"SMB2j FDS", 40, Mapper40_Init},
|
|
{"CALTRON 6-in-1", 41, Mapper41_Init},
|
|
{"BIO MIRACLE FDS", 42, Mapper42_Init},
|
|
{"FDS SMB2j LF36", 43, Mapper43_Init},
|
|
{"MMC3 BMC PIRATE A", 44, Mapper44_Init},
|
|
{"MMC3 BMC PIRATE B", 45, Mapper45_Init},
|
|
{"RUMBLESTATION 15-in-1",46, Mapper46_Init},
|
|
{"NES-QJ SSVB/NWC", 47, Mapper47_Init},
|
|
{"TAITO TCxxx", 48, Mapper48_Init},
|
|
{"MMC3 BMC PIRATE C", 49, Mapper49_Init},
|
|
{"SMB2j FDS Rev. A", 50, Mapper50_Init},
|
|
{"11-in-1 BALL SERIES", 51, Mapper51_Init}, // 1993 year version
|
|
{"MMC3 BMC PIRATE D", 52, Mapper52_Init},
|
|
{"SUPERVISION 16-in-1", 53, Supervision16_Init},
|
|
// {"", 54, Mapper54_Init},
|
|
// {"", 55, Mapper55_Init},
|
|
// {"", 56, Mapper56_Init},
|
|
{"SIMBPLE BMC PIRATE A", 57, Mapper57_Init},
|
|
{"SIMBPLE BMC PIRATE B", 58, BMCGK192_Init},
|
|
{"", 59, Mapper59_Init}, // Check this out
|
|
{"SIMBPLE BMC PIRATE C", 60, BMCD1038_Init},
|
|
{"20-in-1 KAISER Rev. A",61, Mapper61_Init},
|
|
{"700-in-1", 62, Mapper62_Init},
|
|
// {"", 63, Mapper63_Init},
|
|
{"TENGEN RAMBO1", 64, Mapper64_Init},
|
|
{"IREM-H3001", 65, Mapper65_Init},
|
|
{"MHROM", 66, MHROM_Init},
|
|
{"SUNSOFT-FZII", 67, Mapper67_Init},
|
|
{"Sunsoft Mapper #4", 68, Mapper68_Init},
|
|
{"SUNSOFT-5/FME-7", 69, Mapper69_Init},
|
|
{"BA KAMEN DISCRETE", 70, Mapper70_Init},
|
|
{"CAMERICA BF9093", 71, Mapper71_Init},
|
|
{"JALECO JF-17", 72, Mapper72_Init},
|
|
{"KONAMI VRC3", 73, Mapper73_Init},
|
|
{"TW MMC3+VRAM Rev. A", 74, Mapper74_Init},
|
|
{"KONAMI VRC1", 75, Mapper75_Init},
|
|
{"NAMCOT 108 Rev. A", 76, Mapper76_Init},
|
|
{"IREM LROG017", 77, Mapper77_Init},
|
|
{"Irem 74HC161/32", 78, Mapper78_Init},
|
|
{"AVE/C&E/TXC BOARD", 79, Mapper79_Init},
|
|
{"TAITO X1-005 Rev. A", 80, Mapper80_Init},
|
|
// {"", 81, Mapper81_Init},
|
|
{"TAITO X1-017", 82, Mapper82_Init},
|
|
{"YOKO VRC Rev. B", 83, Mapper83_Init},
|
|
// {"", 84, Mapper84_Init},
|
|
{"KONAMI VRC7", 85, Mapper85_Init},
|
|
{"JALECO JF-13", 86, Mapper86_Init},
|
|
{"74*139/74 DISCRETE", 87, Mapper87_Init},
|
|
{"NAMCO 3433", 88, Mapper88_Init},
|
|
{"SUNSOFT-3", 89, Mapper89_Init}, // SUNSOFT-2 mapper
|
|
{"HUMMER/JY BOARD", 90, Mapper90_Init},
|
|
{"EARLY HUMMER/JY BOARD",91, Mapper91_Init},
|
|
{"JALECO JF-19", 92, Mapper92_Init},
|
|
{"SUNSOFT-3R", 93, SUNSOFT_UNROM_Init},// SUNSOFT-2 mapper with VRAM, different wiring
|
|
{"HVC-UN1ROM", 94, Mapper94_Init},
|
|
{"NAMCOT 108 Rev. B", 95, Mapper95_Init},
|
|
{"BANDAI OEKAKIDS", 96, Mapper96_Init},
|
|
{"IREM TAM-S1", 97, Mapper97_Init},
|
|
// {"", 98, Mapper98_Init},
|
|
{"VS Uni/Dual- system", 99, Mapper99_Init},
|
|
// {"", 100, Mapper100_Init},
|
|
{"", 101, Mapper101_Init},
|
|
// {"", 102, Mapper102_Init},
|
|
{"FDS DOKIDOKI FULL", 103, Mapper103_Init},
|
|
// {"", 104, Mapper104_Init},
|
|
{"NES-EVENT NWC1990", 105, Mapper105_Init},
|
|
{"SMB3 PIRATE A", 106, Mapper106_Init},
|
|
{"MAGIC CORP A", 107, Mapper107_Init},
|
|
{"FDS UNROM BOARD", 108, Mapper108_Init},
|
|
// {"", 109, Mapper109_Init},
|
|
// {"", 110, Mapper110_Init},
|
|
{"Cheapocabra", 111, Mapper111_Init},
|
|
{"ASDER/NTDEC BOARD", 112, Mapper112_Init},
|
|
{"HACKER/SACHEN BOARD", 113, Mapper113_Init},
|
|
{"MMC3 SG PROT. A", 114, Mapper114_Init},
|
|
{"MMC3 PIRATE A", 115, Mapper115_Init},
|
|
{"MMC1/MMC3/VRC PIRATE",116, UNLSL12_Init},
|
|
{"FUTURE MEDIA BOARD", 117, Mapper117_Init},
|
|
{"TSKROM", 118, TKSROM_Init},
|
|
{"NES-TQROM", 119, Mapper119_Init},
|
|
{"FDS TOBIDASE", 120, Mapper120_Init},
|
|
{"MMC3 PIRATE PROT. A", 121, Mapper121_Init},
|
|
// {"", 122, Mapper122_Init},
|
|
{"MMC3 PIRATE H2288", 123, UNLH2288_Init},
|
|
// {"", 124, Mapper124_Init},
|
|
{"FDS LH32", 125, LH32_Init},
|
|
// {"", 126, Mapper126_Init},
|
|
// {"", 127, Mapper127_Init},
|
|
// {"", 128, Mapper128_Init},
|
|
// {"", 129, Mapper129_Init},
|
|
// {"", 130, Mapper130_Init},
|
|
// {"", 131, Mapper131_Init},
|
|
{"TXC/MGENIUS 22111", 132, UNL22211_Init},
|
|
{"SA72008", 133, SA72008_Init},
|
|
{"MMC3 BMC PIRATE", 134, Mapper134_Init},
|
|
// {"", 135, Mapper135_Init},
|
|
{"TCU02", 136, TCU02_Init},
|
|
{"S8259D", 137, S8259D_Init},
|
|
{"S8259B", 138, S8259B_Init},
|
|
{"S8259C", 139, S8259C_Init},
|
|
{"JALECO JF-11/14", 140, Mapper140_Init},
|
|
{"S8259A", 141, S8259A_Init},
|
|
{"UNLKS7032", 142, UNLKS7032_Init},
|
|
{"TCA01", 143, TCA01_Init},
|
|
{"AGCI 50282", 144, Mapper144_Init},
|
|
{"SA72007", 145, SA72007_Init},
|
|
{"SA0161M", 146, SA0161M_Init},
|
|
{"TCU01", 147, TCU01_Init},
|
|
{"SA0037", 148, SA0037_Init},
|
|
{"SA0036", 149, SA0036_Init},
|
|
{"S74LS374N", 150, S74LS374N_Init},
|
|
{"", 151, Mapper151_Init},
|
|
{"", 152, Mapper152_Init},
|
|
{"BANDAI SRAM", 153, Mapper153_Init}, // Bandai board 16 with SRAM instead of EEPROM
|
|
{"", 154, Mapper154_Init},
|
|
{"", 155, Mapper155_Init},
|
|
{"", 156, Mapper156_Init},
|
|
{"BANDAI BARCODE", 157, Mapper157_Init},
|
|
// {"", 158, Mapper158_Init},
|
|
{"BANDAI 24C01", 159, Mapper159_Init}, // Different type of EEPROM on the bandai board
|
|
{"SA009", 160, SA009_Init},
|
|
// {"", 161, Mapper161_Init},
|
|
{"", 162, UNLFS304_Init},
|
|
{"", 163, Mapper163_Init},
|
|
{"", 164, Mapper164_Init},
|
|
{"", 165, Mapper165_Init},
|
|
{"SUBOR Rev. A", 166, Mapper166_Init},
|
|
{"SUBOR Rev. B", 167, Mapper167_Init},
|
|
{"", 168, Mapper168_Init},
|
|
// {"", 169, Mapper169_Init},
|
|
{"", 170, Mapper170_Init},
|
|
{"", 171, Mapper171_Init},
|
|
{"", 172, Mapper172_Init},
|
|
{"", 173, Mapper173_Init},
|
|
// {"", 174, Mapper174_Init},
|
|
{"", 175, Mapper175_Init},
|
|
{"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.
|
|
{"", 177, Mapper177_Init},
|
|
{"", 178, Mapper178_Init},
|
|
// {"", 179, Mapper179_Init},
|
|
{"", 180, Mapper180_Init},
|
|
{"", 181, Mapper181_Init},
|
|
// {"", 182, Mapper182_Init}, // Deprecated, dupe
|
|
{"", 183, Mapper183_Init},
|
|
{"", 184, Mapper184_Init},
|
|
{"", 185, Mapper185_Init},
|
|
{"", 186, Mapper186_Init},
|
|
{"", 187, Mapper187_Init},
|
|
{"", 188, Mapper188_Init},
|
|
{"", 189, Mapper189_Init},
|
|
{"", 190, Mapper190_Init},
|
|
{"", 191, Mapper191_Init},
|
|
{"TW MMC3+VRAM Rev. B", 192, Mapper192_Init},
|
|
{"NTDEC TC-112", 193, Mapper193_Init}, // War in the Gulf
|
|
{"TW MMC3+VRAM Rev. C", 194, Mapper194_Init},
|
|
{"TW MMC3+VRAM Rev. D", 195, Mapper195_Init},
|
|
{"", 196, Mapper196_Init},
|
|
{"", 197, Mapper197_Init},
|
|
{"TW MMC3+VRAM Rev. E", 198, Mapper198_Init},
|
|
{"", 199, Mapper199_Init},
|
|
{"", 200, Mapper200_Init},
|
|
{"", 201, Mapper201_Init},
|
|
{"", 202, Mapper202_Init},
|
|
{"", 203, Mapper203_Init},
|
|
{"", 204, Mapper204_Init},
|
|
{"", 205, Mapper205_Init},
|
|
{"NAMCOT 108 Rev. C", 206, Mapper206_Init}, // Deprecated, Used to be "DEIROM" whatever it means, but actually simple version of MMC3
|
|
{"TAITO X1-005 Rev. B", 207, Mapper207_Init},
|
|
{"", 208, Mapper208_Init},
|
|
{"", 209, Mapper209_Init},
|
|
{"", 210, Mapper210_Init},
|
|
{"", 211, Mapper211_Init},
|
|
{"", 212, Mapper212_Init},
|
|
{"", 213, Mapper213_Init},
|
|
{"", 214, Mapper214_Init},
|
|
{"", 215, UNL8237_Init},
|
|
{"", 216, Mapper216_Init},
|
|
{"", 217, Mapper217_Init}, // Redefined to a new Discrete BMC mapper
|
|
{"Magic Floor", 218, Mapper218_Init},
|
|
{"UNLA9746", 219, UNLA9746_Init},
|
|
{"Debug Mapper", 220, QTAi_Init},
|
|
{"UNLN625092", 221, UNLN625092_Init},
|
|
{"", 222, Mapper222_Init},
|
|
// {"", 223, Mapper223_Init},
|
|
// {"", 224, Mapper224_Init},
|
|
{"", 225, Mapper225_Init},
|
|
{"BMC 22+20-in-1", 226, Mapper226_Init},
|
|
{"", 227, Mapper227_Init},
|
|
{"", 228, Mapper228_Init},
|
|
{"", 229, Mapper229_Init},
|
|
{"BMC Contra+22-in-1", 230, Mapper230_Init},
|
|
{"", 231, Mapper231_Init},
|
|
{"BMC QUATTRO", 232, Mapper232_Init},
|
|
{"BMC 22+20-in-1 RST", 233, Mapper233_Init},
|
|
{"BMC MAXI", 234, Mapper234_Init},
|
|
{"", 235, Mapper235_Init},
|
|
// {"", 236, Mapper236_Init},
|
|
// {"", 237, Mapper237_Init},
|
|
{"UNL6035052", 238, UNL6035052_Init},
|
|
// {"", 239, Mapper239_Init},
|
|
{"", 240, Mapper240_Init},
|
|
{"", 241, Mapper241_Init},
|
|
{"", 242, Mapper242_Init},
|
|
{"S74LS374NA", 243, S74LS374NA_Init},
|
|
{"DECATHLON", 244, Mapper244_Init},
|
|
{"", 245, Mapper245_Init},
|
|
{"FONG SHEN BANG", 246, Mapper246_Init},
|
|
// {"", 247, Mapper247_Init},
|
|
// {"", 248, Mapper248_Init},
|
|
{"", 249, Mapper249_Init},
|
|
{"", 250, Mapper250_Init},
|
|
// {"", 251, Mapper251_Init}, // No good dumps for this mapper, use UNIF version
|
|
{"SAN GUO ZHI PIRATE", 252, Mapper252_Init},
|
|
{"DRAGON BALL PIRATE", 253, Mapper253_Init},
|
|
{"", 254, Mapper254_Init},
|
|
// {"", 255, Mapper255_Init}, // No good dumps for this mapper
|
|
|
|
//-------- Mappers 256-511 is the Supplementary Multilingual Plane ----------
|
|
//-------- Mappers 512-767 is the Supplementary Ideographic Plane -----------
|
|
//-------- Mappers 3840-4095 are for rom dumps not publicly released --------
|
|
|
|
// An attempt to make working the UNIF BOARD ROMs in INES FORMAT
|
|
// I don't know if there a complete ines 2.0 mapper list exist, so if it does,
|
|
// just redefine these numbers to any others which isn't used before
|
|
// see the ines-correct.h files for the ROMs CHR list
|
|
|
|
{"ONE-BUS Systems", 256, UNLOneBus_Init},
|
|
{"PEC-586 Computer", 257, UNLPEC586Init},
|
|
{"158B Prot Board", 258, UNL158B_Init},
|
|
{"F-15 MMC3 Based", 259, BMCF15_Init},
|
|
{"HP10xx/H20xx Boards", 260, BMCHPxx_Init},
|
|
{"810544-CA-1", 261, BMC810544CA1_Init},
|
|
{"SMD132/SMD133", 268, SMD132_SMD133_Init},
|
|
|
|
{"Impact Soft MMC3 Flash Board", 406, Mapper406_Init },
|
|
|
|
{"KONAMI QTAi Board", 547, QTAi_Init },
|
|
|
|
{"", 0, NULL}
|
|
};
|
|
|
|
int iNESLoad(const char *name, FCEUFILE *fp, int OverwriteVidMode) {
|
|
struct md5_context md5;
|
|
|
|
if (FCEU_fread(&head, 1, 16, fp) != 16 || memcmp(&head, "NES\x1A", 4))
|
|
return LOADER_INVALID_FORMAT;
|
|
|
|
head.cleanup();
|
|
|
|
memset(&iNESCart, 0, sizeof(iNESCart));
|
|
|
|
iNES2 = ((head.ROM_type2 & 0x0C) == 0x08);
|
|
if(iNES2)
|
|
{
|
|
iNESCart.ines2 = true;
|
|
iNESCart.wram_size = (head.RAM_size & 0x0F)?(64 << (head.RAM_size & 0x0F)):0;
|
|
iNESCart.battery_wram_size = (head.RAM_size & 0xF0)?(64 << ((head.RAM_size & 0xF0)>>4)):0;
|
|
iNESCart.vram_size = (head.VRAM_size & 0x0F)?(64 << (head.VRAM_size & 0x0F)):0;
|
|
iNESCart.battery_vram_size = (head.VRAM_size & 0xF0)?(64 << ((head.VRAM_size & 0xF0)>>4)):0;
|
|
iNESCart.submapper = head.ROM_type3 >> 4;
|
|
}
|
|
|
|
MapperNo = (head.ROM_type >> 4);
|
|
MapperNo |= (head.ROM_type2 & 0xF0);
|
|
if(iNES2) MapperNo |= ((head.ROM_type3 & 0x0F) << 8);
|
|
|
|
if (head.ROM_type & 8) {
|
|
Mirroring = 2;
|
|
} else
|
|
Mirroring = (head.ROM_type & 1);
|
|
|
|
int not_round_size;
|
|
if (!iNES2) {
|
|
not_round_size = head.ROM_size;
|
|
}
|
|
else {
|
|
if ((head.Upper_ROM_VROM_size & 0x0F) != 0x0F)
|
|
// simple notation
|
|
not_round_size = head.ROM_size | ((head.Upper_ROM_VROM_size & 0x0F) << 8);
|
|
else
|
|
// exponent-multiplier notation
|
|
not_round_size = ((1 << (head.ROM_size >> 2)) * ((head.ROM_size & 0b11) * 2 + 1)) >> 14;
|
|
}
|
|
|
|
if (!head.ROM_size && !iNES2)
|
|
ROM_size = 256;
|
|
else
|
|
ROM_size = uppow2(not_round_size);
|
|
|
|
VROM_size = uppow2(head.VROM_size | (iNES2?((head.Upper_ROM_VROM_size & 0xF0)<<4):0));
|
|
if (!iNES2) {
|
|
VROM_size = uppow2(head.VROM_size);
|
|
}
|
|
else {
|
|
if ((head.Upper_ROM_VROM_size & 0xF0) != 0xF0)
|
|
// simple notation
|
|
VROM_size = uppow2(head.VROM_size | ((head.Upper_ROM_VROM_size & 0xF0) << 4));
|
|
else
|
|
VROM_size = ((1 << (head.VROM_size >> 2)) * ((head.VROM_size & 0b11) * 2 + 1)) >> 13;
|
|
}
|
|
|
|
int round = true;
|
|
for (int i = 0; i != sizeof(not_power2) / sizeof(not_power2[0]); ++i) {
|
|
//for games not to the power of 2, so we just read enough
|
|
//prg rom from it, but we have to keep ROM_size to the power of 2
|
|
//since PRGCartMapping wants ROM_size to be to the power of 2
|
|
//so instead if not to power of 2, we just use head.ROM_size when
|
|
//we use FCEU_read
|
|
if (not_power2[i] == MapperNo) {
|
|
round = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
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;
|
|
FCEU_PrintError("Unable to allocate memory.");
|
|
return LOADER_HANDLED_ERROR;
|
|
}
|
|
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);
|
|
|
|
FCEU_fread(ROM, 0x4000, (round) ? ROM_size : not_round_size, fp);
|
|
|
|
if (VROM_size)
|
|
FCEU_fread(VROM, 0x2000, VROM_size, fp);
|
|
|
|
md5_starts(&md5);
|
|
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;
|
|
|
|
FCEU_printf(" PRG ROM: %d x 16KiB = %d KiB\n", round ? ROM_size : not_round_size, (round ? ROM_size : not_round_size) * 16);
|
|
FCEU_printf(" CHR ROM: %d x 8KiB = %d KiB\n", VROM_size, VROM_size * 8);
|
|
FCEU_printf(" ROM CRC32: 0x%08lx\n", iNESGameCRC32);
|
|
{
|
|
int x;
|
|
FCEU_printf(" ROM MD5: 0x");
|
|
for(x=0;x<16;x++)
|
|
FCEU_printf("%02x",iNESCart.MD5[x]);
|
|
FCEU_printf("\n");
|
|
}
|
|
|
|
const char* mappername = "Not Listed";
|
|
|
|
for (int mappertest = 0; mappertest < (sizeof bmap / sizeof bmap[0]) - 1; mappertest++) {
|
|
if (bmap[mappertest].number == MapperNo) {
|
|
mappername = bmap[mappertest].name;
|
|
break;
|
|
}
|
|
}
|
|
|
|
FCEU_printf(" Mapper #: %d\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");
|
|
if(iNES2)
|
|
{
|
|
FCEU_printf(" NES2.0 Extensions\n");
|
|
FCEU_printf(" Sub Mapper #: %d\n", iNESCart.submapper);
|
|
FCEU_printf(" Total WRAM size: %d KiB\n", (iNESCart.wram_size + iNESCart.battery_wram_size) / 1024);
|
|
FCEU_printf(" Total VRAM size: %d KiB\n", (iNESCart.vram_size + iNESCart.battery_vram_size) / 1024);
|
|
if(head.ROM_type & 2)
|
|
{
|
|
FCEU_printf(" WRAM backed by battery: %d KiB\n", iNESCart.battery_wram_size / 1024);
|
|
FCEU_printf(" VRAM backed by battery: %d KiB\n", iNESCart.battery_vram_size / 1024);
|
|
}
|
|
}
|
|
|
|
SetInput();
|
|
CheckHInfo();
|
|
{
|
|
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;
|
|
|
|
int result = iNES_Init(MapperNo);
|
|
switch(result)
|
|
{
|
|
case 0:
|
|
goto init_ok;
|
|
case 1:
|
|
FCEU_PrintError("iNES mapper #%d is not supported at all.", MapperNo);
|
|
break;
|
|
case 2:
|
|
FCEU_PrintError("Unable to allocate CHR-RAM.");
|
|
break;
|
|
}
|
|
if (ROM) free(ROM);
|
|
if (VROM) free(VROM);
|
|
if (trainerpoo) free(trainerpoo);
|
|
if (ExtraNTARAM) free(ExtraNTARAM);
|
|
ROM = NULL;
|
|
VROM = NULL;
|
|
trainerpoo = NULL;
|
|
ExtraNTARAM = NULL;
|
|
return LOADER_HANDLED_ERROR;
|
|
|
|
init_ok:
|
|
|
|
GameInfo->mappernum = MapperNo;
|
|
FCEU_LoadGameSave(&iNESCart);
|
|
|
|
strcpy(LoadedRomFName, name); //bbit edited: line added
|
|
|
|
// Extract Filename only. Should account for Windows/Unix this way.
|
|
if (strrchr(name, '/')) {
|
|
name = strrchr(name, '/') + 1;
|
|
} else if (strrchr(name, '\\')) {
|
|
name = strrchr(name, '\\') + 1;
|
|
}
|
|
|
|
GameInterface = iNESGI;
|
|
currCartInfo = &iNESCart;
|
|
FCEU_printf("\n");
|
|
|
|
// since apparently the iNES format doesn't store this information,
|
|
// guess if the settings should be PAL or NTSC from the ROM name
|
|
// TODO: MD5 check against a list of all known PAL games instead?
|
|
if (iNES2) {
|
|
FCEUI_SetVidSystem(((head.TV_system & 3) == 1) ? 1 : 0);
|
|
} else if (OverwriteVidMode) {
|
|
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 LOADER_OK;
|
|
}
|
|
|
|
// bbit edited: the whole function below was added
|
|
int iNesSave(void) {
|
|
char name[2048];
|
|
|
|
strcpy(name, LoadedRomFName);
|
|
if (strcmp(name + strlen(name) - 4, ".nes") != 0) { //para edit
|
|
strcat(name, ".nes");
|
|
}
|
|
|
|
return iNesSaveAs(name);
|
|
}
|
|
|
|
int iNesSaveAs(const char* name)
|
|
{
|
|
//adelikat: TODO: iNesSave() and this have pretty much the same code, outsource the common code to a single function
|
|
//caitsith2: done. iNesSave() now gets filename and calls iNesSaveAs with that filename.
|
|
FILE *fp;
|
|
|
|
if (GameInfo->type != GIT_CART) return 0;
|
|
if (GameInterface != iNESGI) return 0;
|
|
|
|
fp = fopen(name, "wb");
|
|
if (!fp)
|
|
return 0;
|
|
|
|
if (fwrite(&head, 1, 16, fp) != 16)
|
|
{
|
|
fclose(fp);
|
|
return 0;
|
|
}
|
|
|
|
if (head.ROM_type & 4)
|
|
{
|
|
/* Trainer */
|
|
fwrite(trainerpoo, 512, 1, fp);
|
|
}
|
|
|
|
fwrite(ROM, 0x4000, ROM_size, fp);
|
|
|
|
if (head.VROM_size)
|
|
fwrite(VROM, 0x2000, head.VROM_size, fp);
|
|
|
|
fclose(fp);
|
|
return 1;
|
|
}
|
|
|
|
//para edit: added function below
|
|
char *iNesShortFName(void) {
|
|
char *ret;
|
|
|
|
if (!(ret = strrchr(LoadedRomFName, '\\')))
|
|
{
|
|
if (!(ret = strrchr(LoadedRomFName, '/')))
|
|
return 0;
|
|
}
|
|
return ret + 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 = NULL; // need here for compatibility with UNIF mapper code
|
|
if (!VROM_size) {
|
|
if(!iNESCart.ines2)
|
|
{
|
|
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 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;
|
|
}
|
|
else
|
|
{
|
|
CHRRAMSize = iNESCart.battery_vram_size + iNESCart.vram_size;
|
|
}
|
|
if (CHRRAMSize > 0)
|
|
{
|
|
int mCHRRAMSize = (CHRRAMSize < 1024) ? 1024 : CHRRAMSize; // VPage has a resolution of 1k banks, ensure minimum allocation to prevent malicious access from NES software
|
|
if ((UNIFchrrama = VROM = (uint8*)FCEU_dmalloc(mCHRRAMSize)) == NULL) return 2;
|
|
FCEU_MemoryRand(VROM, CHRRAMSize);
|
|
SetupCartCHRMapping(0, VROM, CHRRAMSize, 1);
|
|
AddExState(VROM, CHRRAMSize, 0, "CHRR");
|
|
}
|
|
else {
|
|
// mapper 256 (OneBus) has not CHR-RAM _and_ has not CHR-ROM region in iNES file
|
|
// so zero-sized CHR should be supported at least for this mapper
|
|
VROM = NULL;
|
|
}
|
|
}
|
|
if (head.ROM_type & 8)
|
|
{
|
|
if (ExtraNTARAM != NULL)
|
|
{
|
|
AddExState(ExtraNTARAM, 2048, 0, "EXNR");
|
|
}
|
|
}
|
|
tmp->init(&iNESCart);
|
|
return 0;
|
|
}
|
|
tmp++;
|
|
}
|
|
return 1;
|
|
}
|