diff --git a/src/boards/272.c b/src/boards/272.c new file mode 100644 index 0000000..923f544 --- /dev/null +++ b/src/boards/272.c @@ -0,0 +1,179 @@ +/* FCE Ultra - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2022 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 + * 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 272 is used for a bootleg implementation of + * 悪魔城 Special: ぼくDracula君 (Akumajō Special: Boku Dracula-kun). + * + * as implemented from + * https://forums.nesdev.org/viewtopic.php?f=9&t=15302&start=60#p205862 + * + */ + +#include "mapinc.h" + +static uint8 prg[2]; +static uint8 chr[8]; +static uint8 mirr; +static uint8 pal_mirr; +static uint8 last_pa13; +static uint8 IRQCount; +static uint8 IRQa; + +static SFORMAT StateRegs[] = +{ + { prg, 2, "PRG" }, + { chr, 8, "CHR" }, + { &mirr, 1, "MIRR" }, + { &last_pa13, 1, "PA13" }, + { &IRQCount, 1, "CNTR" }, + { &pal_mirr, 1, "PALM" }, + { &IRQa, 1, "CCLK" }, + { 0 } +}; + +/* shifts bit from position `bit` into position `pos` of expression `exp` */ +#define shi(exp, bit, pos) \ + ((((exp) & (1 << (bit))) >> (bit)) << (pos)) + +static uint32 vrc_addr_mix(uint32 A) { + /* this game wires A0 to VRC_A0 and A1 to VRC_A1 */ + return (A & 0xf000) | shi(A, 0, 0) | shi(A, 1, 1); +} + +static void Sync(void) { + uint8 i; + setprg8(0x8000, prg[0]); + setprg8(0xa000, prg[1]); + setprg16(0xc000, -1); + for (i = 0; i < 8; ++i) + setchr1(0x400 * i, chr[i]); + switch (pal_mirr) { + case 2: setmirror(MI_0); break; + case 3: setmirror(MI_1); break; + default: + switch (mirr) { + case 0: setmirror(MI_V); break; + case 1: setmirror(MI_H); break; + } + } +} + +static DECLFW(M272Write) { + /* writes to VRC chip */ + switch (vrc_addr_mix(A)) { + case 0x8000: + case 0x8001: + case 0x8002: + case 0x8003: + prg[0] = V; + break; + case 0x9000: + case 0x9001: + case 0x9002: + case 0x9003: + mirr = V & 1; + break; + case 0xA000: + case 0xA001: + case 0xA002: + case 0xA003: + prg[1] = V; + break; + case 0xb000: chr[0] = (chr[0] & 0xF0) | (V & 0xF); break; + case 0xb001: chr[0] = (chr[0] & 0xF) | ((V & 0xF) << 4); break; + case 0xb002: chr[1] = (chr[1] & 0xF0) | (V & 0xF); break; + case 0xb003: chr[1] = (chr[1] & 0xF) | ((V & 0xF) << 4); break; + case 0xc000: chr[2] = (chr[2] & 0xF0) | (V & 0xF); break; + case 0xc001: chr[2] = (chr[2] & 0xF) | ((V & 0xF) << 4); break; + case 0xc002: chr[3] = (chr[3] & 0xF0) | (V & 0xF); break; + case 0xc003: chr[3] = (chr[3] & 0xF) | ((V & 0xF) << 4); break; + case 0xd000: chr[4] = (chr[4] & 0xF0) | (V & 0xF); break; + case 0xd001: chr[4] = (chr[4] & 0xF) | ((V & 0xF) << 4); break; + case 0xd002: chr[5] = (chr[5] & 0xF0) | (V & 0xF); break; + case 0xd003: chr[5] = (chr[5] & 0xF) | ((V & 0xF) << 4); break; + case 0xe000: chr[6] = (chr[6] & 0xF0) | (V & 0xF); break; + case 0xe001: chr[6] = (chr[6] & 0xF) | ((V & 0xF) << 4); break; + case 0xe002: chr[7] = (chr[7] & 0xF0) | (V & 0xF); break; + case 0xe003: chr[7] = (chr[7] & 0xF) | ((V & 0xF) << 4); break; + + default: + break; + } + + /* writes to PAL chip */ + switch (A & 0xC00C) { + case 0x8004: pal_mirr = V & 3; break; + case 0x800c: X6502_IRQBegin(FCEU_IQEXT); break; + case 0xc004: X6502_IRQEnd(FCEU_IQEXT); break; + case 0xc008: IRQa = 1; break; + case 0xc00c: IRQa = 0; IRQCount = 0; X6502_IRQEnd(FCEU_IQEXT); break; + } + + Sync(); +} + +static void M272Power(void) { + prg[0] = prg[1] = 0; + chr[0] = chr[1] = chr[2] = chr[3] = 0; + chr[4] = chr[5] = chr[6] = chr[7] = 0; + mirr = pal_mirr = 0; + last_pa13 = 0; + IRQCount = 0; + IRQa = 0; + Sync(); + SetWriteHandler(0x8000, 0xFFFF, M272Write); + SetReadHandler(0x8000, 0xFFFF, CartBR); +} + +static void M272Hook(uint32 A) { + uint8 pa13 = (A >> 13) & 1; + if ((last_pa13 == 1) && (pa13 == 0)) { + if (IRQa) { + IRQCount++; + if (IRQCount == 84) { + IRQCount = 0; + X6502_IRQBegin(FCEU_IQEXT); + } + } + } + last_pa13 = pa13; +} + +static void M272Reset(void) { + prg[0] = prg[1] = 0; + chr[0] = chr[1] = chr[2] = chr[3] = 0; + chr[4] = chr[5] = chr[6] = chr[7] = 0; + mirr = pal_mirr = 0; + last_pa13 = 0; + IRQCount = 0; + IRQa = 0; + Sync(); +} + +static void StateRestore(int version) { + Sync(); +} + +void Mapper272_Init(CartInfo *info) { + info->Power = M272Power; + info->Reset = M272Reset; + PPU_hook = M272Hook; + GameStateRestore = StateRestore; + AddExState(&StateRegs, ~0, 0, 0); +} diff --git a/src/boards/291.c b/src/boards/291.c new file mode 100644 index 0000000..da6f7ab --- /dev/null +++ b/src/boards/291.c @@ -0,0 +1,59 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2022 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 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" + +static void M291CW(uint32 A, uint8 V) { + setchr1(A, V | ((EXPREGS[0] << 2) & 0x100)); +} + +static void M291PW(uint32 A, uint8 V) { + if (EXPREGS[0] & 0x20) + setprg32(0x8000, ((EXPREGS[0] >> 1) & 3) | ((EXPREGS[0] >> 4) & 4)); + else + setprg8(A, (V & 0x0F) | ((EXPREGS[0] >> 2) & 0x10)); +} + +static DECLFW(M291Write) { + EXPREGS[0] = V; + FixMMC3PRG(MMC3_cmd); + FixMMC3CHR(MMC3_cmd); +} + +static void M291Reset(void) { + EXPREGS[0] = 0; + MMC3RegReset(); +} + +static void M291Power(void) { + EXPREGS[0] = 0; + GenMMC3Power(); + SetWriteHandler(0x6000, 0x7FFF, M291Write); +} + +void Mapper291_Init(CartInfo *info) { + GenMMC3_Init(info, 256, 512, 0, 0); + cwrap = M291CW; + pwrap = M291PW; + info->Power = M291Power; + info->Reset = M291Reset; + AddExState(EXPREGS, 1, 0, "EXPR"); +} diff --git a/src/boards/414.c b/src/boards/414.c new file mode 100644 index 0000000..79ff817 --- /dev/null +++ b/src/boards/414.c @@ -0,0 +1,64 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2022 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 + * 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" + +static uint8 latch_data; +static uint32 latch_addr; + +static SFORMAT StateRegs[] = +{ + { &latch_addr, 4, "ADDR" }, + { &latch_data, 1, "DATA" }, + { 0 } +}; + +static void Sync(void) { + if (latch_addr & 0x2000) { /* NROM-256 */ + setprg32(0x8000, latch_addr >> 2); + } else { /* NROM-128 */ + setprg16(0x8000, latch_addr >> 1); + setprg16(0xC000, latch_addr >> 1); + } + setchr8(latch_data); + setmirror((latch_data & 1) ^ 1); +} + +static DECLFW(M414Write) { + latch_addr = A; + latch_data = V & CartBR(A); + Sync(); +} + +static void M414Power(void) { + Sync(); + SetReadHandler(0x8000, 0xFFFF, CartBR); + SetWriteHandler(0x8000, 0xFFFF, M414Write); +} + +static void StateRestore(int version) { + Sync(); +} + +void Mapper414_Init(CartInfo *info) { + info->Power = M414Power; + GameStateRestore = StateRestore; + AddExState(&StateRegs, ~0, 0, 0); +} diff --git a/src/boards/431.c b/src/boards/431.c new file mode 100644 index 0000000..11a987f --- /dev/null +++ b/src/boards/431.c @@ -0,0 +1,62 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2022 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 + * 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" + +static uint8 inner_bank; +static uint8 outer_bank; + +static SFORMAT StateRegs[] = +{ + { &outer_bank, 1, "OUTB" }, + { &inner_bank, 1, "INNB" }, + { 0 } +}; + +static void Sync(void) { + setprg16(0x8000, ((outer_bank >> 2) & ~7) | (inner_bank & 7)); + setprg16(0xC000, ((outer_bank >> 2) & ~7) | 7); + setchr8(0); + setmirror((outer_bank & 1) ^ 1); +} + +static DECLFW(M431Write) { + if (A < 0xC000) outer_bank = V; + else inner_bank = V; + Sync(); +} + +static void M431Power(void) { + inner_bank = 0; + outer_bank = 0; + Sync(); + SetReadHandler(0x8000, 0xFFFF, CartBR); + SetWriteHandler(0x8000, 0xFFFF, M431Write); +} + +static void StateRestore(int version) { + Sync(); +} + +void Mapper431_Init(CartInfo *info) { + info->Power = M431Power; + GameStateRestore = StateRestore; + AddExState(&StateRegs, ~0, 0, 0); +} diff --git a/src/boards/addrlatch.c b/src/boards/addrlatch.c index 9273341..43946bf 100644 --- a/src/boards/addrlatch.c +++ b/src/boards/addrlatch.c @@ -704,3 +704,14 @@ void J2282_Init(CartInfo *info) { Latch_Init(info, J2282Sync, NULL, 0x0000, 0x8000, 0xFFFF, 0); } + +/* -------------- Mapper 409 ------------------------ */ +static void M409Sync(void) { + setprg16(0x8000, latche); + setprg16(0xC000, ~0); + setchr8(0); +} + +void Mapper409_Init(CartInfo *info) { + Latch_Init(info, M409Sync, NULL, 0x0000, 0xC000, 0xCFFF, 0); +} diff --git a/src/ines.c b/src/ines.c index c417a7a..575ac88 100644 --- a/src/ines.c +++ b/src/ines.c @@ -691,6 +691,7 @@ INES_BOARD_BEGIN() INES_BOARD( "8-in-1 JY-119", 267, Mapper267_Init ) INES_BOARD( "COOLBOY/MINDKIDS", 268, Mapper268_Init ) /* Submapper distinguishes between COOLBOY and MINDKIDS */ INES_BOARD( "Games Xplosion 121-in-1", 269, Mapper269_Init ) + INES_BOARD( "Akumajō Special: Boku Dracula-kun", 272, Mapper272_Init ) INES_BOARD( "80013-B", 274, BMC80013B_Init ) INES_BOARD( "YY860417C", 281, Mapper281_Init ) INES_BOARD( "860224C", 282, Mapper282_Init ) @@ -701,6 +702,7 @@ INES_BOARD_BEGIN() INES_BOARD( "GKCX1", 288, Mapper288_Init ) INES_BOARD( "60311C", 289, BMC60311C_Init ) INES_BOARD( "NTD-03", 290, BMCNTD03_Init ) + INES_BOARD( "Kasheng 2-in-1 ", 291, Mapper291_Init ) INES_BOARD( "DRAGONFIGHTER", 292, UNLBMW8544_Init ) INES_BOARD( "NewStar 12-in-1/7-in-1", 293, Mapper293_Init ) INES_BOARD( "MMC3 BMC PIRATE", 294, Bs5652_Init ) /* nesdev redirects this as mapper 134 */ @@ -784,8 +786,10 @@ INES_BOARD_BEGIN() INES_BOARD( "831019C J-2282", 402, J2282_Init ) INES_BOARD( "89433", 403, Mapper403_Init ) INES_BOARD( "JY012005", 404, Mapper404_Init ) + INES_BOARD( "retroUSB DPCMcart", 409, Mapper409_Init ) INES_BOARD( "JY-302", 410, Mapper410_Init ) INES_BOARD( "A88S-1", 411, Mapper411_Init ) + INES_BOARD( "9999999-in-1", 414, Mapper414_Init ) INES_BOARD( "0353", 415, Mapper415_Init ) INES_BOARD( "4-in-1/N-32", 416, Mapper416_Init ) INES_BOARD( "", 417, Mapper417_Init ) @@ -793,6 +797,7 @@ INES_BOARD_BEGIN() INES_BOARD( "BS-400R/BS-4040", 422, Mapper422_Init ) INES_BOARD( "AB-G1L/WELL-NO-DG450", 428, Mapper428_Init ) INES_BOARD( "LIKO BBG-235-8-1B", 429, Mapper429_Init ) + INES_BOARD( "Realtek GN-91B", 431, Mapper431_Init ) INES_BOARD( "Realtec 8090", 432, Mapper432_Init ) INES_BOARD( "NC-20MB", 433, Mapper433_Init ) INES_BOARD( "S-009", 434, Mapper434_Init ) diff --git a/src/ines.h b/src/ines.h index 90f3fa6..0671d68 100644 --- a/src/ines.h +++ b/src/ines.h @@ -247,9 +247,11 @@ void Mapper254_Init(CartInfo *); void Mapper255_Init(CartInfo *); void GN45_Init(CartInfo *info); /* m361, m366 */ +void Mapper272_Init(CartInfo *); void Mapper281_Init(CartInfo *); void Mapper282_Init(CartInfo *); void Mapper283_Init(CartInfo *); +void Mapper291_Init(CartInfo *); void Mapper295_Init(CartInfo *); void Bs5652_Init(CartInfo *); @@ -294,8 +296,10 @@ void Mapper397_Init(CartInfo *); void Mapper401_Init(CartInfo *); void Mapper403_Init(CartInfo *); void Mapper404_Init(CartInfo *); +void Mapper409_Init(CartInfo *); void Mapper410_Init(CartInfo *); void Mapper411_Init(CartInfo *); +void Mapper414_Init(CartInfo *); void Mapper415_Init(CartInfo *); void Mapper416_Init(CartInfo *); void Mapper417_Init(CartInfo *); @@ -303,6 +307,7 @@ void Mapper421_Init(CartInfo *); void Mapper422_Init(CartInfo *); void Mapper428_Init(CartInfo *); void Mapper429_Init(CartInfo *); +void Mapper431_Init(CartInfo *); void Mapper432_Init(CartInfo *); void Mapper433_Init(CartInfo *); void Mapper434_Init(CartInfo *);