860 lines
30 KiB
C
860 lines
30 KiB
C
/* FCE Ultra - NES/Famicom Emulator
|
|
*
|
|
* Copyright notice for this file:
|
|
* 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
|
|
*/
|
|
|
|
/* TODO: Battery backup file saving, mirror force */
|
|
/* **INCOMPLETE** */
|
|
/* Override stuff: CHR RAM instead of CHR ROM, mirroring. */
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
|
|
#include "fceu-types.h"
|
|
#include "fceu.h"
|
|
#include "cart.h"
|
|
#include "unif.h"
|
|
#include "ines.h"
|
|
#include "general.h"
|
|
#include "state.h"
|
|
#include "fceu-endian.h"
|
|
#include "file.h"
|
|
#include "fceu-memory.h"
|
|
#include "input.h"
|
|
#include "md5.h"
|
|
#include "crc32.h"
|
|
|
|
#include "string/stdstring.h"
|
|
|
|
typedef struct {
|
|
char ID[4];
|
|
uint32 info;
|
|
} UNIF_HEADER;
|
|
|
|
typedef struct {
|
|
char *name;
|
|
int ines_mapper;
|
|
void (*init)(CartInfo *);
|
|
int flags;
|
|
} BMAPPING;
|
|
|
|
typedef struct {
|
|
char *name;
|
|
int (*init)(FCEUFILE *fp);
|
|
} BFMAPPING;
|
|
|
|
CartInfo UNIFCart;
|
|
|
|
static int vramo;
|
|
static int mirrortodo;
|
|
static int submapper;
|
|
static int cspecial;
|
|
static uint8 *boardname;
|
|
static uint8 *sboardname;
|
|
|
|
static uint32 CHRRAMSize;
|
|
uint8 *UNIFchrrama = 0;
|
|
|
|
static UNIF_HEADER unhead;
|
|
static UNIF_HEADER uchead;
|
|
|
|
|
|
static uint8 *malloced[32];
|
|
static uint32 mallocedsizes[32];
|
|
/* used to preserve the rom order as found in the rom file
|
|
* at least one mapper has bank 4 at the beginning for e.g. */
|
|
static uint32 prg_idx[16];
|
|
static uint32 chr_idx[16];
|
|
|
|
static uint32 prg_chip_count;
|
|
static uint32 chr_chip_count;
|
|
|
|
static uint64 UNIF_PRGROMSize, UNIF_CHRROMSize;
|
|
|
|
static int FixRomSize(uint32 size, uint32 minimum) {
|
|
uint32 x = 1;
|
|
|
|
if (size < minimum)
|
|
return minimum;
|
|
while (x < size)
|
|
x <<= 1;
|
|
return x;
|
|
}
|
|
|
|
static void FreeUNIF(void) {
|
|
int x;
|
|
if (UNIFchrrama) {
|
|
free(UNIFchrrama); UNIFchrrama = 0;
|
|
}
|
|
if (boardname) {
|
|
free(boardname); boardname = 0;
|
|
}
|
|
for (x = 0; x < 32; x++) {
|
|
if (malloced[x]) {
|
|
free(malloced[x]); malloced[x] = 0;
|
|
}
|
|
}
|
|
if (ROM) {
|
|
free(ROM); ROM = 0;
|
|
}
|
|
if (VROM) {
|
|
free(VROM); VROM = 0;
|
|
}
|
|
}
|
|
|
|
static void ResetUNIF(void) {
|
|
int x;
|
|
for (x = 0; x < 32; x++)
|
|
malloced[x] = 0;
|
|
for (x = 0; x < 16; x++)
|
|
prg_idx[x] = chr_idx[x] = 0;
|
|
vramo = 0;
|
|
boardname = 0;
|
|
mirrortodo = 0;
|
|
memset(&UNIFCart, 0, sizeof(UNIFCart));
|
|
UNIFchrrama = 0;
|
|
prg_chip_count = 0;
|
|
chr_chip_count = 0;
|
|
UNIF_PRGROMSize = 0;
|
|
UNIF_CHRROMSize = 0;
|
|
ROM_size = 0;
|
|
VROM_size = 0;
|
|
}
|
|
|
|
static void Cleanup(void) {
|
|
FreeUNIF();
|
|
ResetUNIF();
|
|
}
|
|
|
|
static uint8 exntar[2048];
|
|
|
|
static void MooMirroring(void) {
|
|
if (mirrortodo < 0x4)
|
|
/* 06-22-19 Allow override when using vertical/horizontal mirroring. */
|
|
SetupCartMirroring(mirrortodo, (mirrortodo >> 1) & 1, 0);
|
|
else if (mirrortodo == 0x4) {
|
|
SetupCartMirroring(4, 1, exntar);
|
|
AddExState(exntar, 2048, 0, "EXNR");
|
|
} else
|
|
SetupCartMirroring(0, 0, 0);
|
|
}
|
|
|
|
static int DoMirroring(FCEUFILE *fp) {
|
|
int t;
|
|
uint32 i;
|
|
if (uchead.info == 1) {
|
|
if ((t = FCEU_fgetc(fp)) == EOF)
|
|
return(0);
|
|
mirrortodo = t;
|
|
{
|
|
static char *stuffo[6] = { "Horizontal", "Vertical", "$2000", "$2400", "\"Four-screen\"", "Controlled by Mapper Hardware" };
|
|
if (t < 6)
|
|
FCEU_printf(" Name/Attribute Table Mirroring: %s\n", stuffo[t]);
|
|
}
|
|
} else {
|
|
FCEU_printf(" Incorrect Mirroring Chunk Size (%d). Data is:", uchead.info);
|
|
for (i = 0; i < uchead.info; i++) {
|
|
if ((t = FCEU_fgetc(fp)) == EOF)
|
|
return(0);
|
|
FCEU_printf(" %02x", t);
|
|
}
|
|
FCEU_printf("\n Default Name/Attribute Table Mirroring: Horizontal\n", uchead.info);
|
|
mirrortodo = 0;
|
|
}
|
|
return(1);
|
|
}
|
|
|
|
static int NAME(FCEUFILE *fp) {
|
|
char namebuf[100];
|
|
int index;
|
|
int t;
|
|
|
|
/* FCEU_printf(" Name: "); */
|
|
index = 0;
|
|
|
|
while ((t = FCEU_fgetc(fp)) > 0)
|
|
if (index < 99)
|
|
namebuf[index++] = t;
|
|
|
|
namebuf[index] = 0;
|
|
FCEU_printf(" Name: %s\n", namebuf);
|
|
|
|
if (!GameInfo->name) {
|
|
GameInfo->name = malloc(strlen(namebuf) + 1);
|
|
strcpy((char*)GameInfo->name, namebuf);
|
|
}
|
|
return(1);
|
|
}
|
|
|
|
static int DINF(FCEUFILE *fp) {
|
|
char name[100], method[100];
|
|
uint8 d, m;
|
|
uint16 y;
|
|
int t;
|
|
|
|
if (FCEU_fread(name, 1, 100, fp) != 100)
|
|
return(0);
|
|
if ((t = FCEU_fgetc(fp)) == EOF) return(0);
|
|
d = t;
|
|
if ((t = FCEU_fgetc(fp)) == EOF) return(0);
|
|
m = t;
|
|
if ((t = FCEU_fgetc(fp)) == EOF) return(0);
|
|
y = t;
|
|
if ((t = FCEU_fgetc(fp)) == EOF) return(0);
|
|
y |= t << 8;
|
|
if (FCEU_fread(method, 1, 100, fp) != 100)
|
|
return(0);
|
|
name[99] = method[99] = 0;
|
|
FCEU_printf(" Dumped by: %s\n", name);
|
|
FCEU_printf(" Dumped with: %s\n", method);
|
|
{
|
|
char *months[12] = {
|
|
"January", "February", "March", "April", "May", "June", "July",
|
|
"August", "September", "October", "November", "December"
|
|
};
|
|
FCEU_printf(" Dumped on: %s %d, %d\n", months[(m - 1) % 12], d, y);
|
|
}
|
|
return(1);
|
|
}
|
|
|
|
static int CTRL(FCEUFILE *fp) {
|
|
int t;
|
|
uint32 i;
|
|
if (uchead.info == 1) {
|
|
if ((t = FCEU_fgetc(fp)) == EOF)
|
|
return(0);
|
|
/* The information stored in this byte isn't very helpful, but it's
|
|
better than nothing...maybe.
|
|
*/
|
|
|
|
if (t & 1)
|
|
GameInfo->input[0] = GameInfo->input[1] = SI_GAMEPAD;
|
|
else
|
|
GameInfo->input[0] = GameInfo->input[1] = SI_NONE;
|
|
if (t & 2)
|
|
GameInfo->input[1] = SI_ZAPPER;
|
|
} else {
|
|
FCEU_printf(" Incorrect Control Chunk Size (%d). Data is:", uchead.info);
|
|
for (i = 0; i < uchead.info; i++) {
|
|
t = FCEU_fgetc(fp);
|
|
FCEU_printf(" %02x", t);
|
|
}
|
|
FCEU_printf("\n");
|
|
GameInfo->input[0] = GameInfo->input[1] = SI_GAMEPAD;
|
|
}
|
|
return(1);
|
|
}
|
|
|
|
static int TVCI(FCEUFILE *fp) {
|
|
int t;
|
|
if ((t = FCEU_fgetc(fp)) == EOF)
|
|
return(0);
|
|
if (t <= 2) {
|
|
char *stuffo[3] = { "NTSC", "PAL", "NTSC and PAL" };
|
|
if (t == 0)
|
|
GameInfo->vidsys = GIV_NTSC;
|
|
else if (t == 1)
|
|
GameInfo->vidsys = GIV_PAL;
|
|
FCEU_printf(" TV Standard Compatibility: %s\n", stuffo[t]);
|
|
}
|
|
return(1);
|
|
}
|
|
|
|
static int EnableBattery(FCEUFILE *fp) {
|
|
int ret = FCEU_fgetc(fp);
|
|
UNIFCart.battery = (ret > 0) ? 1 : 0;
|
|
if (UNIFCart.battery)
|
|
FCEU_printf(" Battery-backed.\n");
|
|
return(1);
|
|
}
|
|
|
|
static int LoadPRG(FCEUFILE *fp) {
|
|
int z, t;
|
|
z = uchead.ID[3] - '0';
|
|
|
|
if (z < 0 || z > 15)
|
|
return(0);
|
|
FCEU_printf(" PRG ROM %d size: %d\n", z, (int)uchead.info);
|
|
if (malloced[z])
|
|
free(malloced[z]);
|
|
t = uchead.info;
|
|
if (!(malloced[z] = (uint8*)FCEU_malloc(t)))
|
|
return(0);
|
|
mallocedsizes[z] = t;
|
|
memset(malloced[z] + uchead.info, 0xFF, t - uchead.info);
|
|
if (FCEU_fread(malloced[z], 1, uchead.info, fp) != uchead.info) {
|
|
FCEU_printf("Read Error!\n");
|
|
return(0);
|
|
}
|
|
|
|
UNIF_PRGROMSize += t;
|
|
prg_idx[prg_chip_count] = z;
|
|
prg_chip_count++;
|
|
|
|
return(1);
|
|
}
|
|
|
|
static int SetBoardName(FCEUFILE *fp) {
|
|
if (!(boardname = (uint8*)FCEU_malloc(uchead.info + 1)))
|
|
return(0);
|
|
FCEU_fread(boardname, 1, uchead.info, fp);
|
|
boardname[uchead.info] = 0;
|
|
/* strip whitespaces */
|
|
boardname = (uint8*)string_trim_whitespace((char *const)boardname);
|
|
FCEU_printf(" Board name: %s\n", boardname);
|
|
sboardname = boardname;
|
|
if (!memcmp(boardname, "NES-", 4) || !memcmp(boardname, "UNL-", 4) ||
|
|
!memcmp(boardname, "HVC-", 4) || !memcmp(boardname, "BTL-", 4) ||
|
|
!memcmp(boardname, "BMC-", 4))
|
|
sboardname += 4;
|
|
|
|
return(1);
|
|
}
|
|
|
|
static int LoadCHR(FCEUFILE *fp) {
|
|
int z, t;
|
|
z = uchead.ID[3] - '0';
|
|
if (z < 0 || z > 15)
|
|
return(0);
|
|
FCEU_printf(" CHR ROM %d size: %d\n", z, (int)uchead.info);
|
|
if (malloced[16 + z])
|
|
free(malloced[16 + z]);
|
|
t = uchead.info;
|
|
if (!(malloced[16 + z] = (uint8*)FCEU_malloc(t)))
|
|
return(0);
|
|
mallocedsizes[16 + z] = t;
|
|
memset(malloced[16 + z] + uchead.info, 0xFF, t - uchead.info);
|
|
if (FCEU_fread(malloced[16 + z], 1, uchead.info, fp) != uchead.info) {
|
|
FCEU_printf("Read Error!\n");
|
|
return(0);
|
|
}
|
|
|
|
UNIF_CHRROMSize += t;
|
|
chr_idx[chr_chip_count] = z;
|
|
chr_chip_count++;
|
|
|
|
return(1);
|
|
}
|
|
|
|
#define NO_BUSC 1
|
|
|
|
struct _unif_db {
|
|
uint64 partialMD5;
|
|
char *boardname;
|
|
int submapper;
|
|
int mirroring;
|
|
int special; /* TODO: for bus conflicts, set 1 for no bus_conflict */
|
|
};
|
|
|
|
static struct _unif_db unif_db[] = {
|
|
{ 0x03ed6963ca50e1d8ULL, "A65AS", 1, -1, -1 },
|
|
{ 0x616851e56946893bULL, "RESETNROM-XIN1", 0, MI_V, -1 }, /* Sheng Tian 2-in-1(Unl,ResetBase)[p1].unf */
|
|
{ 0x4cd729b5ae23a3cfULL, "RESETNROM-XIN1", 0, MI_H, -1 }, /* Sheng Tian 2-in-1(Unl,ResetBase)[p2].unf */
|
|
|
|
{ 0, NULL, -1, -1, -1 } /* end of the line */
|
|
};
|
|
|
|
static void CheckHashInfo(void) {
|
|
unsigned x = 0;
|
|
uint64 partialMD5 = 0;
|
|
|
|
for (x = 0; x < 8; x++)
|
|
partialMD5 |= (uint64)UNIFCart.MD5[15 - x] << (x * 8);
|
|
|
|
x = 0;
|
|
do {
|
|
if (partialMD5 == unif_db[x].partialMD5) {
|
|
FCEU_printf("\n");
|
|
FCEU_PrintError(" The UNIF header contains incorrect information.\n");
|
|
FCEU_PrintError(" For now, the information will be corrected in RAM.\n");
|
|
if (unif_db[x].boardname != NULL && strcmp((char*)unif_db[x].boardname, (char*)sboardname) != 0) {
|
|
FCEU_printf(" Boardname should be set to %s\n", unif_db[x].boardname);
|
|
sboardname = (uint8*)unif_db[x].boardname;
|
|
}
|
|
if (unif_db[x].submapper >= 0 && unif_db[x].submapper != submapper) {
|
|
FCEU_PrintError(" Submapper should be set to %d\n", unif_db[x].submapper);
|
|
submapper = unif_db[x].submapper;
|
|
}
|
|
if (unif_db[x].mirroring >= 0 && unif_db[x].mirroring != mirrortodo) {
|
|
static char *stuffo[6] = { "Horizontal", "Vertical", "$2000", "$2400", "\"Four-screen\"", "Controlled by Mapper Hardware" };
|
|
FCEU_PrintError(" Mirroring should be set to %s\n", stuffo[unif_db[x].mirroring]);
|
|
mirrortodo = unif_db[x].mirroring;
|
|
}
|
|
if (unif_db[x].special >= 0 && unif_db[x].special != cspecial) {
|
|
if (!(strcmp((char*)sboardname, "CNROM"))) {
|
|
FCEU_PrintError(" Special flags applied, No bus conflict.\n");
|
|
cspecial = unif_db[x].special;
|
|
}
|
|
}
|
|
/* todo special case aka, dipswitches, busc-like in fk23c/a, etc */
|
|
FCEU_printf("\n");
|
|
}
|
|
x++;
|
|
} while (unif_db[x].partialMD5 > 0);
|
|
|
|
}
|
|
|
|
#define NO_INES -1
|
|
#define BMCFLAG_FORCE4 0x01
|
|
#define BMCFLAG_16KCHRR 0x02
|
|
#define BMCFLAG_32KCHRR 0x04
|
|
#define BMCFLAG_128KCHRR 0x08
|
|
#define BMCFLAG_256KCHRR 0x10
|
|
|
|
static BMAPPING bmap[] = {
|
|
{ "11160", 299, BMC11160_Init, 0 },
|
|
{ "12-IN-1", 331, BMC12IN1_Init, 0 },
|
|
{ "13in1JY110", 295, Mapper295_Init, 0 },
|
|
{ "190in1", 300, BMC190in1_Init, 0 },
|
|
{ "22211", 132, Mapper132_Init, 0 },
|
|
{ "3D-BLOCK", 355, UNL3DBlock_Init, 0 },
|
|
{ "411120-C", 287, BMC411120C_Init, 0 },
|
|
{ "42in1ResetSwitch", 233, Mapper233_Init, 0 },
|
|
{ "43272", 242, Mapper242_Init, 0 },
|
|
{ "603-5052", 238, UNL6035052_Init, 0 },
|
|
{ "64in1NoRepeat", 314, BMC64in1nr_Init, 0 },
|
|
{ "70in1", 236, Mapper236_Init, 0 },
|
|
{ "70in1B", 236, Mapper236_Init, 0 },
|
|
{ "810544-C-A1", 261, BMC810544CA1_Init, 0 },
|
|
{ "8157", 242, Mapper242_Init, 0 },
|
|
{ "8237", 215, UNL8237_Init, 0 },
|
|
{ "8237A", 215, UNL8237A_Init, 0 },
|
|
{ "830118C", 348, BMC830118C_Init, 0 },
|
|
{ "A65AS", 285, Mapper285_Init, 0 },
|
|
{ "AB-G1L", 428, Mapper428_Init, 0 },
|
|
{ "WELL-NO-DG450", 428, Mapper428_Init, 0 },
|
|
{ "TF2740", 428, Mapper428_Init, 0 },
|
|
{ "AC08", 42, AC08_Init, 0 },
|
|
{ "ANROM", 7, ANROM_Init, 0 },
|
|
{ "AX5705", 530, UNLAX5705_Init, 0 },
|
|
{ "BB", 108, UNLBB_Init, 0 },
|
|
{ "BS-110", 444, Mapper444_Init, 0 }, /* Due to a mix-up, UNIF MAPR BMC-BS-110 is actually the NC7000M PCB and refers to NES 2.0 Mapper 444 instead. */
|
|
{ "831128C", 528, Mapper528_Init, 0 },
|
|
{ "BS-5", 286, BMCBS5_Init, 0 },
|
|
{ "CC-21", 27, UNLCC21_Init, 0 },
|
|
{ "CITYFIGHT", 266, UNLCITYFIGHT_Init, 0 },
|
|
{ "10-24-C-A1", 327, BMC1024CA1_Init, 0 },
|
|
{ "CNROM", 3, CNROM_Init, 0 },
|
|
{ "CPROM", 13, CPROM_Init, BMCFLAG_16KCHRR },
|
|
{ "D1038", 59, BMCD1038_Init, 0 },
|
|
{ "T3H53", 59, BMCD1038_Init, 0 },
|
|
{ "DANCE", 256, UNLOneBus_Init, 0 },
|
|
{ "DANCE2000", 518, Mapper518_Init, 0 },
|
|
{ "DREAMTECH01", 521, DreamTech01_Init, 0 },
|
|
{ "EDU2000", 329, UNLEDU2000_Init, 0 },
|
|
{ "EKROM", 5, EKROM_Init, 0 },
|
|
{ "ELROM", 5, ELROM_Init, 0 },
|
|
{ "ETROM", 5, ETROM_Init, 0 },
|
|
{ "EWROM", 5, EWROM_Init, 0 },
|
|
{ "FK23C", 176, BMCFK23C_Init, BMCFLAG_256KCHRR },
|
|
{ "FK23CA", 176, BMCFK23CA_Init, BMCFLAG_256KCHRR },
|
|
{ "FS304", 162, Mapper162_Init, 0 },
|
|
{ "G-146", 349, BMCG146_Init, 0 },
|
|
{ "GK-192", 58, Mapper58_Init, 0 },
|
|
{ "GS-2004", 283, Mapper283_Init, 0 },
|
|
{ "GS-2013", 283, Mapper283_Init, 0 },
|
|
{ "Ghostbusters63in1", 226, Mapper226_Init, 0 },
|
|
{ "G631", 226, Mapper226_Init, 0 }, /* duplicate, probably wrong name */
|
|
{ "H2288", 123, UNLH2288_Init, 0 },
|
|
{ "HKROM", 4, HKROM_Init, 0 },
|
|
{ "KOF97", 263, UNLKOF97_Init, 0 },
|
|
/* { "KONAMI-QTAI", NO_INES, Mapper190_Init, 0 }, */
|
|
{ "KS7012", 346, UNLKS7012_Init, 0 },
|
|
{ "KS7013B", 312, UNLKS7013B_Init, 0 },
|
|
{ "KS7016", 306, UNLKS7016_Init, 0 },
|
|
{ "KS7017", 303, UNLKS7017_Init, 0 },
|
|
{ "KS7030", 347, UNLKS7030_Init, 0 },
|
|
{ "KS7031", 305, UNLKS7031_Init, 0 },
|
|
{ "KS7032", 142, UNLKS7032_Init, 0 },
|
|
{ "KS7037", 307, UNLKS7037_Init, 0 },
|
|
{ "KS7057", 302, UNLKS7057_Init, 0 },
|
|
{ "LE05", NO_INES, LE05_Init, 0 },
|
|
{ "LH10", 522, LH10_Init, 0 },
|
|
{ "LH32", 125, LH32_Init, 0 },
|
|
{ "LH53", 535, LH53_Init, 0 },
|
|
{ "MALISB", 325, UNLMaliSB_Init, 0 },
|
|
{ "MARIO1-MALEE2", 42, MALEE_Init, 0 },
|
|
{ "MHROM", 66, MHROM_Init, 0 },
|
|
{ "N625092", 221, UNLN625092_Init, 0 },
|
|
{ "NROM", 0, NROM_Init, 0 },
|
|
{ "NROM-128", 0, NROM_Init, 0 },
|
|
{ "NROM-256", 0, NROM_Init, 0 },
|
|
{ "NTBROM", 68, Mapper68_Init, 0 },
|
|
{ "NTD-03", 290, BMCNTD03_Init, 0 },
|
|
{ "NovelDiamond9999999in1", 201, Novel_Init, 0 },
|
|
{ "OneBus", 256, UNLOneBus_Init, 0 },
|
|
{ "PEC-586", NO_INES, UNLPEC586Init, 0 },
|
|
{ "RROM", 0, NROM_Init, 0 },
|
|
{ "RROM-128", 0, NROM_Init, 0 },
|
|
{ "SA-002", 136, Mapper136_Init, 0 },
|
|
{ "SA-0036", 149, SA0036_Init, 0 },
|
|
{ "SA-0037", 148, SA0037_Init, 0 },
|
|
{ "SA-009", 160, SA009_Init, 0 },
|
|
{ "SA-016-1M", 146, SA0161M_Init, 0 },
|
|
{ "SA-72007", 145, SA72007_Init, 0 },
|
|
{ "SA-72008", 133, SA72008_Init, 0 },
|
|
{ "SA-9602B", 513, SA9602B_Init, BMCFLAG_32KCHRR },
|
|
{ "SA-NROM", 143, TCA01_Init, 0 },
|
|
{ "SAROM", 1, SAROM_Init, 0 },
|
|
{ "SBROM", 1, SBROM_Init, 0 },
|
|
{ "SC-127", 35, Mapper35_Init, 0 },
|
|
{ "SCROM", 1, SCROM_Init, 0 },
|
|
{ "SEROM", 1, SEROM_Init, 0 },
|
|
{ "SGROM", 1, SGROM_Init, 0 },
|
|
{ "SHERO", 262, UNLSHeroes_Init, 0 },
|
|
{ "SKROM", 1, SKROM_Init, 0 },
|
|
{ "SL12", 116, UNLSL12_Init, 0 },
|
|
{ "SL1632", 14, UNLSL1632_Init, 0 },
|
|
{ "SL1ROM", 1, SL1ROM_Init, 0 },
|
|
{ "SLROM", 1, SLROM_Init, 0 },
|
|
{ "SMB2J", 304, UNLSMB2J_Init, 0 },
|
|
{ "SNROM", 1, SNROM_Init, 0 },
|
|
{ "SOROM", 1, SOROM_Init, 0 },
|
|
{ "SSS-NROM-256", NO_INES, SSSNROM_Init, 0 },
|
|
{ "SUNSOFT_UNROM", 93, SUNSOFT_UNROM_Init, 0 }, /* fix me, real pcb name, real pcb type */
|
|
{ "Sachen-74LS374N", 150, S74LS374N_Init, 0 },
|
|
{ "Sachen-74LS374NA", 150, S74LS374N_Init, 0 }, /* seems to be custom mapper */
|
|
{ "Sachen-8259A", 141, S8259A_Init, 0 },
|
|
{ "Sachen-8259B", 138, S8259B_Init, 0 },
|
|
{ "Sachen-8259C", 139, S8259C_Init, 0 },
|
|
{ "Sachen-8259D", 137, S8259D_Init, 0 },
|
|
{ "Super24in1SC03", 176, Super24_Init, 0 },
|
|
{ "SuperHIK8in1", 45, Mapper45_Init, 0 },
|
|
{ "Supervision16in1", 53, Supervision16_Init, 0 },
|
|
{ "T-227-1", NO_INES, BMCT2271_Init, 0 },
|
|
{ "T-230", 529, UNLT230_Init, 0 },
|
|
{ "T-262", 265, Mapper265_Init, 0 },
|
|
{ "TBROM", 4, TBROM_Init, 0 },
|
|
{ "TC-U01-1.5M", 147, Mapper147_Init, 0 },
|
|
{ "TEK90", 90, Mapper90_Init, 0 },
|
|
{ "TEROM", 4, TEROM_Init, 0 },
|
|
{ "TF1201", 298, UNLTF1201_Init, 0 },
|
|
{ "TFROM", 4, TFROM_Init, 0 },
|
|
{ "TGROM", 4, TGROM_Init, 0 },
|
|
{ "TKROM", 4, TKROM_Init, 0 },
|
|
{ "TKSROM", 118, TKSROM_Init, 0 },
|
|
{ "TLROM", 4, TLROM_Init, 0 },
|
|
{ "TLSROM", 118, TLSROM_Init, 0 },
|
|
{ "TQROM", 119, TQROM_Init, 0 },
|
|
{ "TR1ROM", 4, TFROM_Init, BMCFLAG_FORCE4 },
|
|
{ "TSROM", 4, TSROM_Init, 0 },
|
|
{ "TVROM", 4, TLROM_Init, BMCFLAG_FORCE4 },
|
|
{ "Transformer", NO_INES, Transformer_Init, 0 },
|
|
{ "UNROM", 2, UNROM_Init, 0 },
|
|
{ "UNROM-512-8", 30, UNROM512_Init, 0 },
|
|
{ "UNROM-512-16", 30, UNROM512_Init, BMCFLAG_16KCHRR },
|
|
{ "UNROM-512-32", 30, UNROM512_Init, BMCFLAG_32KCHRR },
|
|
{ "UOROM", 2, UNROM_Init, 0 },
|
|
{ "VRC7", 85, UNLVRC7_Init, 0 },
|
|
{ "YOKO", 264, Mapper264_Init, 0 },
|
|
{ "COOLBOY", 268, COOLBOY_Init, BMCFLAG_256KCHRR },
|
|
{ "MINDKIDS", 268, MINDKIDS_Init, BMCFLAG_256KCHRR },
|
|
{ "158B", 258, UNL8237_Init, 0 },
|
|
{ "DRAGONFIGHTER", 292, UNLBMW8544_Init, 0 },
|
|
{ "EH8813A", 519, UNLEH8813A_Init, 0 },
|
|
{ "HP898F", 319, BMCHP898F_Init, 0 },
|
|
{ "F-15", 259, BMCF15_Init, 0 },
|
|
{ "RT-01", 328, UNLRT01_Init, 0 },
|
|
{ "81-01-31-C", NO_INES, BMC810131C_Init, 0 },
|
|
{ "8-IN-1", 333, BMC8IN1_Init, 0 },
|
|
{ "RET-CUFROM", 29, Mapper29_Init, BMCFLAG_32KCHRR },
|
|
{ "60311C", 289, BMC60311C_Init, 0 },
|
|
{ "WS", 332, BMCWS_Init, 0 },
|
|
{ "HPxx", 260, BMCHPxx_Init, 0 },
|
|
{ "HP2018-A", 260, BMCHPxx_Init, 0 },
|
|
{ "CHINA_ER_SAN2", 19, Mapper19_Init, 0 },
|
|
{ "WAIXING-FW01", 227, Mapper227_Init, 0 },
|
|
{ "WAIXING-FS005", 176, WAIXINGFS005_Init, 0 },
|
|
{ "80013-B", 274, BMC80013B_Init, 0 },
|
|
{ "TH2131-1", 308, UNLTH21311_Init, 0 },
|
|
{ "LH51", 309, LH51_Init, 0 },
|
|
{ "RESETNROM-XIN1", NO_INES, BMCRESETNROMXIN1_Init, 0 }, /* split roms */
|
|
{ "RESET-TXROM", 313, BMCRESETTXROM_Init, 0 },
|
|
{ "K-3088", 287, BMCK3088_Init, 0 },
|
|
{ "FARID_SLROM_8-IN-1", 323, FARIDSLROM8IN1_Init, 0 },
|
|
{ "830425C-4391T", 320, BMC830425C4391T_Init, 0 },
|
|
{ "TJ-03", 341, Mapper341_Init, 0 },
|
|
{ "CTC-09", 335, BMCCTC09_Init, 0 },
|
|
{ "K-3046", 336, BMCK3046_Init, 0 },
|
|
{ "SA005-A", 338, BMCSA005A_Init, 0 },
|
|
{ "K-3006", 339, BMCK3006_Init, 0 },
|
|
{ "K-3036", 340, Mapper340_Init, 0 },
|
|
{ "KS7021A", 525, UNLKS7021A_Init, 0 },
|
|
{ "KS106C", NO_INES, BMCKS106C_Init, 0 }, /* split roms */
|
|
{ "900218", 524, BTL900218_Init, 0 },
|
|
{ "JC-016-2", 205, Mapper205_Init, 0 },
|
|
{ "AX-40G", 527, UNLAX40G_Init, 0 },
|
|
{ "STREETFIGTER-GAME4IN1", NO_INES, BMCSFGAME4IN1_Init, 0 }, /* mapper 49? submapper 1*/
|
|
{ "BJ-56", 526, UNLBJ56_Init, 0 },
|
|
{ "L6IN1", 345, BMCL6IN1_Init, 0 },
|
|
{ "CTC-12IN1", 337, BMCCTC12IN1_Init, 0 },
|
|
{ "891227", 350, BMC891227_Init, 0 },
|
|
{ "NEWSTAR-GRM070-8IN1", 333, BMC8IN1_Init, 0 },
|
|
{ "FARID_UNROM_8-IN-1", 324, FARIDUNROM_Init, 0 },
|
|
{ "K-3033", 322, BMCK3033_Init, 0 },
|
|
{ "830134C", 315, BMC830134C_Init, 0 },
|
|
{ "GN-26", 344, BMCGN26_Init, 0 },
|
|
{ "KG256", NO_INES, KG256_Init, 0 },
|
|
{ "T4A54A", 134, Mapper134_Init, 0 },
|
|
{ "WX-KB4K", 134, Mapper134_Init, 0 },
|
|
{ "SB-5013", 359, Mapper359_Init, 0 },
|
|
{ "82112C", 540, Mapper540_Init, 0 },
|
|
{ "N49C-300", 369, Mapper369_Init, 0 },
|
|
{ "830752C", 396, Mapper396_Init, 0 },
|
|
|
|
{ "BS-400R", 422, Mapper422_Init, 0 },
|
|
{ "BS-4040R", 422, Mapper422_Init, 0 },
|
|
{ "22026", 271, Mapper271_Init, 0 },
|
|
{ "DS-07", 439, Mapper439_Init, 0 },
|
|
{ "K86B", 439, Mapper439_Init, 0 },
|
|
{ "COOLGIRL", 342, COOLGIRL_Init, BMCFLAG_256KCHRR },
|
|
{ "S-2009", 434, Mapper434_Init, 0 },
|
|
{ "Yhc-Unrom-Cart", 500, Mapper500_Init, 0 },
|
|
{ "Yhc-Axrom-Cart", 501, Mapper501_Init, 0 },
|
|
{ "Yhc-A/B/Uxrom-Cart", 502, Mapper502_Init, 0 },
|
|
{ "JY4M4", 537, Mapper537_Init, 0 },
|
|
{ "82112C", 540, Mapper540_Init, 0 },
|
|
{ "KN-20", 577, Mapper577_Init, 0 },
|
|
{ "820436-C", 579, Mapper579_Init, 0 },
|
|
{ "8203", 585, Mapper585_Init, 0 },
|
|
{ "K-3057", 587, Mapper587_Init, 0 },
|
|
{ NULL, NO_INES, NULL, 0 }
|
|
};
|
|
|
|
static BFMAPPING bfunc[] = {
|
|
{ "CTRL", CTRL },
|
|
{ "TVCI", TVCI },
|
|
{ "BATR", EnableBattery },
|
|
{ "MIRR", DoMirroring },
|
|
{ "PRG", LoadPRG },
|
|
{ "CHR", LoadCHR },
|
|
{ "NAME", NAME },
|
|
{ "MAPR", SetBoardName },
|
|
{ "DINF", DINF },
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
int LoadUNIFChunks(FCEUFILE *fp) {
|
|
int x;
|
|
int t;
|
|
for (;; ) {
|
|
t = FCEU_fread(&uchead, 1, 4, fp);
|
|
if (t < 4) {
|
|
if (t > 0)
|
|
return 0;
|
|
return 1;
|
|
}
|
|
if (!(FCEU_read32le(&uchead.info, fp)))
|
|
return 0;
|
|
t = 0;
|
|
x = 0;
|
|
while (bfunc[x].name) {
|
|
if (!memcmp(&uchead, bfunc[x].name, strlen(bfunc[x].name))) {
|
|
if (!bfunc[x].init(fp))
|
|
return 0;
|
|
t = 1;
|
|
break;
|
|
}
|
|
x++;
|
|
}
|
|
if (!t)
|
|
if (FCEU_fseek(fp, uchead.info, SEEK_CUR))
|
|
return(0);
|
|
}
|
|
}
|
|
|
|
static int InitializeBoard(void) {
|
|
int x = 0;
|
|
|
|
if (!sboardname) return(0);
|
|
|
|
while (bmap[x].name) {
|
|
/* ignore case during board name comparing */
|
|
if (string_is_equal_noncase((const char*)sboardname, (const char*)bmap[x].name)) {
|
|
|
|
if (VROM_size == 0) {
|
|
if (bmap[x].flags & BMCFLAG_16KCHRR)
|
|
CHRRAMSize = 16;
|
|
else if (bmap[x].flags & BMCFLAG_32KCHRR)
|
|
CHRRAMSize = 32;
|
|
else if (bmap[x].flags & BMCFLAG_128KCHRR)
|
|
CHRRAMSize = 128;
|
|
else if (bmap[x].flags & BMCFLAG_256KCHRR)
|
|
CHRRAMSize = 256;
|
|
else
|
|
CHRRAMSize = 8;
|
|
CHRRAMSize <<= 10;
|
|
if ((UNIFchrrama = (uint8*)FCEU_malloc(CHRRAMSize))) {
|
|
SetupCartCHRMapping(0, UNIFchrrama, CHRRAMSize, 1);
|
|
AddExState(UNIFchrrama, CHRRAMSize, 0, "CHRR");
|
|
} else
|
|
return(-1);
|
|
}
|
|
if (bmap[x].flags & BMCFLAG_FORCE4)
|
|
mirrortodo = 4;
|
|
MooMirroring();
|
|
|
|
UNIFCart.mapper = bmap[x].ines_mapper;
|
|
UNIFCart.submapper = submapper;
|
|
GameInfo->cspecial = cspecial;
|
|
|
|
bmap[x].init(&UNIFCart);
|
|
return(1);
|
|
}
|
|
x++;
|
|
}
|
|
FCEU_printf("\n");
|
|
FCEU_PrintError(" Board type not supported, '%s'.\n", boardname);
|
|
return(0);
|
|
}
|
|
|
|
static void UNIFGI(int h) {
|
|
switch (h) {
|
|
case GI_RESETM2:
|
|
if (UNIFCart.Reset)
|
|
UNIFCart.Reset();
|
|
break;
|
|
case GI_POWER:
|
|
if (UNIFCart.Power)
|
|
UNIFCart.Power();
|
|
if (UNIFchrrama) memset(UNIFchrrama, 0, 8192);
|
|
break;
|
|
case GI_CLOSE:
|
|
if (UNIFCart.Close)
|
|
UNIFCart.Close();
|
|
FreeUNIF();
|
|
break;
|
|
}
|
|
}
|
|
|
|
int UNIFLoad(const char *name, FCEUFILE *fp) {
|
|
struct md5_context md5;
|
|
uint64 prg_size_bytes = 0, chr_size_bytes = 0;
|
|
int x = 0;
|
|
|
|
FCEU_fseek(fp, 0, SEEK_SET);
|
|
FCEU_fread(&unhead, 1, 4, fp);
|
|
if (memcmp(&unhead, "UNIF", 4))
|
|
return 0;
|
|
|
|
ResetCartMapping();
|
|
|
|
ResetExState(0, 0);
|
|
ResetUNIF();
|
|
if (!FCEU_read32le(&unhead.info, fp)) {
|
|
Cleanup();
|
|
return 0;
|
|
}
|
|
if (FCEU_fseek(fp, 0x20, SEEK_SET) < 0) {
|
|
Cleanup();
|
|
return 0;
|
|
}
|
|
if (!LoadUNIFChunks(fp)) {
|
|
Cleanup();
|
|
return 0;
|
|
}
|
|
|
|
ROM_size = (UNIF_PRGROMSize / 0x1000) + ((UNIF_PRGROMSize % 0x1000) ? 1 : 0);
|
|
ROM_size = (ROM_size >> 2) + ((ROM_size & 3) ? 1: 0);
|
|
if (UNIF_CHRROMSize) {
|
|
VROM_size = (UNIF_CHRROMSize / 0x400) + ((UNIF_CHRROMSize % 0x400) ? 1 : 0);
|
|
VROM_size = (VROM_size >> 3) + ((VROM_size & 7) ? 1: 0);
|
|
}
|
|
|
|
UNIF_PRGROMSize = FixRomSize(UNIF_PRGROMSize, 2048);
|
|
if (UNIF_CHRROMSize)
|
|
UNIF_CHRROMSize = FixRomSize(UNIF_CHRROMSize, 8192);
|
|
|
|
/* Note: Use rounded size for memory allocations and board mapping */
|
|
|
|
if (!(ROM = (uint8*)malloc(UNIF_PRGROMSize))) {
|
|
Cleanup();
|
|
return 0;
|
|
}
|
|
if (UNIF_CHRROMSize) {
|
|
if (!(VROM = (uint8*)malloc(UNIF_CHRROMSize))) {
|
|
Cleanup();
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/* combine multiple prg/chr blocks into single blocks and free memory used. */
|
|
|
|
for (x = 0; x < 16; x++) {
|
|
int p = prg_idx[x];
|
|
int c = 16 + chr_idx[x];
|
|
if (malloced[p]) {
|
|
memcpy(ROM + prg_size_bytes, malloced[p], mallocedsizes[p]);
|
|
prg_size_bytes += mallocedsizes[p];
|
|
free(malloced[p]);
|
|
malloced[p] = 0;
|
|
}
|
|
|
|
if (malloced[c]) {
|
|
memcpy(VROM + chr_size_bytes, malloced[c], mallocedsizes[c]);
|
|
chr_size_bytes += mallocedsizes[c];
|
|
free(malloced[c]);
|
|
malloced[c] = 0;
|
|
}
|
|
}
|
|
|
|
/* Note: Use raw size in bytes for checksums */
|
|
|
|
UNIFCart.PRGRomSize = prg_size_bytes;
|
|
UNIFCart.CHRRomSize = chr_size_bytes;
|
|
|
|
UNIFCart.PRGCRC32 = CalcCRC32(0, ROM, prg_size_bytes);
|
|
UNIFCart.CHRCRC32 = CalcCRC32(0, VROM, chr_size_bytes);
|
|
UNIFCart.CRC32 = CalcCRC32(UNIFCart.PRGCRC32, VROM, chr_size_bytes);
|
|
|
|
md5_starts(&md5);
|
|
md5_update(&md5, ROM, prg_size_bytes);
|
|
if (chr_size_bytes)
|
|
md5_update(&md5, VROM, chr_size_bytes);
|
|
md5_finish(&md5, UNIFCart.MD5);
|
|
memcpy(GameInfo->MD5, UNIFCart.MD5, sizeof(UNIFCart.MD5));
|
|
|
|
CheckHashInfo();
|
|
|
|
/* Note: Use rounded size for board mappings */
|
|
|
|
SetupCartPRGMapping(0, ROM, UNIF_PRGROMSize, 0);
|
|
if (UNIF_CHRROMSize)
|
|
SetupCartCHRMapping(0, VROM, UNIF_CHRROMSize, 0);
|
|
|
|
FCEU_printf(" PRG-ROM CRC32: 0x%08X\n", UNIFCart.PRGCRC32);
|
|
FCEU_printf(" PRG+CHR CRC32: 0x%08X\n", UNIFCart.CRC32);
|
|
FCEU_printf(" PRG+CHR MD5 : 0x%s\n", md5_asciistr(UNIFCart.MD5));
|
|
|
|
if (!InitializeBoard()) {
|
|
Cleanup();
|
|
return 0;
|
|
}
|
|
|
|
FCEU_printf(" [UNIF] PRG ROM: %u KiB\n", UNIFCart.PRGRomSize / 1024);
|
|
FCEU_printf(" [UNIF] CHR ROM: %u KiB\n", UNIFCart.CHRRomSize / 1024);
|
|
FCEU_printf(" [UNIF] iNES Mapper: %d\n", UNIFCart.mapper);
|
|
FCEU_printf(" [UNIF] SubMapper: %d\n", UNIFCart.submapper);
|
|
|
|
GameInterface = UNIFGI;
|
|
|
|
return 1;
|
|
}
|