Implement mappers 28, 29, 31, 56, 63, 255, BMC-60311C, BMC-WS, BMC-HPxx

- Added a few mappers to the list. Tested with roms from goodnes set and some demos
- Fix IRQ for Kaiser7032/202 - Issue noticeable with SMB2/3's status status bar
This commit is contained in:
retro-wertz
2019-05-24 06:59:26 +08:00
parent 2a58bc129e
commit 005eb7bdc3
15 changed files with 872 additions and 39 deletions

79
src/boards/255.c Normal file
View File

@@ -0,0 +1,79 @@
/* FCEUmm - NES/Famicom Emulator
*
* Copyright (C) 2019 Libretro Team
*
* 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
*/
/* added 2019-5-23
* Mapper 255
* https://wiki.nesdev.com/w/index.php/INES_Mapper_225
* 115-in-1 [p1][!] CRC32 0xb39d30b4
* Seems to handle up to last game in the multicarts than m225 but causes
* graphics garbage past it, else games works fine */
#include "mapinc.h"
static uint8 preg, creg, mode, mirr;
static SFORMAT StateRegs[] =
{
{ &preg, 1, "PRG0" },
{ &creg, 1, "CHR0" },
{ &mode, 1, "MODE" },
{ &mirr, 1, "MIRR" },
{ 0 }
};
static void Sync(void) {
setprg16(0x8000, preg & ~mode);
setprg16(0xC000, preg | mode);
setchr8(creg);
setmirror(mirr ^ 1);
}
static DECLFW(M255Write) {
uint32 bank = (A >> 8 & 0x40);
preg = bank | ((A >> 6) & 0x3F);
creg = bank | (A & 0x3F);
mirr = (A >> 13) & 1;
mode = ((~A) >> 12 & 1);
Sync();
}
static void M255Power(void) {
preg = 0;
mode = 1;
Sync();
SetReadHandler(0x8000, 0xFFFF, CartBR);
SetWriteHandler(0x8000, 0xFFFF, M255Write);
}
static void M255Reset(void) {
preg = 0;
mode = 1;
Sync();
}
static void StateRestore(int version) {
Sync();
}
void Mapper255_Init(CartInfo *info) {
info->Reset = M255Reset;
info->Power = M255Power;
GameStateRestore = StateRestore;
AddExState(&StateRegs, ~0, 0, 0);
}

187
src/boards/28.c Normal file
View File

