summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/bus/nes/mmc1_clones.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/bus/nes/mmc1_clones.cpp')
-rw-r--r--src/devices/bus/nes/mmc1_clones.cpp432
1 files changed, 432 insertions, 0 deletions
diff --git a/src/devices/bus/nes/mmc1_clones.cpp b/src/devices/bus/nes/mmc1_clones.cpp
new file mode 100644
index 00000000000..8c318c4b96c
--- /dev/null
+++ b/src/devices/bus/nes/mmc1_clones.cpp
@@ -0,0 +1,432 @@
+// license:BSD-3-Clause
+// copyright-holders:kmg
+/***********************************************************************************************************
+
+
+ NES/Famicom cartridge emulation for MMC-1 clone PCBs
+
+
+ Here we emulate several pirate PCBs based on MMC-1 boards
+
+ ***********************************************************************************************************/
+
+
+#include "emu.h"
+#include "mmc1_clones.h"
+
+
+#ifdef NES_PCB_DEBUG
+#define VERBOSE (LOG_GENERAL)
+#else
+#define VERBOSE (0)
+#endif
+#include "logmacro.h"
+
+
+//-------------------------------------------------
+// constructor
+//-------------------------------------------------
+
+DEFINE_DEVICE_TYPE(NES_BMC_JY012005, nes_bmc_jy012005_device, "nes_bmc_jy012005", "NES Cart BMC JY012005 PCB")
+DEFINE_DEVICE_TYPE(NES_BMC_JY820845C, nes_bmc_jy820845c_device, "nes_bmc_jy820845c", "NES Cart BMC JY820845C PCB")
+DEFINE_DEVICE_TYPE(NES_FARID_SLROM, nes_farid_slrom_device, "nes_farid_slrom", "NES Cart Farid SLROM 8 in 1 PCB")
+DEFINE_DEVICE_TYPE(NES_NINJARYU, nes_ninjaryu_device, "nes_ninjaryu", "NES Cart Ninja Ryukenden Chinese PCB")
+DEFINE_DEVICE_TYPE(NES_RESETSXROM, nes_resetsxrom_device, "nes_resetsxrom", "NES Cart BMC RESET-SXROM PCB")
+DEFINE_DEVICE_TYPE(NES_SRPG_5IN1, nes_srpg5in1_device, "nes_srpg5in1", "NES Cart Super RPG 5 in 1 PCB")
+DEFINE_DEVICE_TYPE(NES_TXC_22110, nes_txc_22110_device, "nes_txc_22110", "NES Cart TXC 01-22110-000 PCB")
+
+
+nes_bmc_jy012005_device::nes_bmc_jy012005_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
+ : nes_sxrom_device(mconfig, NES_BMC_JY012005, tag, owner, clock), m_latch0(0)
+{
+}
+
+nes_bmc_jy820845c_device::nes_bmc_jy820845c_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
+ : nes_sxrom_device(mconfig, NES_BMC_JY820845C, tag, owner, clock), m_latch0(0), m_mode(0)
+{
+}
+
+nes_farid_slrom_device::nes_farid_slrom_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
+ : nes_sxrom_device(mconfig, NES_FARID_SLROM, tag, owner, clock), m_outer(0)
+{
+}
+
+nes_ninjaryu_device::nes_ninjaryu_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
+ : nes_sxrom_device(mconfig, NES_NINJARYU, tag, owner, clock)
+{
+}
+
+nes_resetsxrom_device::nes_resetsxrom_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
+ : nes_sxrom_device(mconfig, NES_RESETSXROM, tag, owner, clock), m_reset_count(-1)
+{
+}
+
+nes_srpg5in1_device::nes_srpg5in1_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
+ : nes_sxrom_device(mconfig, NES_SRPG_5IN1, tag, owner, clock), m_outer(0), m_outer_count(0), m_outer_latch(0)
+{
+}
+
+nes_txc_22110_device::nes_txc_22110_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
+ : nes_sxrom_device(mconfig, NES_TXC_22110, tag, owner, clock), m_latch0(0), m_mode(0)
+{
+}
+
+
+
+void nes_bmc_jy012005_device::device_start()
+{
+ nes_sxrom_device::device_start();
+ save_item(NAME(m_latch0));
+}
+
+void nes_bmc_jy012005_device::pcb_reset()
+{
+ m_latch0 = 0;
+ nes_sxrom_device::pcb_reset();
+}
+
+void nes_bmc_jy820845c_device::device_start()
+{
+ nes_sxrom_device::device_start();
+ save_item(NAME(m_latch0));
+ save_item(NAME(m_mode));
+}
+
+void nes_bmc_jy820845c_device::pcb_reset()
+{
+ nes_sxrom_device::pcb_reset();
+
+ m_latch0 = 0;
+ m_mode = 0;
+ update_banks();
+}
+
+void nes_farid_slrom_device::device_start()
+{
+ nes_sxrom_device::device_start();
+ save_item(NAME(m_outer));
+}
+
+void nes_farid_slrom_device::pcb_reset()
+{
+ m_outer = 0;
+ nes_sxrom_device::pcb_reset();
+}
+
+void nes_resetsxrom_device::device_start()
+{
+ nes_sxrom_device::device_start();
+ save_item(NAME(m_reset_count));
+}
+
+void nes_resetsxrom_device::pcb_reset()
+{
+ m_reset_count = (m_reset_count + 1) & 3;
+ nes_sxrom_device::pcb_reset();
+}
+
+void nes_srpg5in1_device::device_start()
+{
+ nes_sxrom_device::device_start();
+ save_item(NAME(m_outer));
+ save_item(NAME(m_outer_count));
+ save_item(NAME(m_outer_latch));
+}
+
+void nes_srpg5in1_device::pcb_reset()
+{
+ m_outer = 0;
+ m_outer_count = 0;
+ m_outer_latch = 0;
+ nes_sxrom_device::pcb_reset();
+}
+
+void nes_txc_22110_device::device_start()
+{
+ nes_sxrom_device::device_start();
+ save_item(NAME(m_latch0));
+ save_item(NAME(m_mode));
+}
+
+void nes_txc_22110_device::pcb_reset()
+{
+ nes_sxrom_device::pcb_reset();
+
+ m_latch0 = 0;
+ m_mode = 0;
+ update_banks();
+}
+
+
+
+/*-------------------------------------------------
+ mapper specific handlers
+ -------------------------------------------------*/
+
+/*-------------------------------------------------
+
+ UNL-NINJARYU
+
+ Games: Ninja Ryukenden Chinese
+
+ This board was previously assigned to mapper 111. It has
+ registers akin to MMC1 but without the need to write to
+ them serially. The one existing game has 256K CHR, so this
+ must have at least 1 more bit for CHR banking. Other differences?
+
+ In MAME: Preliminary supported.
+
+ -------------------------------------------------*/
+
+void nes_ninjaryu_device::write_h(offs_t offset, u8 data)
+{
+ LOG("unl_ninjaryu write_h, offset: %04x, data: %02x\n", offset, data);
+ u8 reg = BIT(offset, 13, 2);
+ m_reg[reg] = data;
+ update_regs(reg);
+}
+
+
+/*-------------------------------------------------
+
+ MULTIGAME CARTS BASED ON MMC1
+
+ -------------------------------------------------*/
+
+/*-------------------------------------------------
+
+ BMC-JY012005
+
+ Games: 1998 Super HiK 8 in 1 (JY-021B)
+
+ MMC1 clone with banking for multigame menu.
+
+ NES 2.0: mapper 404
+
+ In MAME: Supported.
+
+ -------------------------------------------------*/
+
+void nes_bmc_jy012005_device::set_prg()
+{
+ u8 mode = !BIT(m_latch0, 6);
+ nes_sxrom_device::set_prg((m_latch0 & 0x07 & ~mode) << 3, mode << 3 | 0x07);
+}
+
+void nes_bmc_jy012005_device::set_chr()
+{
+ nes_sxrom_device::set_chr((m_latch0 & 0x07) << 5, 0x1f);
+}
+
+void nes_bmc_jy012005_device::write_m(offs_t offset, u8 data)
+{
+ LOG("bmc_jy012005 write_m, offset: %04x, data: %02x\n", offset, data);
+
+ if (!BIT(m_latch0, 7)) // outer bank lock
+ {
+ m_latch0 = data;
+ set_prg();
+ set_chr();
+ }
+}
+
+/*-------------------------------------------------
+
+ BMC-JY820845C
+
+ Games: 7 in 1 1993 Chess Series (JY-015)
+
+ MMC1 clone with banking for multigame menu.
+
+ NES 2.0: mapper 550
+
+ In MAME: Supported.
+
+ -------------------------------------------------*/
+
+void nes_bmc_jy820845c_device::update_banks() // used by menu and MHROM games
+{
+ prg32((m_mode & 0x07) << 1 | BIT(m_latch0, 4));
+ chr8((m_mode & 0x06) << 1 | (m_latch0 & 0x03), CHRROM);
+}
+
+void nes_bmc_jy820845c_device::write_m(offs_t offset, u8 data)
+{
+ LOG("bmc_jy820845c write_m, offset: %04x, data: %02x\n", offset, data);
+
+ nes_sxrom_device::write_m(offset, data); // register overlaid on WRAM
+
+ if (offset >= 0x1000 && !BIT(m_mode, 3))
+ {
+ m_mode = offset & 0x0f;
+ if ((m_mode & 0x06) == 0x06) // MMC1 mode
+ {
+ set_prg();
+ set_chr();
+ }
+ else
+ update_banks();
+ }
+}
+
+void nes_bmc_jy820845c_device::write_h(offs_t offset, u8 data)
+{
+ LOG("bmc_jy820845c write_h, offset: %04x, data: %02x\n", offset, data);
+
+ m_latch0 = data;
+
+ if ((m_mode & 0x06) == 0x06)
+ nes_sxrom_device::write_h(offset, data);
+ else
+ update_banks();
+}
+
+/*-------------------------------------------------
+
+ FARID_SLROM_8-IN-1
+
+ Games: 8 in 1
+
+ MMC1 clone with banking for multigame menu.
+
+ NES 2.0: mapper 323
+
+ In MAME: Supported.
+
+ -------------------------------------------------*/
+
+void nes_farid_slrom_device::write_m(offs_t offset, u8 data)
+{
+ LOG("farid_slrom write_m, offset: %04x, data: %02x\n", offset, data);
+ if (!BIT(m_reg[3], 4) && !BIT(m_outer, 3)) // MMC1 WRAM enabled and outer bank not locked
+ m_outer = data;
+}
+
+/*-------------------------------------------------
+
+ BMC-RESET-SXROM
+
+ Games: 4 in 1 (JY-021, JY-022, JY-051)
+
+ MMC1 clone with outer banks switched by resetting.
+
+ NES 2.0: mapper 374
+
+ In MAME: Supported.
+
+ -------------------------------------------------*/
+
+/*-------------------------------------------------
+
+ BMC-SRPG-5IN1 (PCB has no distinguishing label)
+
+ Games: Super RPG 5 in 1 CH501
+
+ MMC1 clone with banking for multigame menu. Note: This
+ game does not soft reset properly on real hardware.
+
+ The interesting feature of this board is that it has a
+ serially written 4-bit shift register that selects the
+ outer game bank (meaning it has two shift registers,
+ since it also clones the MMC1's). The MSB (bit 3) seems
+ to indicate menu mode (0) or game mode (1), but it's not
+ clear if/how this is used. Is it a lock? We currently
+ don't use the MSB nor allow it to be read back.
+
+ NES 2.0: mapper 543
+
+ In MAME: Supported.
+
+ -------------------------------------------------*/
+
+void nes_srpg5in1_device::write_l(offs_t offset, u8 data)
+{
+ LOG("srpg5in1 write_l, offset: %04x, data: %02x\n", offset, data);
+
+ offset += 0x100;
+ if (offset >= 0x1000)
+ {
+ m_outer_latch = (data & 0x08) | m_outer_latch >> 1;
+ m_outer_count = (m_outer_count + 1) & 0x03;
+ if (!m_outer_count)
+ {
+ m_outer = m_outer_latch;
+ set_prg();
+ }
+ }
+}
+
+void nes_srpg5in1_device::write_m(offs_t offset, u8 data)
+{
+ LOG("srpg5in1 write_m, offset: %04x, data: %02x\n", offset, data);
+
+ u8 bank = BIT(m_outer, 1) ? bitswap<3>(m_outer, 1, 2, 0) : (m_outer & 1) << 1 | BIT(m_reg[1], 3);
+
+ if (!BIT(m_reg[3], 4)) // WRAM enabled
+ m_battery[((bank * 0x2000) + offset) & (m_battery.size() - 1)] = data;
+}
+
+u8 nes_srpg5in1_device::read_m(offs_t offset)
+{
+ LOG("srpg5in1 read_m, offset: %04x\n", offset);
+
+ u8 bank = BIT(m_outer, 1) ? bitswap<3>(m_outer, 1, 2, 0) : (m_outer & 1) << 1 | BIT(m_reg[1], 3);
+
+ if (!BIT(m_reg[3], 4)) // WRAM enabled
+ return m_battery[((bank * 0x2000) + offset) & (m_battery.size() - 1)];
+
+ return get_open_bus();
+}
+
+/*-------------------------------------------------
+
+ TXC 01-22110-000 Board
+
+ Games: 2 in 1 Uzi Lightgun (MGC-002)
+
+ This board has an MMC1 clone for Operation Wolf and
+ otherwise is mostly compatible with mapper 70 for
+ Bandai's Space Shadow.
+
+ NES 2.0: mapper 297
+
+ In MAME: Supported.
+
+ -------------------------------------------------*/
+
+void nes_txc_22110_device::update_banks() // used by menu and Space Shadow
+{
+ u8 outer = (m_mode & 0x02) << 1;
+ prg16_89ab(outer | BIT(m_latch0, 4, 2));
+ prg16_cdef(outer | 3);
+ chr8(m_latch0 & 0x0f, CHRROM);
+}
+
+void nes_txc_22110_device::write_l(offs_t offset, u8 data)
+{
+ LOG("TXC 22110 write_l, offset: %04x, data: %02x\n", offset, data);
+ if (offset < 0x100) // $4100 - $41ff
+ {
+ m_mode = data;
+ if (m_mode & 1) // MMC1 mode
+ {
+ set_prg();
+ set_chr();
+ }
+ else
+ update_banks();
+ }
+}
+
+void nes_txc_22110_device::write_h(offs_t offset, u8 data)
+{
+ LOG("TXC 22110 write_h, offset: %04x, data: %02x\n", offset, data);
+
+ if (m_mode & 1)
+ nes_sxrom_device::write_h(offset, data);
+ else
+ {
+ m_latch0 = data;
+ update_banks();
+ }
+}