From b7050cb55d0d77c7b645fb40d91f460c90849e85 Mon Sep 17 00:00:00 2001 From: negativeExponent Date: Fri, 14 Feb 2020 11:39:54 +0800 Subject: [PATCH] Add mappers 111, 356, 269, 353 - backport mapper 111 (Cheapocabra or GTROM) from fceux --- src/boards/269.c | 89 +++++++++++++ src/boards/353.c | 130 +++++++++++++++++++ src/boards/356.c | 103 +++++++++++++++ src/boards/cheapocabra.c | 269 +++++++++++++++++++++++++++++++++++++++ src/ines.c | 5 +- src/ines.h | 4 + 6 files changed, 599 insertions(+), 1 deletion(-) create mode 100644 src/boards/269.c create mode 100644 src/boards/353.c create mode 100644 src/boards/356.c create mode 100644 src/boards/cheapocabra.c diff --git a/src/boards/269.c b/src/boards/269.c new file mode 100644 index 0000000..f638b9c --- /dev/null +++ b/src/boards/269.c @@ -0,0 +1,89 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * 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 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 269 + * Games Xplosion 121-in-1 + * 15000-in-1 + * 18000-in-1 + */ + +#include "mapinc.h" +#include "mmc3.h" + +static uint8 *CHRROM; +static uint32 CHRROMSIZE; + +static void M269CW(uint32 A, uint8 V) { + uint32 NV = V; + if (EXPREGS[2] & 8) + NV &= (1 << ((EXPREGS[2] & 7) + 1)) - 1; + NV |= EXPREGS[0] | ((EXPREGS[2] & 0xF0) << 4); + setchr1(A, NV); +} + +static void M269PW(uint32 A, uint8 V) { + uint32 MV = V & ((EXPREGS[3] & 0x3F) ^ 0x3F); + MV |= EXPREGS[1]; + MV |= ((EXPREGS[3] & 0x40) << 2); + setprg8(A, MV); +} + +static DECLFW(M269Write5) { + if (!(EXPREGS[3] & 0x80)) { + EXPREGS[EXPREGS[4]] = V; + EXPREGS[4] = (EXPREGS[4] + 1) & 3; + FixMMC3PRG(MMC3_cmd); + FixMMC3CHR(MMC3_cmd); + } +} + +static void M269Reset(void) { + EXPREGS[0] = EXPREGS[1] = EXPREGS[3] = EXPREGS[4] = 0; + EXPREGS[2] = 0x0F; + MMC3RegReset(); +} + +static void M269Power(void) { + uint32 i; + EXPREGS[0] = EXPREGS[1] = EXPREGS[3] = EXPREGS[4] = 0; + EXPREGS[2] = 0x0F; + GenMMC3Power(); + SetWriteHandler(0x5000, 0x5FFF, M269Write5); + + CHRROMSIZE = PRGsize[0]; + CHRROM = (uint8*)FCEU_gmalloc(CHRROMSIZE); + /* Decrypt CHR data */ + for (i = 0; i < CHRROMSIZE; i++) { + uint8_t Val = PRGptr[0][i]; + Val = ((Val & 1) << 6) | ((Val & 2) << 3) | ((Val & 4) << 0) | ((Val & 8) >> 3) | ((Val & 16) >> 3) | ((Val & 32) >> 2) | ((Val & 64) >> 1) | ((Val & 128) << 0); + CHRROM[i] = Val; + } + SetupCartCHRMapping(0, CHRROM, CHRROMSIZE, 0); + AddExState(CHRROM, CHRROMSIZE, 0, "_CHR"); +} + +void Mapper269_Init(CartInfo *info) { + GenMMC3_Init(info, 512, 0, 8, 0); + cwrap = M269CW; + pwrap = M269PW; + info->Power = M269Power; + info->Reset = M269Reset; + AddExState(EXPREGS, 5, 0, "EXPR"); +} diff --git a/src/boards/353.c b/src/boards/353.c new file mode 100644 index 0000000..94e644f --- /dev/null +++ b/src/boards/353.c @@ -0,0 +1,130 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * 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 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 353 is used for the 92 Super Mario Family multicart, + * consisting of an MMC3 clone ASIC together with a PAL. + * The PCB code is 81-03-05-C. + */ + +#include "mapinc.h" +#include "mmc3.h" + +static uint8* CHRRAM = NULL; +static uint32 CHRRAMSIZE; +static uint8 PPUCHRBus; +static uint8 MIR[8]; + +static void M353PPU(uint32 A) { + A &= 0x1FFF; + A >>= 10; + PPUCHRBus = A; + if (EXPREGS[0] == 0) + setmirror(MI_0 + MIR[A]); +} + +static void M353PW(uint32 A, uint8 V) { + uint32 bank = V; + + if (EXPREGS[0] == 2) { + bank &= 0x0F; + bank |= (DRegBuf[0] & 0x80) ? 0x10 : 0x00; + bank |= (EXPREGS[0] << 5); + } else { + if ((EXPREGS[0] == 3) && !(DRegBuf[0] & 0x80)) { + switch (A & 0xF000) { + case 0xC000: + case 0xE000: + bank = DRegBuf[6 + ((A >> 13) & 1)] | 0x70; + break; + } + } else { + bank &= 0x1F; + bank |= (EXPREGS[0] << 5); + } + } + + setprg8(A, bank); +} + +static void M353CW(uint32 A, uint8 V) { + if ((EXPREGS[0] == 2) && (DRegBuf[0] & 0x80)) + setchr8r(0x10, 0); + else + setchr1(A, (V & 0x7F) | ((EXPREGS[0]) << 7)); + + MIR[A >> 10] = V >> 7; + if ((EXPREGS[0] == 0) && (PPUCHRBus == (A >> 10))) + setmirror(MI_0 + (V >> 7)); +} + +static void M353MW(uint8 V) { + if (EXPREGS[0] != 0) { + A000B = V; + setmirror((V & 1) ^ 1); + } +} + +static DECLFW(M353Write) { + if (A & 0x80) { + EXPREGS[0] = (A >> 13) & 0x03; + FixMMC3PRG(MMC3_cmd); + FixMMC3CHR(MMC3_cmd); + } else { + if (A < 0xC000) { + MMC3_CMDWrite(A, V); + FixMMC3PRG(MMC3_cmd); + } else + MMC3_IRQWrite(A, V); + } +} + +static void M353Power(void) { + EXPREGS[0] = 0; + GenMMC3Power(); + SetWriteHandler(0x8000, 0xFFFF, M353Write); +} + +static void M353Reset(void) { + EXPREGS[0] = 0; + MMC3RegReset(); +} + +static void M353Close(void) { + if (CHRRAM) + FCEU_gfree(CHRRAM); + CHRRAM = NULL; +} + +void Mapper353_Init(CartInfo* info) { + GenMMC3_Init(info, 256, 128, 8, info->battery); + cwrap = M353CW; + pwrap = M353PW; + mwrap = M353MW; + PPU_hook = M353PPU; + info->Power = M353Power; + info->Close = M353Close; + info->Reset = M353Reset; + AddExState(EXPREGS, 1, 0, "EXPR"); + + CHRRAMSIZE = 8192; + CHRRAM = (uint8*)FCEU_gmalloc(CHRRAMSIZE); + SetupCartCHRMapping(0x10, CHRRAM, CHRRAMSIZE, 1); + AddExState(CHRRAM, CHRRAMSIZE, 0, "CHRR"); +} diff --git a/src/boards/356.c b/src/boards/356.c new file mode 100644 index 0000000..c5dc93f --- /dev/null +++ b/src/boards/356.c @@ -0,0 +1,103 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * 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 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 356 - J.Y. Company's 7-in-1 Rockman (JY-208) + * All registers work as INES Mapper 045, except $6000 sequential register 2 (third write): + */ + +#include "mapinc.h" +#include "mmc3.h" + +static uint8* CHRRAM = NULL; +static uint32 CHRRAMSIZE = 0; + +static void M356CW(uint32 A, uint8 V) { + if (EXPREGS[2] & 0x20) { + uint32 NV = V; + if (EXPREGS[2] & 8) + NV &= (1 << ((EXPREGS[2] & 7) + 1)) - 1; + else + if (EXPREGS[2]) + NV &= 0; /* hack ;( don't know exactly how it should be */ + NV |= EXPREGS[0] | ((EXPREGS[2] & 0xF0) << 4); + setchr1(A, NV); + } else + setchr8r(0x10, 0); +} + +static void M356PW(uint32 A, uint8 V) { + uint32 MV = V & ((EXPREGS[3] & 0x3F) ^ 0x3F); + MV |= EXPREGS[1]; + if (UNIFchrrama) + MV |= ((EXPREGS[2] & 0x40) << 2); + setprg8(A, MV); +} + +static void M356MW(uint8 V) { + if (EXPREGS[2] & 0x40) + SetupCartMirroring(4, 1, CHRRAM); + else + setmirror((V & 1) ^ 1); +} + +static DECLFW(M356Write) { + if (!(EXPREGS[3] & 0x40)) { + EXPREGS[EXPREGS[4]] = V; + EXPREGS[4] = (EXPREGS[4] + 1) & 3; + FixMMC3PRG(MMC3_cmd); + FixMMC3CHR(MMC3_cmd); + } +} + +static void M356Close(void) { + if (CHRRAM) + FCEU_free(CHRRAM); + CHRRAM = NULL; +} + +static void M356Reset(void) { + EXPREGS[0] = EXPREGS[1] = EXPREGS[3] = EXPREGS[4] = 0; + EXPREGS[2] = 0x0F; + MMC3RegReset(); +} + +static void M356Power(void) { + EXPREGS[4] = 0; + EXPREGS[0] = EXPREGS[1] = EXPREGS[3] = EXPREGS[4] = 0; + EXPREGS[2] = 0x0F; + GenMMC3Power(); + SetWriteHandler(0x6000, 0x7FFF, M356Write); +} + +void Mapper356_Init(CartInfo* info) { + GenMMC3_Init(info, 128, 128, 0, 0); + cwrap = M356CW; + pwrap = M356PW; + mwrap = M356MW; + info->Reset = M356Reset; + info->Power = M356Power; + info->Close = M356Close; + AddExState(EXPREGS, 5, 0, "EXPR"); + + CHRRAMSIZE = 8192; + CHRRAM = (uint8*)FCEU_gmalloc(CHRRAMSIZE); + SetupCartCHRMapping(0x10, CHRRAM, CHRRAMSIZE, 1); + AddExState(CHRRAM, CHRRAMSIZE, 0, "CHRR"); +} diff --git a/src/boards/cheapocabra.c b/src/boards/cheapocabra.c new file mode 100644 index 0000000..7730941 --- /dev/null +++ b/src/boards/cheapocabra.c @@ -0,0 +1,269 @@ +/* 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 + */ + +/* mapper 111 - Cheapocabra board by Memblers + * http://forums.nesdev.com/viewtopic.php?p=146039 + * + * 512k PRG-ROM in 32k pages (flashable if battery backed is specified) + * 32k CHR-RAM used as: + * 2 x 8k pattern pages + * 2 x 8k nametable pages + * + * Notes: + * - CHR-RAM for nametables maps to $3000-3FFF as well, but FCEUX internally mirrors to 4k? + */ + +#include "mapinc.h" +#include "../ines.h" + +static uint8 reg; +static uint8 *CHRRAM = NULL; +static uint32 CHRRAMSIZE; + +static uint8 flash = 0; +static uint8 flash_mode; +static uint8 flash_sequence; +static uint8 flash_id; +static uint8 *FLASHROM = NULL; +static uint32 FLASHROMSIZE; + +static SFORMAT StateRegs[] = { + { ®, 1, "REG" }, + { 0 } +}; + +static SFORMAT FlashRegs[] = { + { &flash_mode, 1, "FMOD" }, + { &flash_sequence, 1, "FSEQ" }, + { &flash_id, 1, "FMID" }, + { 0 } +}; + +static void Sync(void) { + /* bit 7 controls green LED */ + /* bit 6 controls red LED */ + uint32 prg_chip = flash ? 0x10 : 0; + int nt = (reg & 0x20) ? 8192 : 0; /* bit 5 controls 8k nametable page */ + int chr = (reg & 0x10) ? 1 : 0; /* bit 4 selects 8k CHR page */ + int prg = (reg & 0x0F); /* bits 0-3 select 32k PRG page */ + int n = 0; + + nt += (16 * 1024); + for (n = 0; n < 4; ++n) { + setntamem(CHRRAM + nt + (1024 * n), 1, n); + } + setchr8r(0x10, chr); + setprg32r(prg_chip, 0x8000, prg); +} + +static DECLFW(M111Write) { + if ((A >= 0x5000 && A <= 0x5FFF) || (A >= 0x7000 && A <= 0x7FFF)) { + reg = V; + Sync(); + } +} + +static DECLFR(M111FlashID) { + /* Software ID mode is undefined by the datasheet for all but the lowest 2 addressable bytes, + * but some tests of the chip currently being used found it repeats in 512-byte patterns. + * http://forums.nesdev.com/viewtopic.php?p=178728#p178728 + */ + + uint32 aid = A & 0x1FF; + switch (aid) { + case 0: + return 0xBF; + case 1: + return 0xB7; + default: + return 0xFF; + } +} + +void M111FlashIDEnter() { + if (flash_id) + return; + flash_id = 1; + SetReadHandler(0x8000, 0xFFFF, M111FlashID); +} + +void M111FlashIDExit() { + if (!flash_id) + return; + flash_id = 0; + SetReadHandler(0x8000, 0xFFFF, CartBR); +} + +enum { + FLASH_MODE_READY = 0, + FLASH_MODE_COMMAND, + FLASH_MODE_BYTE_WRITE, + FLASH_MODE_ERASE, +}; + +static DECLFW(M111Flash) { + uint32 flash_addr = 0; + uint32 command_addr = 0; + + if (A < 0x8000 || A > 0xFFFF) + return; + + flash_addr = ((reg & 0x0F) << 15) | (A & 0x7FFF); + command_addr = flash_addr & 0x7FFF; + + switch (flash_mode) { + default: + case FLASH_MODE_READY: + if (command_addr == 0x5555 && V == 0xAA) { + flash_mode = FLASH_MODE_COMMAND; + flash_sequence = 0; + } else if (V == 0xF0) { + M111FlashIDExit(); + } + break; + case FLASH_MODE_COMMAND: + if (flash_sequence == 0) { + if (command_addr == 0x2AAA && V == 0x55) + flash_sequence = 1; + else + flash_mode = FLASH_MODE_READY; + } else if (flash_sequence == 1) { + if (command_addr == 0x5555) { + flash_sequence = 0; + switch (V) { + default: + flash_mode = FLASH_MODE_READY; + break; + case 0xA0: + flash_mode = FLASH_MODE_BYTE_WRITE; + break; + case 0x80: + flash_mode = FLASH_MODE_ERASE; + break; + case 0x90: + M111FlashIDEnter(); + flash_mode = FLASH_MODE_READY; + break; + case 0xF0: + M111FlashIDExit(); + flash_mode = FLASH_MODE_READY; + break; + } + } else + flash_mode = FLASH_MODE_READY; + } else + flash_mode = FLASH_MODE_READY; /* should be unreachable */ + break; + case FLASH_MODE_BYTE_WRITE: + FLASHROM[flash_addr] &= V; + flash_mode = FLASH_MODE_READY; + break; + case FLASH_MODE_ERASE: + if (flash_sequence == 0) { + if (command_addr == 0x5555 && V == 0xAA) + flash_sequence = 1; + else + flash_mode = FLASH_MODE_READY; + } else if (flash_sequence == 1) { + if (command_addr == 0x2AAA && V == 0x55) + flash_sequence = 2; + else + flash_mode = FLASH_MODE_READY; + } else if (flash_sequence == 2) { + if (command_addr == 0x5555 && V == 0x10) /* erase chip */ + { + memset(FLASHROM, 0xFF, FLASHROMSIZE); + } else if (V == 0x30) /* erase 4k sector */ + { + uint32 sector = flash_addr & 0x7F000; + memset(FLASHROM + sector, 0xFF, 1024 * 4); + } + flash_mode = FLASH_MODE_READY; + } else + flash_mode = FLASH_MODE_READY; /* should be unreachable */ + break; + } +} + +static void M111Power(void) { + reg = 0xFF; + Sync(); + SetReadHandler(0x8000, 0xffff, CartBR); + SetWriteHandler(0x5000, 0x5fff, M111Write); + SetWriteHandler(0x7000, 0x7fff, M111Write); + + if (flash) { + flash_mode = 0; + flash_sequence = 0; + flash_id = 0; + SetWriteHandler(0x8000, 0xFFFF, M111Flash); + } +} + +static void M111Close(void) { + if (CHRRAM) + FCEU_gfree(CHRRAM); + CHRRAM = NULL; + + if (FLASHROM) + FCEU_gfree(FLASHROM); + FLASHROM = NULL; +} + +static void StateRestore(int version) { + Sync(); +} + +void Mapper111_Init(CartInfo* info) { + info->Power = M111Power; + info->Close = M111Close; + + CHRRAMSIZE = 1024 * 32; + CHRRAM = (uint8*)FCEU_gmalloc(CHRRAMSIZE); + SetupCartCHRMapping(0x10, CHRRAM, CHRRAMSIZE, 1); + + GameStateRestore = StateRestore; + AddExState(&StateRegs, ~0, 0, 0); + AddExState(CHRRAM, CHRRAMSIZE, 0, "CRAM"); + + flash = (info->battery != 0); + if (flash) { + uint32 PRGSIZE = 0; + uint32 w = 0; + uint32 r = 0; + + FLASHROMSIZE = 1024 * 512; + FLASHROM = (uint8*)FCEU_gmalloc(FLASHROMSIZE); + info->SaveGame[0] = FLASHROM; + info->SaveGameLen[0] = FLASHROMSIZE; + AddExState(FLASHROM, FLASHROMSIZE, 0, "FROM"); + AddExState(&FlashRegs, ~0, 0, 0); + + /* copy PRG ROM into FLASHROM, use it instead of PRG ROM */ + PRGSIZE = ROM_size * 16 * 1024; + for (w = 0, r = 0; w < FLASHROMSIZE; ++w) { + FLASHROM[w] = ROM[r]; + ++r; + if (r >= PRGSIZE) + r = 0; + } + SetupCartPRGMapping(0x10, FLASHROM, FLASHROMSIZE, 0); + } +} diff --git a/src/ines.c b/src/ines.c index cfb9258..7b24030 100644 --- a/src/ines.c +++ b/src/ines.c @@ -505,7 +505,7 @@ static BMAPPINGLocal bmap[] = { {(uint8_t*)"FDS UNROM BOARD", 108, Mapper108_Init}, /* {(uint8_t*)"", 109, Mapper109_Init}, */ /* {(uint8_t*)"", 110, Mapper110_Init}, */ -/* {(uint8_t*)"", 111, Mapper111_Init}, */ + {(uint8_t*)"Cheapocabra", 111, Mapper111_Init}, {(uint8_t*)"ASDER/NTDEC BOARD", 112, Mapper112_Init}, {(uint8_t*)"HACKER/SACHEN BOARD", 113, Mapper113_Init}, {(uint8_t*)"MMC3 SG PROT. A", 114, Mapper114_Init}, @@ -681,6 +681,9 @@ static BMAPPINGLocal bmap[] = { {(uint8_t*)"Brilliant Com Cocoma Pack", 516, Mapper516_Init}, {(uint8_t*)"SB-5013/GCL8050/841242C", 359, Mapper359_Init}, {(uint8_t*)"82112C", 540, Mapper540_Init}, + {(uint8_t*)"7-in-1 Rockman (JY-208)", 356, Mapper356_Init}, + {(uint8_t*)"Games Xplosion 121-in-1", 269, Mapper269_Init}, + {(uint8_t*)"Super Mario Family", 353, Mapper353_Init}, /* UNIF to NES 2.0 BOARDS */ diff --git a/src/ines.h b/src/ines.h index f818021..d54c8b1 100644 --- a/src/ines.h +++ b/src/ines.h @@ -136,6 +136,7 @@ void Mapper105_Init(CartInfo *); void Mapper106_Init(CartInfo *); void Mapper107_Init(CartInfo *); void Mapper108_Init(CartInfo *); +void Mapper111_Init(CartInfo *); void Mapper112_Init(CartInfo *); void Mapper113_Init(CartInfo *); void Mapper114_Init(CartInfo *); @@ -244,8 +245,11 @@ void NC7000M_Init(CartInfo *); void J2282_Init(CartInfo *); void Mapper267_Init(CartInfo *); +void Mapper269_Init(CartInfo *); void Mapper288_Init(CartInfo *); void Mapper297_Init(CartInfo *); +void Mapper353_Init(CartInfo *); +void Mapper356_Init(CartInfo *); void Mapper357_Init(CartInfo *); void Mapper359_Init(CartInfo *); void Mapper360_Init(CartInfo *);