@@ -0,0 +1,187 @@
/*
* Copyright (C) 2012-2017 FCEUX team
*
* 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.
*
*/
/* added 2019-5-23
* Mapper 28 - Action 53
* http://wiki.nesdev.com/w/index.php/INES_Mapper_028 */
#include "mapinc.h"
static uint8 prg_mask_16k;
static uint8 reg, chr, prg, mode, outer;
static SFORMAT StateRegs[] = {
{&reg, 1, "REG"},
{&chr, 1, "CHR"},
{&prg, 1, "PRG"},
{&mode, 1, "MODE"},
{&outer, 1, "OUTR"},
{0}
};
void SyncMirror() {
switch (mode & 3) {
case 0: setmirror(MI_0); break;
case 1: setmirror(MI_1); break;
case 2: setmirror(MI_V); break;
case 3: setmirror(MI_H); break;
}
}
void Mirror(uint8 value)
{
if ((mode & 2) == 0) {
mode &= 0xfe;
mode |= value >> 4 & 1;
}
SyncMirror();
}
static void Sync() {
uint8 prglo;
uint8 prghi;
uint8 outb = outer << 1;
/* this can probably be rolled up, but i have no motivation to do so
* until it's been tested */
switch (mode & 0x3c) {
/* 32K modes */
case 0x00:
case 0x04:
prglo = outb;
prghi = outb | 1;
break;
case 0x10:
case 0x14:
prglo = outb & ~2 | prg << 1 & 2;
prghi = outb & ~2 | prg << 1 & 2 | 1;
break;
case 0x20:
case 0x24:
prglo = outb & ~6 | prg << 1 & 6;
prghi = outb & ~6 | prg << 1 & 6 | 1;
break;
case 0x30:
case 0x34:
prglo = outb & ~14 | prg << 1 & 14;
prghi = outb & ~14 | prg << 1 & 14 | 1;
break;
/* bottom fixed modes */
case 0x08:
prglo = outb;
prghi = outb | prg & 1;
break;
case 0x18:
prglo = outb;
prghi = outb & ~2 | prg & 3;
break;
case 0x28:
prglo = outb;
prghi = outb & ~6 | prg & 7;
break;
case 0x38:
prglo = outb;
prghi = outb & ~14 | prg & 15;
break;
/* top fixed modes */
case 0x0c:
prglo = outb | prg & 1;
prghi = outb | 1;
break;
case 0x1c:
prglo = outb & ~2 | prg & 3;
prghi = outb | 1;
break;
case 0x2c:
prglo = outb & ~6 | prg & 7;
prghi = outb | 1;
break;
case 0x3c:
prglo = outb & ~14 | prg & 15;
prghi = outb | 1;
break;
}
prglo &= prg_mask_16k;
prghi &= prg_mask_16k;
setprg16(0x8000, prglo);
setprg16(0xC000, prghi);
setchr8(chr);
}
static DECLFW(WriteEXP) {
reg = V & 0x81;
}
static DECLFW(WritePRG) {
switch (reg) {
case 0x00:
chr = V & 3;
Mirror(V);
Sync();
break;
case 0x01:
prg = V & 15;
Mirror(V);
Sync();
break;
case 0x80:
mode = V & 63;
SyncMirror();
Sync();
break;
case 0x81:
outer = V & 63;
Sync();
break;
}
}
static void M28Power(void) {
outer = 63;
prg = 15;
Sync();
prg_mask_16k = PRGsize[0] - 1;
SetWriteHandler(0x5000,0x5FFF,WriteEXP);
SetWriteHandler(0x8000,0xFFFF,WritePRG);
SetReadHandler(0x8000,0xFFFF,CartBR);
SetReadHandler(0x6000,0x7FFF,CartBR);
SetWriteHandler(0x6000,0x7FFF,CartBW);
}
static void M28Reset(void) {
outer = 63;
prg = 15;
Sync();
}
static void StateRestore(int version) {
Sync();
}
void Mapper28_Init(CartInfo* info) {
info->Power=M28Power;
info->Reset=M28Reset;
GameStateRestore=StateRestore;
AddExState(&StateRegs, ~0, 0, 0);
}

66
src/boards/31.c Normal file
View File

@@ -0,0 +1,66 @@
/* FCEUmm - NES/Famicom Emulator
*
* Copyright (C) 2019 Libretro Team
*
* 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
*/
/* added 2019-5-23
* Mapper 31 - custom mapper by infiniteneslives
* https://wiki.nesdev.com/w/index.php/INES_Mapper_031 */
#include "mapinc.h"
static uint8 preg[8];
static SFORMAT StateRegs[] =
{
{ preg, 8, "PREG" },
{ 0 }
};
static void Sync(void) {
setprg4(0x8000, preg[0]);
setprg4(0x9000, preg[1]);
setprg4(0xA000, preg[2]);
setprg4(0xB000, preg[3]);
setprg4(0xC000, preg[4]);
setprg4(0xD000, preg[5]);
setprg4(0xE000, preg[6]);
setprg4(0xF000, preg[7]);
setchr8(0);
}
static DECLFW(M31Write) {
preg[A & 7] = V;
Sync();
}
static void M31Power(void) {
preg[7] = ~0;
Sync();
SetReadHandler(0x8000, 0xFFFF, CartBR);
SetWriteHandler(0x5000, 0x5FFF, M31Write);
}
static void StateRestore(int version) {
Sync();
}
void Mapper31_Init(CartInfo *info) {
info->Power = M31Power;
GameStateRestore = StateRestore;
AddExState(&StateRegs, ~0, 0, 0);
}

