diff --git a/src/boards/528.c b/src/boards/528.c new file mode 100644 index 0000000..e9e6dc1 --- /dev/null +++ b/src/boards/528.c @@ -0,0 +1,127 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023 + * + * 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 + */ + +/* NES 2.0 Mapper 528 + * UNIF BMC-831128C + */ + +#include "mapinc.h" +#include "vrcirq.h" + +static uint8 preg[4], creg[8], mirr; +static uint8 gamesel; +static uint8 *WRAM; +static uint32 WRAMSIZE; + +static SFORMAT StateRegs[] = +{ + { preg, 4, "PREG" }, + { creg, 8, "CREG" }, + { &mirr, 1, "MIRR" }, + { &gamesel, 1, "GSEL" }, + { 0 } +}; + +static void Sync(void) { + uint8 mask = (gamesel << 4) | 0x0F; + if (preg[3] == 1) { + setprg8r(0x10, 0x6000, 0); + } else { + setprg8(0x6000, (preg[3] & mask) + gamesel); + } + setprg8(0x8000, (preg[0] & mask) + (gamesel << 4)); + setprg8(0xA000, (preg[1] & mask) + (gamesel << 4)); + setprg8(0xC000, ( ~1 & mask) + (gamesel << 4)); + setprg8(0xE000, ( ~0 & mask) + (gamesel << 4)); + setchr1(0x0000, creg[0] + (gamesel << 8)); + setchr1(0x0400, creg[1] + (gamesel << 8)); + setchr1(0x0800, creg[2] + (gamesel << 8)); + setchr1(0x0C00, creg[3] + (gamesel << 8)); + setchr1(0x1000, creg[4] + (gamesel << 8)); + setchr1(0x1400, creg[5] + (gamesel << 8)); + setchr1(0x1800, creg[6] + (gamesel << 8)); + setchr1(0x1C00, creg[7] + (gamesel << 8)); + switch (mirr & 3) { + 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 DECLFW(M528Write1) { + switch (A & 0x0F) { + case 0x0: creg[0] = V; break; + case 0x1: creg[1] = V; break; + case 0x2: creg[2] = V; break; + case 0x3: creg[3] = V; break; + case 0x4: creg[4] = V; break; + case 0x5: creg[5] = V; break; + case 0x6: creg[6] = V; break; + case 0x7: creg[7] = V; break; + case 0x8: preg[3] = V; break; + case 0x9: preg[0] = V; break; + case 0xA: preg[1] = V; break; + case 0xB: break; + case 0xC: mirr = V & 3; break; + case 0xD: VRCIRQ_Control(V); break; + case 0xE: VRCIRQ_Acknowledge(); break; + case 0xF: VRCIRQ_Latch(V); break; + } + gamesel = (A & 0x4000) >> 14; + Sync(); +} + +static void M528Power(void) { + int i; + gamesel = 0; + preg[0] = 0; + preg[1] = 1; + preg[2] = 0; + preg[3] = 0; + for (i = 0; i < 8; i++) { + creg[i] = i; + } + Sync(); + + SetReadHandler(0x8000, 0xFFFF, CartBR); + SetWriteHandler(0xA000, 0xAFFF, M528Write1); + SetWriteHandler(0xC000, 0xCFFF, M528Write1); + + SetReadHandler(0x6000, 0x7FFF, CartBR); + SetWriteHandler(0x6000, 0x7FFF, CartBW); + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); +} + +static void StateRestore(int version) { + Sync(); +} + +void Mapper528_Init(CartInfo *info) { + info->Power = M528Power; + GameStateRestore = StateRestore; + VRCIRQ_Init(); + AddExState(&StateRegs, ~0, 0, 0); + + WRAMSIZE = 8192; + WRAM = (uint8*) FCEU_gmalloc(WRAMSIZE); + SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); + AddExState(WRAM, WRAMSIZE, 0, "WRAM"); +} diff --git a/src/boards/vrcirq.c b/src/boards/vrcirq.c new file mode 100644 index 0000000..d12d3d3 --- /dev/null +++ b/src/boards/vrcirq.c @@ -0,0 +1,93 @@ +#include "mapinc.h" +#include "vrcirq.h" + +static int16 IRQPrescaler; +static uint8 IRQCount; +static uint8 IRQLatch; +static uint8 IRQd; +static uint8 IRQa; +static uint8 IRQm; + +static SFORMAT StateRegs[] = +{ + { &IRQPrescaler, 2, "PREC" }, + { &IRQCount, 1, "IRQC" }, + { &IRQLatch, 1, "IRQL" }, + { &IRQd, 1, "IRQD" }, + { &IRQa, 1, "IRQA" }, + { &IRQm, 1, "IRQM" }, + + { 0 } +}; + +static void FP_FASTAPASS(1) VRCIRQ_IrqHook(int a) +{ + int count = a; + + if (!IRQa) { + return; + } + + while (count) { + count--; + IRQPrescaler -= 3; + if (IRQm || (IRQPrescaler < 0 && !IRQm)) { + IRQPrescaler += 341; + if (IRQCount == 0xFF) { + X6502_IRQBegin(FCEU_IQEXT); + IRQCount = IRQLatch; + } else { + IRQCount++; + } + } + } +} + +void VRCIRQ_Init(void) +{ + IRQPrescaler = 0; + IRQCount = 0; + IRQLatch = 0; + IRQd = 0; + IRQa = 0; + IRQm = 0; + MapIRQHook = VRCIRQ_IrqHook; + + AddExState(&StateRegs, ~0, 0, 0); +} + +void VRCIRQ_Latch(uint8 V) +{ + IRQLatch = V; +} + +void VRCIRQ_LatchNibble(uint8 V, uint8 highBit) +{ + if (highBit) { + IRQLatch &= 0x0F; + IRQLatch |= V << 4; + } else { + IRQLatch &= 0xF0; + IRQLatch |= V & 0xF; + } +} + +void VRCIRQ_Control(uint8 V) +{ + IRQd = (V & 0x01) == 0x01; + IRQa = (V & 0x02) == 0x02; + IRQm = (V & 0x04) == 0x04; + IRQPrescaler = 341; + + if (IRQa) { + IRQCount = IRQLatch; + } + + X6502_IRQEnd(FCEU_IQEXT); +} + +void VRCIRQ_Acknowledge(void) +{ + IRQa = IRQd; + X6502_IRQEnd(FCEU_IQEXT); +} diff --git a/src/boards/vrcirq.h b/src/boards/vrcirq.h new file mode 100644 index 0000000..5a98137 --- /dev/null +++ b/src/boards/vrcirq.h @@ -0,0 +1,10 @@ +#ifndef _VRCIRQ_H +#define _VRCIRQ_H + +void VRCIRQ_Init(void); +void VRCIRQ_Latch(uint8 V); +void VRCIRQ_LatchNibble(uint8 V, uint8 highBit); +void VRCIRQ_Control(uint8 V); +void VRCIRQ_Acknowledge(void); + +#endif /* _VRCIRQ_H */ \ No newline at end of file diff --git a/src/ines.c b/src/ines.c index 2cd9219..345d4c8 100644 --- a/src/ines.c +++ b/src/ines.c @@ -848,6 +848,7 @@ INES_BOARD_BEGIN() INES_BOARD( "KS7021A", 525, UNLKS7021A_Init ) INES_BOARD( "BJ-56", 526, UNLBJ56_Init ) INES_BOARD( "AX-40G", 527, UNLAX40G_Init ) + INES_BOARD( "831128C", 528, Mapper528_Init ) INES_BOARD( "T-230", 529, UNLT230_Init ) INES_BOARD( "AX5705", 530, UNLAX5705_Init ) INES_BOARD( "Sachen 3014", 533, Mapper533_Init ) diff --git a/src/ines.h b/src/ines.h index 7901730..0d4f5f4 100644 --- a/src/ines.h +++ b/src/ines.h @@ -348,6 +348,7 @@ void Mapper501_Init(CartInfo *); void Mapper502_Init(CartInfo *); void Mapper516_Init(CartInfo *); void Mapper523_Init(CartInfo *); +void Mapper528_Init(CartInfo *); void Mapper533_Init(CartInfo *); void Mapper534_Init(CartInfo *); void Mapper538_Init(CartInfo *); diff --git a/src/unif.c b/src/unif.c index d2d964f..a022ec8 100644 --- a/src/unif.c +++ b/src/unif.c @@ -446,6 +446,7 @@ static BMAPPING bmap[] = { { "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 },