Rewrite BMC-FK23C/A (m176) based on updated notes and testing

This commit is contained in:
negativeExponent
2020-03-12 23:56:55 +08:00
parent 68b8f0e120
commit 16031375d4

View File

@@ -1,7 +1,8 @@
/* FCE Ultra - NES/Famicom Emulator
/* FCEUmm - NES/Famicom Emulator
*
* Copyright notice for this file:
* Copyright (C) 2006 CaH4e3
* Copyright (C) 2020 negativeExponent
*
* 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
@@ -18,282 +19,465 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/* 2020-3-14 - Refactoring based on latest sources */
/* TODO: Add database for ines 1.0 headers */
#include "mapinc.h"
#include "mmc3.h"
#include "../ines.h"
static int is_BMCFK23CA;
static uint8 unromchr;
static uint32 dipswitch = 0;
static uint8 *CHRRAM = NULL;
static uint32 CHRRAMSize;
static uint8 *WRAM = NULL;
static uint8 *CHRRAM = NULL;
static uint32 WRAMSIZE = 0;
static uint32 CHRRAMSIZE = 0;
static void BMCFK23CCW(uint32 A, uint8 V) {
if (EXPREGS[0] & 0x40)
setchr8(EXPREGS[2] | unromchr);
else if (EXPREGS[0] & 0x20) {
setchr1r(0x10, A, V);
} else {
uint16 base=(EXPREGS[2] & 0x7F) << 3;
if (EXPREGS[3] & 2) {
int cbase = (MMC3_cmd & 0x80) << 5;
setchr1(A, V | base);
setchr1(0x0000 ^ cbase, DRegBuf[0] | base);
setchr1(0x0400 ^ cbase, EXPREGS[6] | base);
setchr1(0x0800 ^ cbase, DRegBuf[1] | base);
setchr1(0x0c00 ^ cbase, EXPREGS[7] | base);
} else
setchr1(A, V | base);
}
}
static uint8 fk23_regs[4] = { 0 };
static uint8 mmc3_regs[12] = { 0 };
static uint8 mmc3_ctrl = 0;
static uint8 mmc3_mirr = 0;
static uint8 mmc3_wram = 0;
static uint8 irq_count = 0;
static uint8 irq_latch = 0;
static uint8 irq_enabled = 0;
static uint8 irq_reload = 0;
static uint8 cnrom_chr = 0;
static uint8 dipswitch = 0;
/* some games are wired differently, and this will need to be changed.
* all the WXN games require prg_bonus = 1, and cah4e3's multicarts require prg_bonus = 0
* we'll populate this from a game database
*/
static int prg_mask;
static int prg_bonus = 1;
static uint8 is_bmcfk23ca = 0;
static uint8 subtype = 0;
/*
* prg_bonus = 0
* 4-in-1 (FK23C8021)[p1][!].nes
* 4-in-1 (FK23C8033)[p1][!].nes
* 4-in-1 (FK23C8043)[p1][!].nes
* 4-in-1 (FK23Cxxxx, S-0210A PCB)[p1][!].nes
* prg_bonus = 1
* [m176]大富翁2-上海大亨.wxn.nes
* [m176]宠物翡翠.fix.nes
* [m176]格兰帝亚.wxn.nes
* [m176]梦幻之星.wxn.nes
* [m176]水浒神兽.fix.nes
* [m176]西楚霸王.fix.nes
* [m176]超级大富翁.wxn.nes
* [m176]雄霸天下.wxn.nes
* works as-is under virtuanes m176
* [m176]三侠五义.wxn.nes
* [m176]口袋金.fix.nes
* [m176]爆笑三国.fix.nes
* needs other tweaks
* [m176]三国忠烈传.wxn.nes
* [m176]破釜沉舟.fix.nes
*/
static uint64 CartList[] =
{
0x1606b8c2aff8d942LL, /* 4-in-1 (BS-8088) [p1][!].nes */
0x62b51b108a01d2beLL, /* 4-in-1 (FK23C8021) [p1][!].nes */
0xa37eb9163e001a46LL, /* 4-in-1 (FK23C8026) [p1][!].nes */
0x8bb48490d8d22711LL, /* 4-in-1 (FK23C8033) [p1][!].nes */
0xc75888d7b48cd378LL, /* 4-in-1 (FK23C8043) [p1][!].nes */
0xde5ce25860233f7eLL, /* 4-in-1 (FK23C8045) [p1][!].nes */
0x8b6c9fc7769a5500LL, /* 4-in-1 (FK23C8052) [p1][!].nes */
0x5b3aa4cdc484a088LL, /* 4-in-1 (FK23C8056) [p1][!].nes */
0x497344d14c308a1aLL, /* 4-in-1 (FK23C8078) (Ch) [p1].nes */
0x9342bf9bae1c798aLL, /* 4-in-1 (FK23C8079) [p1][!].nes */
0xf81a376fa54fdd69LL, /* 4-in-1 (FK23Cxxxx, S-0210A PCB)[p1][!].nes */
0x8fd9c235957a6df0LL, /* 5-in-1 (K5003) [p1][!]-1125) (Ch).nes */
0x0315924d00dd7807LL, /* Mortal Kombat 30 Peoples (DH1043) (Ch).nes */
0x4b99c39fdb66128aLL, /* 4-in-1 (FK23C8078) (Ch) [p1][U][!].unf */
0x22a0ba5743191778LL, /* Rockman 4 MI (Hack) */
0
static SFORMAT StateRegs[] = {
{ fk23_regs, 4, "EXPR" },
{ mmc3_regs, 12, "M3RG" },
{ &cnrom_chr, 1, "CCHR" },
{ &dipswitch, 1, "DPSW" },
{ &mmc3_ctrl, 1, "M3CT" },
{ &mmc3_mirr, 1, "M3MR" },
{ &mmc3_wram, 1, "M3WR" },
{ &irq_reload, 1, "IRQR" },
{ &irq_count, 1, "IRQC" },
{ &irq_latch, 1, "IRQL" },
{ &irq_enabled, 1, "IRQA" },
{ 0 }
};
static int DetectPRGbonus(CartInfo *tmp) {
int x, i = 0;
uint64 partialmd5 = 0;
#define INVERT_PRG (mmc3_ctrl & 0x40)
#define INVERT_CHR (mmc3_ctrl & 0x80)
#define WRAM_ENABLED (mmc3_wram & 0x80)
#define WRAM_EXTENDED (mmc3_wram & 0x20)
#define FK23_ENABLED (mmc3_wram & 0x40)
#define MMC3_EXTENDED (fk23_regs[3] & 0x02)
#define CHR_CNROM_MODE (fk23_regs[0] & 0x40)
#define CHR_OUTER_BANK_SIZE (fk23_regs[0] & 0x10)
for (x = 0; x < 8; x++)
partialmd5 |= (uint64)tmp->MD5[15 - x] << (x * 8);
while (CartList[i] != 0) {
if (CartList[i] == partialmd5) {
return (0);
}
i++;
}
return (1);
static void cwrap(uint16 A, uint16 V)
{
uint8 bank = 0;
/* some workaround for chr rom / ram access */
if (!UNIFchrrama && !CHRRAMSIZE)
fk23_regs[0] &= ~0x20; /* chr rom with no chr ram always write to bank 0 */
if (UNIFchrrama)
fk23_regs[0] &= ~0x20; /* no chr rom, then chr ram is in bank 0 through UNIFchrrama */
if (UNIFchrrama && WRAM_EXTENDED && (mmc3_wram & 0x04))
fk23_regs[0] &= ~0x20;
bank = (fk23_regs[0] & 0x20) ? 0x10 : 0;
setchr1r(bank, A, V);
}
static void BMCFK23CPW(uint32 A, uint8 V) {
/* Modified (c)May 2017 - Backport older implementations from FCEUmm
* to support big sized FK23CA carts which broke in latest commits.
*/
/* uint32 bank = (EXPREGS[1] & 0x1F); */
uint32 hiblock = ((EXPREGS[0] & 8) << 4) | ((EXPREGS[0] & 0x80) << 1) | (UNIFchrrama ? ((EXPREGS[2] & 0x40) << 3) : 0);
uint32 block = (EXPREGS[1] & 0x60) | hiblock;
uint32 extra = (EXPREGS[3] & 2);
static void SyncCHR(void)
{
if (CHR_CNROM_MODE)
{
uint8 cnrom_mode = fk23_regs[3] & 0x46;
uint8 mask = cnrom_mode ? (CHR_OUTER_BANK_SIZE ? 0x01 : 0x03) : 0;
uint16 bank = (fk23_regs[2] | (cnrom_chr & mask)) << 3;
switch (EXPREGS[0] & 7) {
case 4:
setprg32(0x8000,(EXPREGS[1] | block) >> 1);
break;
case 3:
setprg16(0x8000,(EXPREGS[1] | block));
setprg16(0xC000,(EXPREGS[1] | block));
break;
default:
if (EXPREGS[0] & 3) {
uint32 blocksize = (6) - (EXPREGS[0] & 3);
uint32 mask = (1 << blocksize) - 1;
V &= mask;
/* V &= 63; */ /* ??? is this a good idea? */
V |= EXPREGS[1] << 1;
setprg8(A, (V | (hiblock << 1)));
} else
setprg8(A, ((V & prg_mask) | (block << 1)));
if (extra) {
setprg8(0xC000, EXPREGS[4]);
setprg8(0xE000, EXPREGS[5]);
}
break;
}
setprg8r(0x10, 0x6000, A001B & 3);
cwrap(0x0000, bank);
cwrap(0x0400, bank + 1);
cwrap(0x0800, bank + 2);
cwrap(0x0C00, bank + 3);
cwrap(0x1000, bank + 4);
cwrap(0x1400, bank + 5);
cwrap(0x1800, bank + 6);
cwrap(0x1C00, bank + 7);
}
else
{
uint16 cbase = INVERT_CHR ? 0x1000 : 0;
if (MMC3_EXTENDED)
{
uint16 outer = fk23_regs[2] << 3;
cwrap(cbase ^ 0x0000, mmc3_regs[0] | outer);
cwrap(cbase ^ 0x0400, mmc3_regs[10] | outer);
cwrap(cbase ^ 0x0800, mmc3_regs[1] | outer);
cwrap(cbase ^ 0x0c00, mmc3_regs[11] | outer);
cwrap(cbase ^ 0x1000, mmc3_regs[2] | outer);
cwrap(cbase ^ 0x1400, mmc3_regs[3] | outer);
cwrap(cbase ^ 0x1800, mmc3_regs[4] | outer);
cwrap(cbase ^ 0x1c00, mmc3_regs[5] | outer);
}
else
{
uint8 mask = CHR_OUTER_BANK_SIZE ? 0x7F : 0xFF;
uint16 outer = (fk23_regs[2] << 3) & ~mask;
cwrap(cbase ^ 0x0000, ((mmc3_regs[0] & 0xFE) & mask) | outer);
cwrap(cbase ^ 0x0400, ((mmc3_regs[0] | 0x01) & mask) | outer);
cwrap(cbase ^ 0x0800, ((mmc3_regs[1] & 0xFE) & mask) | outer);
cwrap(cbase ^ 0x0C00, ((mmc3_regs[1] | 0x01) & mask) | outer);
cwrap(cbase ^ 0x1000, (mmc3_regs[2] & mask) | outer);
cwrap(cbase ^ 0x1400, (mmc3_regs[3] & mask) | outer);
cwrap(cbase ^ 0x1800, (mmc3_regs[4] & mask) | outer);
cwrap(cbase ^ 0x1c00, (mmc3_regs[5] & mask) | outer);
}
}
}
static DECLFW(BMCFK23CHiWrite) {
if (EXPREGS[0] & 0x40) {
if (EXPREGS[0] & 0x30)
unromchr = 0;
else {
unromchr = V & 3;
FixMMC3CHR(MMC3_cmd);
}
} else {
if ((A == 0x8001) && (EXPREGS[3] & 2 && MMC3_cmd & 8)) {
EXPREGS[4 | (MMC3_cmd & 3)] = V;
FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(MMC3_cmd);
} else
if (A < 0xC000) {
if (UNIFchrrama) { /* hacky... strange behaviour, must be bit scramble due to pcb layot restrictions
* check if it not interfer with other dumps
*/
if ((A == 0x8000) && (V == 0x46))
V = 0x47;
else if ((A==0x8000) && (V == 0x47))
V = 0x46;
}
MMC3_CMDWrite(A, V);
FixMMC3PRG(MMC3_cmd);
} else
MMC3_IRQWrite(A, V);
}
static void SyncPRG(void)
{
uint8 prg_mode = fk23_regs[0] & 7;
uint16 prg_base = (fk23_regs[1] & 0x07F) | ((fk23_regs[0] << 4) & 0x080) | ((fk23_regs[0] << 1) & 0x100) | ((fk23_regs[2] << 3) & 0x600) | ((fk23_regs[2] << 6) & 0x800);
switch (prg_mode)
{
case 4:
setprg32(0x8000, prg_base >> 1);
break;
case 3:
setprg16(0x8000, prg_base);
setprg16(0xC000, prg_base);
break;
case 0:
case 1:
case 2:
if (MMC3_EXTENDED)
{
uint16 cbase = INVERT_PRG ? 0x4000 : 0;
uint16 outer = prg_base << 1;
setprg8(0x8000 ^ cbase, mmc3_regs[6] | outer);
setprg8(0xA000, mmc3_regs[7] | outer);
setprg8(0xC000 ^ cbase, mmc3_regs[8] | outer);
setprg8(0xE000, mmc3_regs[9] | outer);
}
else
{
uint8 mask = 0x3F >> prg_mode;
uint16 outer = (prg_base << 1) & ~mask;
uint16 cbase = INVERT_PRG ? 0x4000 : 0;
setprg8(0x8000 ^ cbase, (mmc3_regs[6] & mask) | outer);
setprg8(0xA000, (mmc3_regs[7] & mask) | outer);
setprg8(0xC000 ^ cbase, (0xFE & mask) | outer);
setprg8(0xE000, (0xFF & mask) | outer);
}
break;
}
}
static DECLFW(BMCFK23CWrite) {
if (A & (1 << (dipswitch + 4))) {
int remap = 0;
EXPREGS[A & 3] = V;
/* sometimes writing to reg0 causes remappings to occur. we think the 2 signifies this.
* if not, 0x24 is a value that is known to work
* however, the low 4 bits are known to control the mapping mode,
* so 0x20 is more likely to be the immediate remap flag
*/
remap |= ((EXPREGS[0] & 0xF0) == 0x20);
/* this is an actual mapping reg. i think reg0 controls what happens
* when reg1 is written. anyway, we have to immediately remap these
*/
remap |= (A & 3) == 1;
/* this too. */
remap |= (A & 3) == 2;
if (remap) {
FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(MMC3_cmd);
}
}
if (is_BMCFK23CA)
if(EXPREGS[3] & 2)
EXPREGS[0] &= ~7; /* hacky hacky! if someone wants extra banking,
* then for sure doesn't want mode 4 for it!
* (allow to run A version boards on normal mapper)
*/
static void SyncWRAM(void)
{
/* TODO: WRAM Protected mode when not in extended mode */
if (WRAM_ENABLED || WRAM_EXTENDED)
{
if (WRAM_EXTENDED)
{
/* FIXME:this does not look normal, but it works, $5000-$5fff */
setprg8r(0x10, 0x4000, (mmc3_wram & 0x03) + 1);
setprg8r(0x10, 0x6000, mmc3_wram & 0x03);
}
else
setprg8r(0x10, 0x6000, 0);
}
}
static void BMCFK23CReset(void) {
/* !NOT NECESSARY ANYMORE!
*
* this little hack makes sure that we try all the dip switch settings eventually, if we reset enough
* dipswitch++;
* dipswitch&=7;
* printf("BMCFK23C dipswitch set to %d\n",dipswitch);
*/
EXPREGS[0] = EXPREGS[1] = EXPREGS[2] = EXPREGS[3] = 0;
EXPREGS[4] = EXPREGS[5] = EXPREGS[6] = EXPREGS[7] = 0xFF;
MMC3RegReset();
FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(MMC3_cmd);
static void SyncMIR(void)
{
switch (mmc3_mirr & (WRAM_EXTENDED ? 0x03 : 0x01))
{
case 0: setmirror(MI_V); break;
case 1: setmirror(MI_H); break;
case 2: setmirror(MI_0); break;
case 3: setmirror(MI_1); break;
}
}
static void BMCFK23CPower(void) {
GenMMC3Power();
dipswitch = 0;
EXPREGS[0] = EXPREGS[1] = EXPREGS[2] = EXPREGS[3] = 0;
EXPREGS[4] = EXPREGS[5] = EXPREGS[6] = EXPREGS[7] = 0xFF;
SetWriteHandler(0x5000, 0x5fff, BMCFK23CWrite);
SetWriteHandler(0x8000, 0xFFFF, BMCFK23CHiWrite);
FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(MMC3_cmd);
static void Sync(void)
{
SyncPRG();
SyncCHR();
SyncWRAM();
SyncMIR();
}
static void BMCFK23CAPower(void) {
GenMMC3Power();
dipswitch = 0;
EXPREGS[0] = EXPREGS[1] = EXPREGS[2] = EXPREGS[3] = 0;
EXPREGS[4] = EXPREGS[5] = EXPREGS[6] = EXPREGS[7] = 0xFF;
SetWriteHandler(0x5000, 0x5fff, BMCFK23CWrite);
SetWriteHandler(0x8000, 0xFFFF, BMCFK23CHiWrite);
FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(MMC3_cmd);
static DECLFW(WriteLo)
{
if (((WRAM_EXTENDED == 0) || FK23_ENABLED) && (A & (0x10 << dipswitch)))
{
fk23_regs[A & 3] = V;
cnrom_chr = 0;
SyncPRG();
SyncCHR();
}
else
/* FK23C Registers disabled, $5000-$5FFF maps to the second 4 KiB of the 8 KiB WRAM bank 2 */
CartBW(A, V);
}
static void BMCFK23CAClose(void) {
if (CHRRAM)
FCEU_gfree(CHRRAM);
CHRRAM=NULL;
static DECLFW(WriteHi)
{
if (CHR_CNROM_MODE && ((A < 0xA000) || (A >= 0xC000)))
{
cnrom_chr = V & 3;
if ((fk23_regs[0] & 0x07) == 0x03)
cnrom_chr = 0;
SyncCHR();
}
switch (A & 0xE000)
{
case 0x8000:
case 0x9000:
case 0xC000:
case 0xD000:
case 0xE000:
if (CHR_CNROM_MODE)
{
if ((fk23_regs[0] & 0x07) == 0x03)
cnrom_chr = 0;
else
cnrom_chr = V & 3;
SyncCHR();
}
break;
}
switch (A & 0xE001)
{
case 0x8000:
{
uint8 old_ctrl = mmc3_ctrl;
/* Subtype 2, 8192 or more KiB PRG-ROM, no CHR-ROM: Like Subtype 0,
* but MMC3 registers $46 and $47 swapped. */
if (UNIFchrrama && ((ROM_size << 4) > 8192))
{
if (V == 0x46)
V = 0x47;
else if (V == 0x47)
V = 0x46;
}
mmc3_ctrl = V;
if (INVERT_PRG != (old_ctrl & 0x40))
SyncPRG();
if (INVERT_CHR != (old_ctrl & 0x80))
SyncCHR();
break;
}
case 0x8001:
{
uint8 ctrl_mask = MMC3_EXTENDED ? 0x0F : 0x07;
if ((mmc3_ctrl & ctrl_mask) < 12)
{
mmc3_regs[mmc3_ctrl & ctrl_mask] = V;
if (((mmc3_ctrl & ctrl_mask) < 6) || ((mmc3_ctrl & ctrl_mask) >= 10))
SyncCHR();
else
SyncPRG();
}
break;
}
case 0xA000:
mmc3_mirr = V;
SyncMIR();
break;
case 0xA001:
/* ignore bits when ram config register is disabled */
if ((V & 0x20) == 0)
V &= 0xC0;
mmc3_wram = V;
Sync();
break;
case 0xC000:
irq_latch = V;
break;
case 0xC001:
irq_reload = 1;
break;
case 0xE000:
X6502_IRQEnd(FCEU_IQEXT);
irq_enabled = 0;
break;
case 0xE001:
irq_enabled = 1;
break;
}
}
void BMCFK23C_Init(CartInfo *info) {
is_BMCFK23CA = 0;
static void IRQHook(void)
{
if (!irq_count || irq_reload)
irq_count = irq_latch;
else
irq_count--;
GenMMC3_Init(info, 512, 256, 8, 0);
cwrap = BMCFK23CCW;
pwrap = BMCFK23CPW;
info->Power = BMCFK23CPower;
info->Reset = BMCFK23CReset;
if (!irq_count && irq_enabled)
X6502_IRQBegin(FCEU_IQEXT);
AddExState(EXPREGS, 8, 0, "EXPR");
AddExState(&unromchr, 1, 0, "UCHR");
AddExState(&dipswitch, 1, 0, "DPSW");
prg_bonus = DetectPRGbonus(info);
prg_mask = (0x7F >> prg_bonus);
irq_reload = 0;
}
void BMCFK23CA_Init(CartInfo *info) {
is_BMCFK23CA = 1;
static void Reset(void)
{
/* this little hack makes sure that we try all the dip switch settings eventually, if we reset enough */
/*if (is_bmcfk23ca) {
dipswitch = (dipswitch + 1) & 7;
printf("BMCFK23C dipswitch set to $%04x\n",0x5000|0x10 << dipswitch);
}*/
GenMMC3_Init(info, 512, 256, 8, 0);
cwrap=BMCFK23CCW;
pwrap=BMCFK23CPW;
info->Power=BMCFK23CAPower;
info->Reset=BMCFK23CReset;
info->Close=BMCFK23CAClose;
fk23_regs[0] = fk23_regs[1] = fk23_regs[2] = fk23_regs[3] = 0;
mmc3_regs[0] = 0;
mmc3_regs[1] = 2;
mmc3_regs[2] = 4;
mmc3_regs[3] = 5;
mmc3_regs[4] = 6;
mmc3_regs[5] = 7;
mmc3_regs[6] = 0;
mmc3_regs[7] = 1;
mmc3_regs[8] = ~1;
mmc3_regs[9] = ~0;
mmc3_regs[10] = ~0;
mmc3_regs[11] = ~0;
mmc3_wram = 0x80;
mmc3_ctrl = mmc3_mirr = irq_count = irq_latch = irq_enabled = 0;
CHRRAMSize=8192;
CHRRAM=(uint8*)FCEU_gmalloc(CHRRAMSize);
SetupCartCHRMapping(0x10, CHRRAM, CHRRAMSize, 1);
AddExState(CHRRAM, CHRRAMSize, 0, "CRAM");
if (subtype == 1)
fk23_regs[1] = 0x20;
AddExState(EXPREGS, 8, 0, "EXPR");
AddExState(&unromchr, 1, 0, "UCHR");
AddExState(&dipswitch, 1, 0, "DPSW");
prg_bonus = DetectPRGbonus(info);
prg_mask = (0x7F >> prg_bonus);
Sync();
}
static void Power(void)
{
fk23_regs[0] = fk23_regs[1] = fk23_regs[2] = fk23_regs[3] = 0;
mmc3_regs[0] = 0;
mmc3_regs[1] = 2;
mmc3_regs[2] = 4;
mmc3_regs[3] = 5;
mmc3_regs[4] = 6;
mmc3_regs[5] = 7;
mmc3_regs[6] = 0;
mmc3_regs[7] = 1;
mmc3_regs[8] = ~1;
mmc3_regs[9] = ~0;
mmc3_regs[10] = ~0;
mmc3_regs[11] = ~0;
mmc3_wram = 0x80;
mmc3_ctrl = mmc3_mirr = irq_count = irq_latch = irq_enabled = 0;
if (subtype == 1)
fk23_regs[1] = 0x20;
Sync();
SetReadHandler(0x8000, 0xFFFF, CartBR);
SetWriteHandler(0x5000, 0x5fff, WriteLo);
SetWriteHandler(0x8000, 0xFFFF, WriteHi);
if (WRAMSIZE)
{
SetReadHandler(0x6000, 0x7FFF, CartBR);
SetWriteHandler(0x6000, 0x7FFF, CartBW);
FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM);
}
}
static void Close(void)
{
if (WRAM)
FCEU_gfree(WRAM);
WRAM = NULL;
if (CHRRAM)
FCEU_gfree(CHRRAM);
CHRRAM = NULL;
}
static void StateRestore(void)
{
Sync();
}
void BMCFK23C_Init(CartInfo *info)
{
is_bmcfk23ca = 0;
info->Power = Power;
info->Reset = Reset;
info->Close = Close;
GameHBIRQHook = IRQHook;
GameStateRestore = StateRestore;
AddExState(StateRegs, ~0, 0, 0);
if (((ROM_size << 4) == 1024) && ((VROM_size << 3) == 1024))
subtype = 1;
if (info->iNES2)
{
if (!UNIFchrrama)
CHRRAMSIZE = info->CHRRamSize + info->CHRRamSaveSize;
WRAMSIZE = info->PRGRamSize + info->PRGRamSaveSize;
}
else
{
if (!UNIFchrrama)
{
/* Rockman I - VI */
if (ROM_size == 128 && VROM_size == 64)
CHRRAMSIZE = 8 * 1024;
}
/* For compatibility with waixing games, set wram to 32K */
WRAMSIZE = 32 * 1024;
}
if (CHRRAMSIZE)
{
CHRRAM = (uint8 *)FCEU_gmalloc(CHRRAMSIZE);
SetupCartCHRMapping(0x10, CHRRAM, CHRRAMSIZE, 1);
AddExState(CHRRAM, CHRRAMSIZE, 0, "CRAM");
}
if (WRAMSIZE)
{
WRAM = (uint8 *)FCEU_gmalloc(WRAMSIZE);
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if (info->battery)
{
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = info->PRGRamSaveSize ? info->PRGRamSaveSize : WRAMSIZE;
}
}
}
void BMCFK23CA_Init(CartInfo *info)
{
BMCFK23C_Init(info);
is_bmcfk23ca = 1;
}