View File

@@ -2,6 +2,7 @@
*
* Copyright notice for this file:
* Copyright (C) 2007 CaH4e3
* Copyright (C) 2019 Libretro Team (IRQ Update)
*
* 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
@@ -21,43 +22,99 @@
*
*/
/* added 2019-5-23
* - Mapper 56 - UNL KS202
* FDS Conversion: Super Mario Bros. 3 (Pirate, Alt)
* similar to M142 but use WRAM instead? $D000 additional IRQ trigger
* - fix IRQ counter, noticeable in status bars of both SMB2J(KS7032) and SMB3J(KS202)
*/
#include "mapinc.h"
static uint8 reg[8], cmd, IRQa = 0, isirqused = 0;
static int32 IRQCount;
static uint8 reg[8], creg[8], mirr, cmd, IRQa = 0, isirqused = 0;
static int32 IRQCount, IRQLatch;
static uint8 KS7032;
static uint8 *WRAM = NULL;
static uint32 WRAMSIZE;
static SFORMAT StateRegs[] =
static SFORMAT StateRegsKS7032[] =
{
{ &cmd, 1, "CMD" },
{ reg, 8, "REGS" },
{ &IRQa, 1, "IRQA" },
{ &IRQCount, 4, "IRQC" },
{ &IRQCount, 4 | FCEUSTATE_RLSB, "IRQC" },
{ 0 }
};
static SFORMAT StateRegsKS202[] =
{
{ creg, 8, "CREG" },
{ &mirr, 1, "MIRR" },
{ 0 }
};
static void Sync(void) {
setprg8(0x6000, reg[4]);
setprg8(0x8000, reg[1]);
setprg8(0xA000, reg[2]);
setprg8(0xC000, reg[3]);
setprg8(0x8000, reg[0]);
setprg8(0xA000, reg[1]);
setprg8(0xC000, reg[2]);
setprg8(0xE000, ~0);
setchr8(0);
if (KS7032)
setprg8(0x6000, reg[3]);
else {
setprg8r(0x10, 0x6000, 0);
setchr1(0x0000, creg[0]);
setchr1(0x0400, creg[1]);
setchr1(0x0800, creg[2]);
setchr1(0x0C00, creg[3]);
setchr1(0x1000, creg[4]);
setchr1(0x1400, creg[5]);
setchr1(0x1800, creg[6]);
setchr1(0x1C00, creg[7]);
setmirror(mirr);
}
}
static DECLFW(UNLKS7032Write) {
/* FCEU_printf("bs %04x %02x\n",A,V); */
switch (A & 0xF000) {
/* case 0x8FFF: reg[4]=V; Sync(); break; */
case 0x8000: X6502_IRQEnd(FCEU_IQEXT); IRQCount = (IRQCount & 0x000F) | (V & 0x0F); isirqused = 1; break;
case 0x9000: X6502_IRQEnd(FCEU_IQEXT); IRQCount = (IRQCount & 0x00F0) | ((V & 0x0F) << 4); isirqused = 1; break;
case 0xA000: X6502_IRQEnd(FCEU_IQEXT); IRQCount = (IRQCount & 0x0F00) | ((V & 0x0F) << 8); isirqused = 1; break;
case 0xB000: X6502_IRQEnd(FCEU_IQEXT); IRQCount = (IRQCount & 0xF000) | (V << 12); isirqused = 1; break;
case 0xC000: if (isirqused) {
X6502_IRQEnd(FCEU_IQEXT); IRQa = 1;
}
break;
case 0x8000: IRQLatch = (IRQLatch & 0xFFF0) | (V & 0x0F); break;
case 0x9000: IRQLatch = (IRQLatch & 0xFF0F) | ((V & 0x0F) << 4); break;
case 0xA000: IRQLatch = (IRQLatch & 0xF0FF) | ((V & 0x0F) << 8); break;
case 0xB000: IRQLatch = (IRQLatch & 0x0FFF) | (V << 12); break;
case 0xC000:
IRQa = (V & 0xF);
if (IRQa)
IRQCount = IRQLatch;
X6502_IRQEnd(FCEU_IQEXT); break;
case 0xD000: X6502_IRQEnd(FCEU_IQEXT); break;
case 0xE000: cmd = V & 7; break;
case 0xF000: reg[cmd] = V; Sync(); break;
case 0xF000: {
uint8 bank = (cmd - 1);
if (bank < 3)
reg[bank] = reg[bank] & 0x10 | V & 0x0F;
else if (bank < 4)
reg[bank] = V;
Sync();
switch (A & 0xFC00) {
case 0xF000:
A &= 3;
if (A < 3)
reg[bank] = reg[bank] & 0x0F | V & 0x10;
Sync();
break;
case 0xF800:
mirr = (V & 1);
Sync();
break;
case 0xFC00:
creg[A & 7] = V;
Sync();
break;
}
}
break;
}
}
@@ -65,8 +122,7 @@ static void FP_FASTAPASS(1) UNLSMB2JIRQHook(int a) {
if (IRQa) {
IRQCount += a;
if (IRQCount >= 0xFFFF) {
IRQa = 0;
IRQCount = 0;
IRQCount = IRQLatch;
X6502_IRQBegin(FCEU_IQEXT);
}
}
@@ -77,6 +133,10 @@ static void UNLKS7032Power(void) {
SetReadHandler(0x6000, 0x7FFF, CartBR);
SetReadHandler(0x8000, 0xFFFF, CartBR);
SetWriteHandler(0x4020, 0xFFFF, UNLKS7032Write);
if (!KS7032) {
SetWriteHandler(0x6000, 0x7FFF, CartBW);
FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM);
}
}
static void StateRestore(int version) {
@@ -84,8 +144,27 @@ static void StateRestore(int version) {
}
void UNLKS7032_Init(CartInfo *info) {
KS7032 = 1;
info->Power = UNLKS7032Power;
MapIRQHook = UNLSMB2JIRQHook;
GameStateRestore = StateRestore;
AddExState(&StateRegs, ~0, 0, 0);
AddExState(&StateRegsKS7032, ~0, 0, 0);
}
void UNLKS202_Init(CartInfo *info) {
KS7032 = 0;
info->Power = UNLKS7032Power;
MapIRQHook = UNLSMB2JIRQHook;
GameStateRestore = StateRestore;
AddExState(&StateRegsKS7032, ~0, 0, 0);
AddExState(&StateRegsKS202, ~0, 0, 0);
WRAMSIZE = 8192;
WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE);
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
}
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
}

