Files
ci-libretro-fceumm/src/unif.c
libretroadmin 808cc78833 Add mapper 528
2024-05-25 09:38:53 +02:00

852 lines
29 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", 301, UNL8157_Init, 0 },
{ "8237", 215, UNL8237_Init, 0 },
{ "8237A", 215, UNL8237A_Init, 0 },
{ "830118C", 348, BMC830118C_Init, 0 },
{ "A65AS", 285, BMCA65AS_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, UNLD2000_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, UNLYOKO_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, BMCTJ03_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, BMCK3036_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 },
{ 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;
}