View File

@@ -195,6 +195,37 @@ void Mapper61_Init(CartInfo *info) {
Latch_Init(info, M61Sync, NULL, 0x0000, 0x8000, 0xFFFF, 0);
}
/*------------------ Map 063 ---------------------------*/
/* added 2019-5-23
* Mapper 63 NTDEC-Multicart
* http://wiki.nesdev.com/w/index.php/INES_Mapper_063
* - Powerful 250-in-1
* - Hello Kitty 255-in-1 */
static DECLFR(M63Read) {
if (latche & 0x0300)
return X.DB;
return CartBR(A);
}
static void M63Sync(void) {
uint16 mode = latche & 2;
uint16 prg_bank = (latche & 0x3F8) >> 1;
uint16 prg16 = (latche & 4) >> 1;
setprg8(0x8000, (prg_bank | (mode ? 0 : prg16 | 0)));
setprg8(0xA000, (prg_bank | (mode ? 1 : prg16 | 1)));
setprg8(0xC000, (prg_bank | (mode ? 2 : prg16 | 0)));
setprg8(0xE000, ((latche & 0x800) ? ((latche & 0x7C) | ((latche & 6) ? 3 : 1)) :
(prg_bank | (mode ? 3 : (prg16 | 1)))));
setchr8(0);
setmirror((latche & 1) ^ 1);
}
void Mapper63_Init(CartInfo *info) {
Latch_Init(info, M63Sync, NULL, 0x0000, 0x8000, 0xFFFF, 0);
}
/*------------------ Map 092 ---------------------------*/
/* Another two-in-one mapper, two Jaleco carts uses similar
* hardware, but with different wiring.

110
src/boards/bmc60311c.c Normal file
View File

@@ -0,0 +1,110 @@
/* FCEUmm - NES/Famicom Emulator
*
* Copyright (C) 2019 Libretro Team
*
* 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
*/
/* added 2019-5-23
* UNIF: BMC-60311C:
* https://wiki.nesdev.com/w/index.php/NES_2.0_Mapper_289
*/
#include "mapinc.h"
static uint8 inner_bank, outer_bank, mode;
static SFORMAT StateRegs[] =
{
{ &inner_bank, 1, "INB0" },
{ &outer_bank, 1, "OUTB" },
{ &mode, 1, "MODE" },
{ 0 }
};
static void Sync(void) {
uint8 bbank = (mode & 4) ? 0 : (inner_bank & 7);
uint8 bank = outer_bank | bbank;
uint8 preg[2];
/* 0: NROM-128: Same inner/outer 16 KiB bank at CPU $8000-$BFFF
* and $C000-$FFFF
* 1: NROM-256: 32 kiB bank at CPU $8000-$FFFF (Selected inner/outer bank SHR 1)
* 2: UNROM: Inner/outer bank at CPU $8000-BFFF,
* fixed inner bank 7 within outer bank at $C000-$FFFF
* 3: Unknown
*
* The combined inner/outer bank is simply the inner bank, selected by the
* latch at $8000-$FFFF (or 0 if the latch is disabled) ORed with the
* outer bank selected by $6001, without any bit shifting.
*/
preg[0] = bank;
switch (mode & 3) {
case 0x00:
case 0x01:
preg[1] = bank | ((mode & 1) ? 1 : 0);
break;
case 0x02:
preg[1] = outer_bank | 7;
case 0x03:
break;
}
setchr8(0);
setprg16(0x8000, preg[0]);
setprg16(0xC000, preg[1]);
SetupCartMirroring(((mode & 8) >> 3) ^ 1, 1, NULL);
}
static DECLFW(Write0) {
mode = V;
Sync();
}
static DECLFW(Write1) {
outer_bank = V;
Sync();
}
static DECLFW(Write8) {
inner_bank = V;
Sync();
}
static void BMC60311CPower(void) {
inner_bank = outer_bank = mode = 0;
Sync();
SetReadHandler(0x8000, 0xFFFF, CartBR);
SetWriteHandler(0x6000, 0x6000, Write0);
SetWriteHandler(0x6001, 0x6001, Write1);
SetWriteHandler(0x8000, 0xFFFF, Write8);
}
static void BMC60311CReset(void) {
inner_bank = outer_bank = mode = 0;
Sync();
}
static void BMC60311CRestore(int version) {
Sync();
}
void BMC60311C_Init(CartInfo *info) {
info->Power = BMC60311CPower;
info->Reset = BMC60311CReset;
GameStateRestore = BMC60311CRestore;
AddExState(&StateRegs, ~0, 0, 0);
}

View File

@@ -225,6 +225,22 @@ void CPROM_Init(CartInfo *info) {
Latch_Init(info, CPROMSync, 0, 0x8000, 0xFFFF, 0, 0);
}
/*------------------ Map 29 ---------------------------*/
/* added 2019-5-23
* Mapper 28, used by homebrew game Glider
* https://wiki.nesdev.com/w/index.php/INES_Mapper_029 */
static void M29Sync(void) {
setprg16(0x8000, (latche >> 2) & 7);
setprg16(0xc000, ~0);
setchr8r(0, latche & 3);
setprg8r(0x10, 0x6000, 0);
}
void Mapper29_Init(CartInfo *info) {
Latch_Init(info, M29Sync, 0x0000, 0x6000, 0xFFFF, 1, 0);
}
/*------------------ Map 38 ---------------------------*/
static void M38Sync(void) {

171
src/boards/hp10xx_hp20xx.c Normal file
View File

@@ -0,0 +1,171 @@
/* FCE Ultra - NES/Famicom Emulator
*
* Copyright notice for this file:
* Copyright (C) 2017 CaH4e3
*
* 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 "mapinc.h"
#include "mmc3.h"
#include "../ines.h"
/* added on 2019-5-23 - NES 2.0 Mapper 260
* HP10xx/HP20xx - a simplified version of FK23C mapper with pretty strict and better
* organized banking behaviour. It seems that some 176 mapper assigned game may be
* actually this kind of board instead but in common they aren't compatible at all,
* the games on the regular FK23C boards couldn't run on this mapper and vice versa...
*/
static uint8 unromchr, lock;
static uint32 dipswitch;
static void BMCHPxxCW(uint32 A, uint8 V) {
if (EXPREGS[0] & 4) { /* custom banking */
switch(EXPREGS[0] & 3) {
case 0:
case 1:
setchr8(EXPREGS[2] & 0x3F);
/* FCEU_printf("\tCHR8 %02X\n",EXPREGS[2]&0x3F); */
break;
case 2:
setchr8((EXPREGS[2] & 0x3E) | (unromchr & 1));
/* FCEU_printf("\tCHR8 %02X\n",(EXPREGS[2]&0x3E)|(unromchr&1)); */
break;
case 3:
setchr8((EXPREGS[2] & 0x3C) | (unromchr & 3));
/* FCEU_printf("\tCHR8 %02X\n",(EXPREGS[2]&0x3C)|(unromchr&3)); */
break;
}
} else { /* mmc3 banking */
int base, mask;
if(EXPREGS[0] & 1) { /* 128K mode */
base = EXPREGS[2] & 0x30;
mask = 0x7F;
} else { /* 256K mode */
base = EXPREGS[2] & 0x20;
mask = 0xFF;
}
/* FCEU_printf("\tCHR1 %04x:%02X\n",A,(V&mask)|(base<<3)); */
setchr1(A, (V & mask) | (base << 3));
}
}
/* PRG wrapper */
static void BMCHPxxPW(uint32 A, uint8 V) {
if(EXPREGS[0] & 4) { /* custom banking */
if((EXPREGS[0] & 0xF) == 4) { /* 16K mode */
/* FCEU_printf("\tPRG16 %02X\n",EXPREGS[1]&0x1F); */
setprg16(0x8000, EXPREGS[1] & 0x1F);
setprg16(0xC000, EXPREGS[1] & 0x1F);
} else { /* 32K modes */
/* FCEU_printf("\tPRG32 %02X\n",(EXPREGS[1]&0x1F)>>1); */
setprg32(0x8000, (EXPREGS[1] & 0x1F) >> 1);
}
} else { /* mmc3 banking */
uint8 base, mask;
if(EXPREGS[0] & 2) { /* 128K mode */
base = EXPREGS[1] & 0x18;
mask = 0x0F;
} else { /* 256K mode */
base = EXPREGS[1] & 0x10;
mask = 0x1F;
}
/* FCEU_printf("\tPRG8 %02X\n",(V&mask)|(base<<1)); */
setprg8(A, (V & mask) | (base << 1));
setprg8r(0x10, 0x6000, A001B & 3);
}
}
/* MIRROR wrapper */
static void BMCHPxxMW(uint8 V) {
if(EXPREGS[0] & 4) { /* custom banking */
/* FCEU_printf("CUSTOM MIRR: %d\n",(unromchr>>2)&1); */
setmirror(((unromchr >> 2) & 1) ^ 1);
} else { /* mmc3 banking */
/* FCEU_printf("MMC3 MIRR: %d\n",(V&1)^1); */
A000B = V;
setmirror((A000B & 1) ^ 1);
}
}
/* PRG handler ($8000-$FFFF) */
static DECLFW(BMCHPxxHiWrite) {
/* FCEU_printf("HI WRITE %04X:%02X\n",A,V); */
if(EXPREGS[0] & 4) { /* custom banking */
/* FCEU_printf("CUSTOM\n"); */
unromchr = V;
FixMMC3CHR(MMC3_cmd);
} else { /* mmc3 banking */
/* FCEU_printf("MMC3\n"); */
if(A<0xC000) {
MMC3_CMDWrite(A, V);
FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(MMC3_cmd);
} else {
MMC3_IRQWrite(A, V);
}
}
}
/* EXP handler ($5000-$5FFF) */
static DECLFW(BMCHPxxWrite) {
if (!lock) {
/* FCEU_printf("LO WRITE %04X:%02X\n",A,V); */
EXPREGS[A & 3] = V;
lock = V & 0x80;
FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(MMC3_cmd);
}
}
static DECLFR(BMCHPxxRead) {
return dipswitch;
}
static void BMCHPxxReset(void) {
dipswitch++;
dipswitch &= 0xF;
lock = 0;
/* FCEU_printf("BMCHPxx dipswitch set to %d\n",dipswitch); */
EXPREGS[0] = EXPREGS[1] = EXPREGS[2] = EXPREGS[3] = 0;
MMC3RegReset();
FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(MMC3_cmd);
}
static void BMCHPxxPower(void) {
GenMMC3Power();
dipswitch = lock = 0;
EXPREGS[0] = EXPREGS[1] = EXPREGS[2] = EXPREGS[3] = 0;
FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(MMC3_cmd);
SetReadHandler(0x5000, 0x5fff, BMCHPxxRead);
SetWriteHandler(0x5000, 0x5fff, BMCHPxxWrite);
SetWriteHandler(0x8000, 0xffff, BMCHPxxHiWrite);
}
void BMCHPxx_Init(CartInfo *info) {
GenMMC3_Init(info, 256, 256, 8, 0);
cwrap = BMCHPxxCW;
pwrap = BMCHPxxPW;
mwrap = BMCHPxxMW;
info->Power = BMCHPxxPower;
info->Reset = BMCHPxxReset;
AddExState(EXPREGS, 8, 0, "EXPR");
AddExState(&unromchr, 1, 0, "UCHR");
AddExState(&dipswitch, 1, 0, "DPSW");
AddExState(&lock, 1, 0, "LOCK");
}

74
src/boards/super40in1.c Normal file
View File

@@ -0,0 +1,74 @@
/* FCEUmm - NES/Famicom Emulator
*
* Copyright (C) 2019 Libretro Team
*
* 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
*/
/* added 2019-5-23
* BMC-WS Used for Super 40-in-1 multicart
* https://wiki.nesdev.com/w/index.php/NES_2.0_Mapper_332 */
#include "mapinc.h"
static uint8 preg, creg;
static SFORMAT StateRegs[] =
{
{ &preg, 1, "PREG" },
{ &creg, 1, "CREG" },
{ 0 }
};
static void Sync(void) {
if (preg & 8) {
setprg16(0x8000, preg & 7);
setprg16(0xc000, preg & 7);
}
else
setprg32(0x8000, (preg & 6) >> 1);
setchr8(creg);
setmirror(((preg >> 4) & 1) ^ 1);
}
static DECLFW(BMCWSWrite) {
if (preg & 0x20)
return;
switch (A & 1) {
case 0: preg = V; Sync(); break;
case 1: creg = V; Sync(); break;
}
}
static void MBMCWSPower(void) {
Sync();
SetReadHandler(0x8000, 0xFFFF, CartBR);
SetWriteHandler(0x6000, 0x6001, BMCWSWrite);
}
static void BMCWSReset(void) {
}
static void StateRestore(int version) {
Sync();
}
void BMCWS_Init(CartInfo *info) {
info->Reset = BMCWSReset;
info->Power = MBMCWSPower;
GameStateRestore = StateRestore;
AddExState(&StateRegs, ~0, 0, 0);
}