From 7c19aac60e12d6f5ea301bdb34d7826a01e0b06f Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Sun, 8 Nov 2015 12:56:12 +0100 Subject: Rename *.c -> *.cpp in our source (nw) --- src/devices/bus/nes/2a03pur.c | 109 -- src/devices/bus/nes/2a03pur.cpp | 109 ++ src/devices/bus/nes/act53.c | 206 --- src/devices/bus/nes/act53.cpp | 206 +++ src/devices/bus/nes/aladdin.c | 339 ----- src/devices/bus/nes/aladdin.cpp | 339 +++++ src/devices/bus/nes/ave.c | 214 --- src/devices/bus/nes/ave.cpp | 214 +++ src/devices/bus/nes/bandai.c | 479 ------- src/devices/bus/nes/bandai.cpp | 479 +++++++ src/devices/bus/nes/benshieng.c | 105 -- src/devices/bus/nes/benshieng.cpp | 105 ++ src/devices/bus/nes/bootleg.c | 1635 --------------------- src/devices/bus/nes/bootleg.cpp | 1635 +++++++++++++++++++++ src/devices/bus/nes/camerica.c | 225 --- src/devices/bus/nes/camerica.cpp | 225 +++ src/devices/bus/nes/cne.c | 220 --- src/devices/bus/nes/cne.cpp | 220 +++ src/devices/bus/nes/cony.c | 397 ------ src/devices/bus/nes/cony.cpp | 397 ++++++ src/devices/bus/nes/datach.c | 420 ------ src/devices/bus/nes/datach.cpp | 420 ++++++ src/devices/bus/nes/discrete.c | 209 --- src/devices/bus/nes/discrete.cpp | 209 +++ src/devices/bus/nes/disksys.c | 431 ------ src/devices/bus/nes/disksys.cpp | 431 ++++++ src/devices/bus/nes/event.c | 239 ---- src/devices/bus/nes/event.cpp | 239 ++++ src/devices/bus/nes/ggenie.c | 274 ---- src/devices/bus/nes/ggenie.cpp | 274 ++++ src/devices/bus/nes/henggedianzi.c | 278 ---- src/devices/bus/nes/henggedianzi.cpp | 278 ++++ src/devices/bus/nes/hes.c | 87 -- src/devices/bus/nes/hes.cpp | 87 ++ src/devices/bus/nes/hosenkan.c | 155 -- src/devices/bus/nes/hosenkan.cpp | 155 ++ src/devices/bus/nes/irem.c | 352 ----- src/devices/bus/nes/irem.cpp | 352 +++++ src/devices/bus/nes/jaleco.c | 886 ------------ src/devices/bus/nes/jaleco.cpp | 886 ++++++++++++ src/devices/bus/nes/jy.c | 589 -------- src/devices/bus/nes/jy.cpp | 589 ++++++++ src/devices/bus/nes/kaiser.c | 588 -------- src/devices/bus/nes/kaiser.cpp | 588 ++++++++ src/devices/bus/nes/karastudio.c | 309 ---- src/devices/bus/nes/karastudio.cpp | 309 ++++ src/devices/bus/nes/konami.c | 787 ---------- src/devices/bus/nes/konami.cpp | 787 ++++++++++ src/devices/bus/nes/legacy.c | 311 ---- src/devices/bus/nes/legacy.cpp | 311 ++++ src/devices/bus/nes/mmc1.c | 374 ----- src/devices/bus/nes/mmc1.cpp | 374 +++++ src/devices/bus/nes/mmc2.c | 198 --- src/devices/bus/nes/mmc2.cpp | 198 +++ src/devices/bus/nes/mmc3.c | 560 -------- src/devices/bus/nes/mmc3.cpp | 560 ++++++++ src/devices/bus/nes/mmc3_clones.c | 2588 --------------------------------- src/devices/bus/nes/mmc3_clones.cpp | 2588 +++++++++++++++++++++++++++++++++ src/devices/bus/nes/mmc5.c | 679 --------- src/devices/bus/nes/mmc5.cpp | 679 +++++++++ src/devices/bus/nes/multigame.c | 2602 ---------------------------------- src/devices/bus/nes/multigame.cpp | 2602 ++++++++++++++++++++++++++++++++++ src/devices/bus/nes/namcot.c | 688 --------- src/devices/bus/nes/namcot.cpp | 688 +++++++++ src/devices/bus/nes/nanjing.c | 175 --- src/devices/bus/nes/nanjing.cpp | 175 +++ src/devices/bus/nes/nes_carts.c | 366 ----- src/devices/bus/nes/nes_carts.cpp | 366 +++++ src/devices/bus/nes/nes_slot.c | 1053 -------------- src/devices/bus/nes/nes_slot.cpp | 1053 ++++++++++++++ src/devices/bus/nes/ntdec.c | 186 --- src/devices/bus/nes/ntdec.cpp | 186 +++ src/devices/bus/nes/nxrom.c | 583 -------- src/devices/bus/nes/nxrom.cpp | 583 ++++++++ src/devices/bus/nes/pirate.c | 1387 ------------------ src/devices/bus/nes/pirate.cpp | 1387 ++++++++++++++++++ src/devices/bus/nes/pt554.c | 107 -- src/devices/bus/nes/pt554.cpp | 107 ++ src/devices/bus/nes/racermate.c | 92 -- src/devices/bus/nes/racermate.cpp | 92 ++ src/devices/bus/nes/rcm.c | 303 ---- src/devices/bus/nes/rcm.cpp | 303 ++++ src/devices/bus/nes/rexsoft.c | 262 ---- src/devices/bus/nes/rexsoft.cpp | 262 ++++ src/devices/bus/nes/sachen.c | 695 --------- src/devices/bus/nes/sachen.cpp | 695 +++++++++ src/devices/bus/nes/somari.c | 421 ------ src/devices/bus/nes/somari.cpp | 421 ++++++ src/devices/bus/nes/sunsoft.c | 628 -------- src/devices/bus/nes/sunsoft.cpp | 628 ++++++++ src/devices/bus/nes/sunsoft_dcs.c | 315 ---- src/devices/bus/nes/sunsoft_dcs.cpp | 315 ++++ src/devices/bus/nes/taito.c | 470 ------ src/devices/bus/nes/taito.cpp | 470 ++++++ src/devices/bus/nes/tengen.c | 376 ----- src/devices/bus/nes/tengen.cpp | 376 +++++ src/devices/bus/nes/txc.c | 268 ---- src/devices/bus/nes/txc.cpp | 268 ++++ src/devices/bus/nes/waixing.c | 1244 ---------------- src/devices/bus/nes/waixing.cpp | 1244 ++++++++++++++++ 100 files changed, 26464 insertions(+), 26464 deletions(-) delete mode 100644 src/devices/bus/nes/2a03pur.c create mode 100644 src/devices/bus/nes/2a03pur.cpp delete mode 100644 src/devices/bus/nes/act53.c create mode 100644 src/devices/bus/nes/act53.cpp delete mode 100644 src/devices/bus/nes/aladdin.c create mode 100644 src/devices/bus/nes/aladdin.cpp delete mode 100644 src/devices/bus/nes/ave.c create mode 100644 src/devices/bus/nes/ave.cpp delete mode 100644 src/devices/bus/nes/bandai.c create mode 100644 src/devices/bus/nes/bandai.cpp delete mode 100644 src/devices/bus/nes/benshieng.c create mode 100644 src/devices/bus/nes/benshieng.cpp delete mode 100644 src/devices/bus/nes/bootleg.c create mode 100644 src/devices/bus/nes/bootleg.cpp delete mode 100644 src/devices/bus/nes/camerica.c create mode 100644 src/devices/bus/nes/camerica.cpp delete mode 100644 src/devices/bus/nes/cne.c create mode 100644 src/devices/bus/nes/cne.cpp delete mode 100644 src/devices/bus/nes/cony.c create mode 100644 src/devices/bus/nes/cony.cpp delete mode 100644 src/devices/bus/nes/datach.c create mode 100644 src/devices/bus/nes/datach.cpp delete mode 100644 src/devices/bus/nes/discrete.c create mode 100644 src/devices/bus/nes/discrete.cpp delete mode 100644 src/devices/bus/nes/disksys.c create mode 100644 src/devices/bus/nes/disksys.cpp delete mode 100644 src/devices/bus/nes/event.c create mode 100644 src/devices/bus/nes/event.cpp delete mode 100644 src/devices/bus/nes/ggenie.c create mode 100644 src/devices/bus/nes/ggenie.cpp delete mode 100644 src/devices/bus/nes/henggedianzi.c create mode 100644 src/devices/bus/nes/henggedianzi.cpp delete mode 100644 src/devices/bus/nes/hes.c create mode 100644 src/devices/bus/nes/hes.cpp delete mode 100644 src/devices/bus/nes/hosenkan.c create mode 100644 src/devices/bus/nes/hosenkan.cpp delete mode 100644 src/devices/bus/nes/irem.c create mode 100644 src/devices/bus/nes/irem.cpp delete mode 100644 src/devices/bus/nes/jaleco.c create mode 100644 src/devices/bus/nes/jaleco.cpp delete mode 100644 src/devices/bus/nes/jy.c create mode 100644 src/devices/bus/nes/jy.cpp delete mode 100644 src/devices/bus/nes/kaiser.c create mode 100644 src/devices/bus/nes/kaiser.cpp delete mode 100644 src/devices/bus/nes/karastudio.c create mode 100644 src/devices/bus/nes/karastudio.cpp delete mode 100644 src/devices/bus/nes/konami.c create mode 100644 src/devices/bus/nes/konami.cpp delete mode 100644 src/devices/bus/nes/legacy.c create mode 100644 src/devices/bus/nes/legacy.cpp delete mode 100644 src/devices/bus/nes/mmc1.c create mode 100644 src/devices/bus/nes/mmc1.cpp delete mode 100644 src/devices/bus/nes/mmc2.c create mode 100644 src/devices/bus/nes/mmc2.cpp delete mode 100644 src/devices/bus/nes/mmc3.c create mode 100644 src/devices/bus/nes/mmc3.cpp delete mode 100644 src/devices/bus/nes/mmc3_clones.c create mode 100644 src/devices/bus/nes/mmc3_clones.cpp delete mode 100644 src/devices/bus/nes/mmc5.c create mode 100644 src/devices/bus/nes/mmc5.cpp delete mode 100644 src/devices/bus/nes/multigame.c create mode 100644 src/devices/bus/nes/multigame.cpp delete mode 100644 src/devices/bus/nes/namcot.c create mode 100644 src/devices/bus/nes/namcot.cpp delete mode 100644 src/devices/bus/nes/nanjing.c create mode 100644 src/devices/bus/nes/nanjing.cpp delete mode 100644 src/devices/bus/nes/nes_carts.c create mode 100644 src/devices/bus/nes/nes_carts.cpp delete mode 100644 src/devices/bus/nes/nes_slot.c create mode 100644 src/devices/bus/nes/nes_slot.cpp delete mode 100644 src/devices/bus/nes/ntdec.c create mode 100644 src/devices/bus/nes/ntdec.cpp delete mode 100644 src/devices/bus/nes/nxrom.c create mode 100644 src/devices/bus/nes/nxrom.cpp delete mode 100644 src/devices/bus/nes/pirate.c create mode 100644 src/devices/bus/nes/pirate.cpp delete mode 100644 src/devices/bus/nes/pt554.c create mode 100644 src/devices/bus/nes/pt554.cpp delete mode 100644 src/devices/bus/nes/racermate.c create mode 100644 src/devices/bus/nes/racermate.cpp delete mode 100644 src/devices/bus/nes/rcm.c create mode 100644 src/devices/bus/nes/rcm.cpp delete mode 100644 src/devices/bus/nes/rexsoft.c create mode 100644 src/devices/bus/nes/rexsoft.cpp delete mode 100644 src/devices/bus/nes/sachen.c create mode 100644 src/devices/bus/nes/sachen.cpp delete mode 100644 src/devices/bus/nes/somari.c create mode 100644 src/devices/bus/nes/somari.cpp delete mode 100644 src/devices/bus/nes/sunsoft.c create mode 100644 src/devices/bus/nes/sunsoft.cpp delete mode 100644 src/devices/bus/nes/sunsoft_dcs.c create mode 100644 src/devices/bus/nes/sunsoft_dcs.cpp delete mode 100644 src/devices/bus/nes/taito.c create mode 100644 src/devices/bus/nes/taito.cpp delete mode 100644 src/devices/bus/nes/tengen.c create mode 100644 src/devices/bus/nes/tengen.cpp delete mode 100644 src/devices/bus/nes/txc.c create mode 100644 src/devices/bus/nes/txc.cpp delete mode 100644 src/devices/bus/nes/waixing.c create mode 100644 src/devices/bus/nes/waixing.cpp (limited to 'src/devices/bus/nes') diff --git a/src/devices/bus/nes/2a03pur.c b/src/devices/bus/nes/2a03pur.c deleted file mode 100644 index d7c807b63f2..00000000000 --- a/src/devices/bus/nes/2a03pur.c +++ /dev/null @@ -1,109 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Fabio Priuli -/*********************************************************************************************************** - - - NES/Famicom cartridge emulation for 2A03 Puritans Album - - - Here we emulate the PCB designed by infiniteneslives and - rainwarrior for this homebew multicart [mapper 30?] - The main difference of this PCB compared to others is that it - uses 4k PRG banks! - - ***********************************************************************************************************/ - - -#include "emu.h" -#include "2a03pur.h" - - -#ifdef NES_PCB_DEBUG -#define VERBOSE 1 -#else -#define VERBOSE 0 -#endif - -#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) - - -//------------------------------------------------- -// constructor -//------------------------------------------------- - -const device_type NES_2A03PURITANS = &device_creator; - - -nes_2a03pur_device::nes_2a03pur_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_2A03PURITANS, "NES Cart 2A03 Puritans Album PCB", tag, owner, clock, "nes_2a03pur", __FILE__) -{ -} - - - -void nes_2a03pur_device::device_start() -{ - common_start(); - save_item(NAME(m_reg)); - memset(m_reg, 0x00, sizeof(m_reg)); - m_reg[7] = 0xff; -} - -void nes_2a03pur_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - chr8(0, m_chr_source); - // register content is not touched by reset -} - - -/*------------------------------------------------- - mapper specific handlers - -------------------------------------------------*/ - -/*------------------------------------------------- - - Board 2A03 Puritans Album - - In MESS: supported. - - This mapper supports up to 1MB of PRG-ROM, in 4k - banks located at $8000, $9000, $A000, $B000, $C000, - $D000, $E000, and $F000. Each bank is selected by n - 8-bit register at $5FF8, $5FF9, $5FFA, $5FFB, $5FFC, - $5FFD, $5FFE, and $5FFF, respectively, just like NSF - banking. These registers are mirrored across the - entire $5000-$5FFF region (the register is selected - by the low 3 bits), but it is recommended to use the - original addresses. The mirroring is merely a - convenience for the hardware implementation. - - The 8kb CHR region may be RAM or ROM. This project - uses CHR-RAM, and the board used by infiniteneslives - for this project may only support CHR-RAM. - - At power-on, the mapper automatically sets all bits - in the $5FFF bank register, placing the highest bank - in $F000. This occurs on power-on but not on reset, - so any bank that is mapped to $F000 after power-on - should contain a valid reset vector. - - At present, the project uses iNES mapper 30 to - designate this mapper. No mapper number has been - officially reserved yet. - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_2a03pur_device::write_l) -{ - LOG_MMC(("2a03 puritans write_l, offset: %04x, data: %02x\n", offset, data)); - offset += 0x100; - if (offset >= 0x1000) - m_reg[offset & 7] = data; -} - -READ8_MEMBER(nes_2a03pur_device::read_h) -{ - LOG_MMC(("2a03 puritans read_h, offset: %04x\n", offset)); - - return m_prg[(m_reg[(offset >> 12) & 7] * 0x1000) + (offset & 0x0fff)]; -} diff --git a/src/devices/bus/nes/2a03pur.cpp b/src/devices/bus/nes/2a03pur.cpp new file mode 100644 index 00000000000..d7c807b63f2 --- /dev/null +++ b/src/devices/bus/nes/2a03pur.cpp @@ -0,0 +1,109 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for 2A03 Puritans Album + + + Here we emulate the PCB designed by infiniteneslives and + rainwarrior for this homebew multicart [mapper 30?] + The main difference of this PCB compared to others is that it + uses 4k PRG banks! + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "2a03pur.h" + + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_2A03PURITANS = &device_creator; + + +nes_2a03pur_device::nes_2a03pur_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_2A03PURITANS, "NES Cart 2A03 Puritans Album PCB", tag, owner, clock, "nes_2a03pur", __FILE__) +{ +} + + + +void nes_2a03pur_device::device_start() +{ + common_start(); + save_item(NAME(m_reg)); + memset(m_reg, 0x00, sizeof(m_reg)); + m_reg[7] = 0xff; +} + +void nes_2a03pur_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + chr8(0, m_chr_source); + // register content is not touched by reset +} + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + Board 2A03 Puritans Album + + In MESS: supported. + + This mapper supports up to 1MB of PRG-ROM, in 4k + banks located at $8000, $9000, $A000, $B000, $C000, + $D000, $E000, and $F000. Each bank is selected by n + 8-bit register at $5FF8, $5FF9, $5FFA, $5FFB, $5FFC, + $5FFD, $5FFE, and $5FFF, respectively, just like NSF + banking. These registers are mirrored across the + entire $5000-$5FFF region (the register is selected + by the low 3 bits), but it is recommended to use the + original addresses. The mirroring is merely a + convenience for the hardware implementation. + + The 8kb CHR region may be RAM or ROM. This project + uses CHR-RAM, and the board used by infiniteneslives + for this project may only support CHR-RAM. + + At power-on, the mapper automatically sets all bits + in the $5FFF bank register, placing the highest bank + in $F000. This occurs on power-on but not on reset, + so any bank that is mapped to $F000 after power-on + should contain a valid reset vector. + + At present, the project uses iNES mapper 30 to + designate this mapper. No mapper number has been + officially reserved yet. + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_2a03pur_device::write_l) +{ + LOG_MMC(("2a03 puritans write_l, offset: %04x, data: %02x\n", offset, data)); + offset += 0x100; + if (offset >= 0x1000) + m_reg[offset & 7] = data; +} + +READ8_MEMBER(nes_2a03pur_device::read_h) +{ + LOG_MMC(("2a03 puritans read_h, offset: %04x\n", offset)); + + return m_prg[(m_reg[(offset >> 12) & 7] * 0x1000) + (offset & 0x0fff)]; +} diff --git a/src/devices/bus/nes/act53.c b/src/devices/bus/nes/act53.c deleted file mode 100644 index a09244b3a85..00000000000 --- a/src/devices/bus/nes/act53.c +++ /dev/null @@ -1,206 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Fabio Priuli -/*********************************************************************************************************** - - - NES/Famicom cartridge emulation for Action 53 - - - Here we emulate the Multi-Discrete PCB designed by Tepples for - this homebew multicart [mapper 28] - - ***********************************************************************************************************/ - - -#include "emu.h" -#include "act53.h" - - -#ifdef NES_PCB_DEBUG -#define VERBOSE 1 -#else -#define VERBOSE 0 -#endif - -#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) - - -//------------------------------------------------- -// constructor -//------------------------------------------------- - -const device_type NES_ACTION53 = &device_creator; - - -nes_action53_device::nes_action53_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_ACTION53, "NES Cart Action 53 PCB", tag, owner, clock, "nes_action53", __FILE__) -{ -} - - - -void nes_action53_device::device_start() -{ - common_start(); - save_item(NAME(m_sel)); - save_item(NAME(m_reg)); - m_reg[0] = 0x00; - m_reg[1] = 0x0f; - m_reg[2] = 0x00; - m_reg[3] = 0x3f; -} - -void nes_action53_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - // register content is not touched by reset - update_prg(); -} - - -/*------------------------------------------------- - mapper specific handlers - -------------------------------------------------*/ - -/*------------------------------------------------- - - Board ACTION 53 - - In MESS: *VERY* preliminary support. - - This board uses 4 registers (reg is selected by writes to 0x5xxx) - Info from nesdev wiki - - R:$00: [...M ..CC] - C = CHR Reg - M = Mirroring - This bit overwrites bit 0 of R:$80, but only if bit 1 of - R:$80 is clear - - R:$01: [...M PPPP] - P = PRG Reg - M = Mirroring - This bit overwrites bit 0 of R:$80, but only if bit 1 of - R:$80 is clear - - R:$80: [..GG PSMM] - G = Game Size (0=32K, 1=64K, 2=128K, 3=256K) - P = PRG Size (0=32k mode, 1=16k mode) - S = Slot select: - 0 = $C000 swappable, $8000 fixed to bottom of 32K outer bank - 1 = $8000 swappable, $C000 fixed to top of 32K outer bank - This bit is ignored when 'P' is clear (32k mode) - M = Mirroring control: - %00 = 1ScA - %01 = 1ScB - %10 = Vert - %11 = Horz - - R:$81: [..BB BBBB] - Outer PRG Reg - - - -------------------------------------------------*/ - -void nes_action53_device::update_prg() -{ - UINT8 prg_lo = 0, prg_hi = 0, helper = 0; - UINT8 out = (m_reg[3] & 0x3f) << 1; // Outer PRG reg - UINT8 size = (m_reg[2] & 0x30) >> 4; // Game size - UINT8 mask = (1 << (size + 1)) - 1; // Bits to be taken from PRG reg - - if (!BIT(m_reg[2], 3)) - { - helper = (out & ~mask) | ((m_reg[1] << 1) & mask); - //32K mode - prg_lo = (helper & 0xfe); - prg_hi = (helper | 0x01); - } - else - { - helper = (out & ~mask) | (m_reg[1] & mask); - if (BIT(m_reg[2], 2)) - { - //16K mode with fixed HI - prg_lo = helper; - prg_hi = (out | 0x01); - } - else - { - //16K mode with fixed LO - prg_lo = (out & 0xfe); - prg_hi = helper; - } - } - -// printf("banks : 0x%2X - 0x%2X\n", prg_lo, prg_hi); - prg16_89ab(prg_lo); - prg16_cdef(prg_hi); -} - -void nes_action53_device::update_mirr() -{ - switch (m_reg[2] & 0x03) - { - case 0: - set_nt_mirroring(PPU_MIRROR_LOW); - break; - case 1: - set_nt_mirroring(PPU_MIRROR_HIGH); - break; - case 2: - set_nt_mirroring(PPU_MIRROR_VERT); - break; - case 3: - set_nt_mirroring(PPU_MIRROR_HORZ); - break; - } -} - -WRITE8_MEMBER(nes_action53_device::write_l) -{ - LOG_MMC(("action 53 write_l, offset: %04x, data: %02x\n", offset, data)); - offset += 0x100; - if (offset >= 0x1000) - m_sel = BIT(data, 0) | (BIT(data, 7) << 1); -} - - -WRITE8_MEMBER(nes_action53_device::write_h) -{ - LOG_MMC(("action 53 write_h, offset: %04x, data: %02x\n", offset, data)); - - if (m_reg[m_sel] != data) - { - m_reg[m_sel] = data; - - switch (m_sel) - { - case 0: - if (!BIT(m_reg[2],1)) - { - m_reg[2] &= 0xfe; - m_reg[2] |= BIT(data,4); - update_mirr(); - } - chr8(m_reg[0] & 0x03, m_chr_source); - break; - case 1: - if (!BIT(m_reg[2],1)) - { - m_reg[2] &= 0xfe; - m_reg[2] |= BIT(data,4); - update_mirr(); - } - update_prg(); - break; - case 2: - update_prg(); - update_mirr(); - break; - case 3: - update_prg(); - break; - } - } -} diff --git a/src/devices/bus/nes/act53.cpp b/src/devices/bus/nes/act53.cpp new file mode 100644 index 00000000000..a09244b3a85 --- /dev/null +++ b/src/devices/bus/nes/act53.cpp @@ -0,0 +1,206 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for Action 53 + + + Here we emulate the Multi-Discrete PCB designed by Tepples for + this homebew multicart [mapper 28] + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "act53.h" + + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_ACTION53 = &device_creator; + + +nes_action53_device::nes_action53_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_ACTION53, "NES Cart Action 53 PCB", tag, owner, clock, "nes_action53", __FILE__) +{ +} + + + +void nes_action53_device::device_start() +{ + common_start(); + save_item(NAME(m_sel)); + save_item(NAME(m_reg)); + m_reg[0] = 0x00; + m_reg[1] = 0x0f; + m_reg[2] = 0x00; + m_reg[3] = 0x3f; +} + +void nes_action53_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + // register content is not touched by reset + update_prg(); +} + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + Board ACTION 53 + + In MESS: *VERY* preliminary support. + + This board uses 4 registers (reg is selected by writes to 0x5xxx) + Info from nesdev wiki + + R:$00: [...M ..CC] + C = CHR Reg + M = Mirroring + This bit overwrites bit 0 of R:$80, but only if bit 1 of + R:$80 is clear + + R:$01: [...M PPPP] + P = PRG Reg + M = Mirroring + This bit overwrites bit 0 of R:$80, but only if bit 1 of + R:$80 is clear + + R:$80: [..GG PSMM] + G = Game Size (0=32K, 1=64K, 2=128K, 3=256K) + P = PRG Size (0=32k mode, 1=16k mode) + S = Slot select: + 0 = $C000 swappable, $8000 fixed to bottom of 32K outer bank + 1 = $8000 swappable, $C000 fixed to top of 32K outer bank + This bit is ignored when 'P' is clear (32k mode) + M = Mirroring control: + %00 = 1ScA + %01 = 1ScB + %10 = Vert + %11 = Horz + + R:$81: [..BB BBBB] + Outer PRG Reg + + + -------------------------------------------------*/ + +void nes_action53_device::update_prg() +{ + UINT8 prg_lo = 0, prg_hi = 0, helper = 0; + UINT8 out = (m_reg[3] & 0x3f) << 1; // Outer PRG reg + UINT8 size = (m_reg[2] & 0x30) >> 4; // Game size + UINT8 mask = (1 << (size + 1)) - 1; // Bits to be taken from PRG reg + + if (!BIT(m_reg[2], 3)) + { + helper = (out & ~mask) | ((m_reg[1] << 1) & mask); + //32K mode + prg_lo = (helper & 0xfe); + prg_hi = (helper | 0x01); + } + else + { + helper = (out & ~mask) | (m_reg[1] & mask); + if (BIT(m_reg[2], 2)) + { + //16K mode with fixed HI + prg_lo = helper; + prg_hi = (out | 0x01); + } + else + { + //16K mode with fixed LO + prg_lo = (out & 0xfe); + prg_hi = helper; + } + } + +// printf("banks : 0x%2X - 0x%2X\n", prg_lo, prg_hi); + prg16_89ab(prg_lo); + prg16_cdef(prg_hi); +} + +void nes_action53_device::update_mirr() +{ + switch (m_reg[2] & 0x03) + { + case 0: + set_nt_mirroring(PPU_MIRROR_LOW); + break; + case 1: + set_nt_mirroring(PPU_MIRROR_HIGH); + break; + case 2: + set_nt_mirroring(PPU_MIRROR_VERT); + break; + case 3: + set_nt_mirroring(PPU_MIRROR_HORZ); + break; + } +} + +WRITE8_MEMBER(nes_action53_device::write_l) +{ + LOG_MMC(("action 53 write_l, offset: %04x, data: %02x\n", offset, data)); + offset += 0x100; + if (offset >= 0x1000) + m_sel = BIT(data, 0) | (BIT(data, 7) << 1); +} + + +WRITE8_MEMBER(nes_action53_device::write_h) +{ + LOG_MMC(("action 53 write_h, offset: %04x, data: %02x\n", offset, data)); + + if (m_reg[m_sel] != data) + { + m_reg[m_sel] = data; + + switch (m_sel) + { + case 0: + if (!BIT(m_reg[2],1)) + { + m_reg[2] &= 0xfe; + m_reg[2] |= BIT(data,4); + update_mirr(); + } + chr8(m_reg[0] & 0x03, m_chr_source); + break; + case 1: + if (!BIT(m_reg[2],1)) + { + m_reg[2] &= 0xfe; + m_reg[2] |= BIT(data,4); + update_mirr(); + } + update_prg(); + break; + case 2: + update_prg(); + update_mirr(); + break; + case 3: + update_prg(); + break; + } + } +} diff --git a/src/devices/bus/nes/aladdin.c b/src/devices/bus/nes/aladdin.c deleted file mode 100644 index 67749cbe12d..00000000000 --- a/src/devices/bus/nes/aladdin.c +++ /dev/null @@ -1,339 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Fabio Priuli -/*********************************************************************************************************** - - - NES/Famicom cartridge emulation for Camerica/Codemasters Aladdin Deck Enhancer pass-through cart - - - Here we emulate the following PCBs - - * Camerica ALGNV11 [mapper 71] - * Camerica ALGQV11 [mapper 232] - - ***********************************************************************************************************/ - - -#include "emu.h" -#include "aladdin.h" - - -#ifdef NES_PCB_DEBUG -#define VERBOSE 1 -#else -#define VERBOSE 0 -#endif - -#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) - - - -//---------------------------------- -// -// Aladdin Cartslot implementation -// -//---------------------------------- - -//------------------------------------------------- -// sub-cart interface -//------------------------------------------------- - -aladdin_cart_interface::aladdin_cart_interface(const machine_config &mconfig, device_t &device) - : device_slot_card_interface(mconfig, device), - m_rom(NULL), - m_rom_size(0), - m_rom_mask(0xff) -{ -} - -aladdin_cart_interface::~aladdin_cart_interface() -{ -} - -READ8_MEMBER(aladdin_cart_interface::read) -{ - if (offset < 0x4000) - return m_rom[(m_lobank * 0x4000) + (offset & 0x3fff)]; - else - return m_rom[(m_hibank * 0x4000) + (offset & 0x3fff)]; -} - -//------------------------------------------------- -// sub-cart slot device -//------------------------------------------------- - -const device_type NES_ALADDIN_SLOT = &device_creator; - -nes_aladdin_slot_device::nes_aladdin_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : - device_t(mconfig, NES_ALADDIN_SLOT, "NES Aladdin Deck Enhancer Cartridge Slot", tag, owner, clock, "nes_ade_slot", __FILE__), - device_image_interface(mconfig, *this), - device_slot_interface(mconfig, *this) -{ -} - -nes_aladdin_slot_device::~nes_aladdin_slot_device() -{ -} - - -void nes_aladdin_slot_device::device_start() -{ - m_cart = dynamic_cast(get_card_device()); -} - -READ8_MEMBER(nes_aladdin_slot_device::read) -{ - if (m_cart) - return m_cart->read(space, offset, mem_mask); - - return 0xff; -} - -// 128K for Dizzy The Adventurer, 256K for the others -bool nes_aladdin_slot_device::call_load() -{ - if (m_cart) - { - UINT8 *ROM = m_cart->get_cart_base(); - UINT32 size = 0; - - if (!ROM) - return IMAGE_INIT_FAIL; - - if (software_entry() == NULL) - { - if (length() != 0x20010 && length() != 0x40010) - return IMAGE_INIT_FAIL; - - UINT8 temp[0x40010]; - size = length() - 0x10; - fread(&temp, length()); - memcpy(ROM, temp + 0x10, size); - - // double check that iNES files are really mapper 71 or 232 - { - UINT8 mapper = (temp[6] & 0xf0) >> 4; - mapper |= temp[7] & 0xf0; - if (mapper != 71 && mapper != 232) - return IMAGE_INIT_FAIL; - } - } - else - { - if (get_software_region_length("rom") != 0x20000 && get_software_region_length("rom") != 0x40000) - return IMAGE_INIT_FAIL; - - size = get_software_region_length("rom"); - memcpy(ROM, get_software_region("rom"), size); - } - - m_cart->set_cart_size(size); - } - - return IMAGE_INIT_PASS; -} - - -bool nes_aladdin_slot_device::call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry) -{ - load_software_part_region(*this, swlist, swname, start_entry ); - return TRUE; -} - -void nes_aladdin_slot_device::get_default_card_software(std::string &result) -{ - if (open_image_file(mconfig().options())) - { - const char *slot_string = "algn"; - UINT32 len = core_fsize(m_file); - dynamic_buffer rom(len); - UINT8 mapper; - - core_fread(m_file, &rom[0], len); - - mapper = (rom[6] & 0xf0) >> 4; - mapper |= rom[7] & 0xf0; - -// if (mapper == 71) -// slot_string = "algn"; - if (mapper == 232) - slot_string = "algq"; - - clear(); - - result.assign(slot_string); - } - else - software_get_default_slot(result, "algn"); -} - - -//---------------------------------- -// -// Aladdin Minicart implementation -// -//---------------------------------- - -ROM_START( ade_rom ) - ROM_REGION(0x40000, "aderom", ROMREGION_ERASEFF) -ROM_END - -const device_type NES_ALGN_ROM = &device_creator; -const device_type NES_ALGQ_ROM = &device_creator; - -nes_algn_rom_device::nes_algn_rom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) - : device_t(mconfig, type, name, tag, owner, clock, shortname, source), - aladdin_cart_interface( mconfig, *this ) -{ -} - -nes_algn_rom_device::nes_algn_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : device_t(mconfig, NES_ALGN_ROM, "NES Aladdin Deck Enhancer ALGN ROM", tag, owner, clock, "nes_algn_rom", __FILE__), - aladdin_cart_interface( mconfig, *this ) -{ -} - -nes_algq_rom_device::nes_algq_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_algn_rom_device(mconfig, NES_ALGQ_ROM, "NES Aladdin Deck Enhancer ALGQ ROM", tag, owner, clock, "nes_algq_rom", __FILE__) -{ -} - -void nes_algn_rom_device::device_start() -{ - m_rom = (UINT8*)memregion("aderom")->base(); - save_item(NAME(m_lobank)); -} - -void nes_algn_rom_device::device_reset() -{ - m_lobank = 0; - m_hibank = 0x0f & m_rom_mask; -} - -void nes_algq_rom_device::device_start() -{ - m_rom = (UINT8*)memregion("aderom")->base(); - save_item(NAME(m_lobank)); - save_item(NAME(m_hibank)); - save_item(NAME(m_bank_base)); -} - -void nes_algq_rom_device::device_reset() -{ - m_lobank = 0; - m_hibank = 3; - m_bank_base = 0; -} - -const rom_entry *nes_algn_rom_device::device_rom_region() const -{ - return ROM_NAME( ade_rom ); -} - -UINT8 *nes_algn_rom_device::get_cart_base() -{ - return m_rom; -} - -void nes_algn_rom_device::write_prg(UINT32 offset, UINT8 data) -{ - // m_hibank is fixed to the last available bank! - if (offset >= 0x4000) - m_lobank = data & m_rom_mask; -} - -void nes_algq_rom_device::write_prg(UINT32 offset, UINT8 data) -{ - // here hibank & lobank variables are used differently - // m_bank_base = 64K block - // m_lobank = 16K page inside the block - // m_hibank = 3rd page inside the block - if (offset < 0x4000) - { - m_bank_base = ((data >> 3) & 3) << 2; - m_lobank = m_bank_base | (m_lobank & 3); - m_hibank = m_bank_base | 3; - } - else - m_lobank = m_bank_base | (data & 3); -} - - -//----------------------------------------------- -// -// Camerica/Codemasters Aladdin passthru -// implementation -// -//----------------------------------------------- - -const device_type NES_ALADDIN = &device_creator; - -nes_aladdin_device::nes_aladdin_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_ALADDIN, "NES Cart Camerica Aladdin PCB", tag, owner, clock, "nes_aladdin", __FILE__), - m_subslot(*this, "ade_slot") -{ -} - - -void nes_aladdin_device::device_start() -{ - common_start(); -} - -void nes_aladdin_device::pcb_reset() -{ - prg32(0xff); - chr8(0, CHRRAM); -} - - -/*------------------------------------------------- - mapper specific handlers - -------------------------------------------------*/ - -/*------------------------------------------------- - - Camerica/Codemasters Aladdin Deck Enhancer - - iNES: mapper 71 & 232 - - In MESS: Supported (but timing issues in some games) - - -------------------------------------------------*/ - -READ8_MEMBER(nes_aladdin_device::read_h) -{ - LOG_MMC(("aladdin read_h, offset: %04x\n", offset)); - // this shall be the proper code, but it's a bit slower, so we access directly the subcart below - //return m_subslot->read(space, offset, mem_mask); - - if (m_subslot->m_cart) - return m_subslot->m_cart->read(space, offset, mem_mask); - else // this is "fake" in the sense that we fill CPU space with 0xff if no Aladdin cart is loaded - return hi_access_rom(offset); -} - -WRITE8_MEMBER(nes_aladdin_device::write_h) -{ - LOG_MMC(("aladdin write_h, offset: %04x, data: %02x\n", offset, data)); - m_subslot->write_prg(offset, data); -} - -//------------------------------------------------- -// CART SLOT -//------------------------------------------------- - -static SLOT_INTERFACE_START(ade_cart) - SLOT_INTERFACE_INTERNAL("algn", NES_ALGN_ROM) - SLOT_INTERFACE_INTERNAL("algq", NES_ALGQ_ROM) -SLOT_INTERFACE_END - - -MACHINE_CONFIG_FRAGMENT( camerica_aladdin ) - MCFG_ALADDIN_MINICART_ADD("ade_slot", ade_cart) -MACHINE_CONFIG_END - -machine_config_constructor nes_aladdin_device::device_mconfig_additions() const -{ - return MACHINE_CONFIG_NAME( camerica_aladdin ); -} diff --git a/src/devices/bus/nes/aladdin.cpp b/src/devices/bus/nes/aladdin.cpp new file mode 100644 index 00000000000..67749cbe12d --- /dev/null +++ b/src/devices/bus/nes/aladdin.cpp @@ -0,0 +1,339 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for Camerica/Codemasters Aladdin Deck Enhancer pass-through cart + + + Here we emulate the following PCBs + + * Camerica ALGNV11 [mapper 71] + * Camerica ALGQV11 [mapper 232] + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "aladdin.h" + + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + + +//---------------------------------- +// +// Aladdin Cartslot implementation +// +//---------------------------------- + +//------------------------------------------------- +// sub-cart interface +//------------------------------------------------- + +aladdin_cart_interface::aladdin_cart_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig, device), + m_rom(NULL), + m_rom_size(0), + m_rom_mask(0xff) +{ +} + +aladdin_cart_interface::~aladdin_cart_interface() +{ +} + +READ8_MEMBER(aladdin_cart_interface::read) +{ + if (offset < 0x4000) + return m_rom[(m_lobank * 0x4000) + (offset & 0x3fff)]; + else + return m_rom[(m_hibank * 0x4000) + (offset & 0x3fff)]; +} + +//------------------------------------------------- +// sub-cart slot device +//------------------------------------------------- + +const device_type NES_ALADDIN_SLOT = &device_creator; + +nes_aladdin_slot_device::nes_aladdin_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, NES_ALADDIN_SLOT, "NES Aladdin Deck Enhancer Cartridge Slot", tag, owner, clock, "nes_ade_slot", __FILE__), + device_image_interface(mconfig, *this), + device_slot_interface(mconfig, *this) +{ +} + +nes_aladdin_slot_device::~nes_aladdin_slot_device() +{ +} + + +void nes_aladdin_slot_device::device_start() +{ + m_cart = dynamic_cast(get_card_device()); +} + +READ8_MEMBER(nes_aladdin_slot_device::read) +{ + if (m_cart) + return m_cart->read(space, offset, mem_mask); + + return 0xff; +} + +// 128K for Dizzy The Adventurer, 256K for the others +bool nes_aladdin_slot_device::call_load() +{ + if (m_cart) + { + UINT8 *ROM = m_cart->get_cart_base(); + UINT32 size = 0; + + if (!ROM) + return IMAGE_INIT_FAIL; + + if (software_entry() == NULL) + { + if (length() != 0x20010 && length() != 0x40010) + return IMAGE_INIT_FAIL; + + UINT8 temp[0x40010]; + size = length() - 0x10; + fread(&temp, length()); + memcpy(ROM, temp + 0x10, size); + + // double check that iNES files are really mapper 71 or 232 + { + UINT8 mapper = (temp[6] & 0xf0) >> 4; + mapper |= temp[7] & 0xf0; + if (mapper != 71 && mapper != 232) + return IMAGE_INIT_FAIL; + } + } + else + { + if (get_software_region_length("rom") != 0x20000 && get_software_region_length("rom") != 0x40000) + return IMAGE_INIT_FAIL; + + size = get_software_region_length("rom"); + memcpy(ROM, get_software_region("rom"), size); + } + + m_cart->set_cart_size(size); + } + + return IMAGE_INIT_PASS; +} + + +bool nes_aladdin_slot_device::call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry) +{ + load_software_part_region(*this, swlist, swname, start_entry ); + return TRUE; +} + +void nes_aladdin_slot_device::get_default_card_software(std::string &result) +{ + if (open_image_file(mconfig().options())) + { + const char *slot_string = "algn"; + UINT32 len = core_fsize(m_file); + dynamic_buffer rom(len); + UINT8 mapper; + + core_fread(m_file, &rom[0], len); + + mapper = (rom[6] & 0xf0) >> 4; + mapper |= rom[7] & 0xf0; + +// if (mapper == 71) +// slot_string = "algn"; + if (mapper == 232) + slot_string = "algq"; + + clear(); + + result.assign(slot_string); + } + else + software_get_default_slot(result, "algn"); +} + + +//---------------------------------- +// +// Aladdin Minicart implementation +// +//---------------------------------- + +ROM_START( ade_rom ) + ROM_REGION(0x40000, "aderom", ROMREGION_ERASEFF) +ROM_END + +const device_type NES_ALGN_ROM = &device_creator; +const device_type NES_ALGQ_ROM = &device_creator; + +nes_algn_rom_device::nes_algn_rom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + aladdin_cart_interface( mconfig, *this ) +{ +} + +nes_algn_rom_device::nes_algn_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, NES_ALGN_ROM, "NES Aladdin Deck Enhancer ALGN ROM", tag, owner, clock, "nes_algn_rom", __FILE__), + aladdin_cart_interface( mconfig, *this ) +{ +} + +nes_algq_rom_device::nes_algq_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_algn_rom_device(mconfig, NES_ALGQ_ROM, "NES Aladdin Deck Enhancer ALGQ ROM", tag, owner, clock, "nes_algq_rom", __FILE__) +{ +} + +void nes_algn_rom_device::device_start() +{ + m_rom = (UINT8*)memregion("aderom")->base(); + save_item(NAME(m_lobank)); +} + +void nes_algn_rom_device::device_reset() +{ + m_lobank = 0; + m_hibank = 0x0f & m_rom_mask; +} + +void nes_algq_rom_device::device_start() +{ + m_rom = (UINT8*)memregion("aderom")->base(); + save_item(NAME(m_lobank)); + save_item(NAME(m_hibank)); + save_item(NAME(m_bank_base)); +} + +void nes_algq_rom_device::device_reset() +{ + m_lobank = 0; + m_hibank = 3; + m_bank_base = 0; +} + +const rom_entry *nes_algn_rom_device::device_rom_region() const +{ + return ROM_NAME( ade_rom ); +} + +UINT8 *nes_algn_rom_device::get_cart_base() +{ + return m_rom; +} + +void nes_algn_rom_device::write_prg(UINT32 offset, UINT8 data) +{ + // m_hibank is fixed to the last available bank! + if (offset >= 0x4000) + m_lobank = data & m_rom_mask; +} + +void nes_algq_rom_device::write_prg(UINT32 offset, UINT8 data) +{ + // here hibank & lobank variables are used differently + // m_bank_base = 64K block + // m_lobank = 16K page inside the block + // m_hibank = 3rd page inside the block + if (offset < 0x4000) + { + m_bank_base = ((data >> 3) & 3) << 2; + m_lobank = m_bank_base | (m_lobank & 3); + m_hibank = m_bank_base | 3; + } + else + m_lobank = m_bank_base | (data & 3); +} + + +//----------------------------------------------- +// +// Camerica/Codemasters Aladdin passthru +// implementation +// +//----------------------------------------------- + +const device_type NES_ALADDIN = &device_creator; + +nes_aladdin_device::nes_aladdin_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_ALADDIN, "NES Cart Camerica Aladdin PCB", tag, owner, clock, "nes_aladdin", __FILE__), + m_subslot(*this, "ade_slot") +{ +} + + +void nes_aladdin_device::device_start() +{ + common_start(); +} + +void nes_aladdin_device::pcb_reset() +{ + prg32(0xff); + chr8(0, CHRRAM); +} + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + Camerica/Codemasters Aladdin Deck Enhancer + + iNES: mapper 71 & 232 + + In MESS: Supported (but timing issues in some games) + + -------------------------------------------------*/ + +READ8_MEMBER(nes_aladdin_device::read_h) +{ + LOG_MMC(("aladdin read_h, offset: %04x\n", offset)); + // this shall be the proper code, but it's a bit slower, so we access directly the subcart below + //return m_subslot->read(space, offset, mem_mask); + + if (m_subslot->m_cart) + return m_subslot->m_cart->read(space, offset, mem_mask); + else // this is "fake" in the sense that we fill CPU space with 0xff if no Aladdin cart is loaded + return hi_access_rom(offset); +} + +WRITE8_MEMBER(nes_aladdin_device::write_h) +{ + LOG_MMC(("aladdin write_h, offset: %04x, data: %02x\n", offset, data)); + m_subslot->write_prg(offset, data); +} + +//------------------------------------------------- +// CART SLOT +//------------------------------------------------- + +static SLOT_INTERFACE_START(ade_cart) + SLOT_INTERFACE_INTERNAL("algn", NES_ALGN_ROM) + SLOT_INTERFACE_INTERNAL("algq", NES_ALGQ_ROM) +SLOT_INTERFACE_END + + +MACHINE_CONFIG_FRAGMENT( camerica_aladdin ) + MCFG_ALADDIN_MINICART_ADD("ade_slot", ade_cart) +MACHINE_CONFIG_END + +machine_config_constructor nes_aladdin_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( camerica_aladdin ); +} diff --git a/src/devices/bus/nes/ave.c b/src/devices/bus/nes/ave.c deleted file mode 100644 index bc24f1294a5..00000000000 --- a/src/devices/bus/nes/ave.c +++ /dev/null @@ -1,214 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Fabio Priuli -/*********************************************************************************************************** - - - NES/Famicom cartridge emulation for AVE PCBs - - - Here we emulate the following PCBs - - * AVE Nina-001 [mapper 34] - * AVE Nina-006/Nina-003/MB-91 [mapper 79] - * AVE Maxi 15 [mapper 234] - - - ***********************************************************************************************************/ - - -#include "emu.h" -#include "ave.h" - - -#ifdef NES_PCB_DEBUG -#define VERBOSE 1 -#else -#define VERBOSE 0 -#endif - -#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) - - -//------------------------------------------------- -// constructor -//------------------------------------------------- - -const device_type NES_NINA001 = &device_creator; -const device_type NES_NINA006 = &device_creator; -const device_type NES_MAXI15 = &device_creator; - - -nes_nina001_device::nes_nina001_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_NINA001, "NES Cart AVE Nina-001 PCB", tag, owner, clock, "nes_nina001", __FILE__) -{ -} - -nes_nina006_device::nes_nina006_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_NINA006, "NES Cart AVE Nina-006 PCB", tag, owner, clock, "nes_nina006", __FILE__) -{ -} - -nes_maxi15_device::nes_maxi15_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_MAXI15, "NES Cart AVE Maxi 15 PCB", tag, owner, clock, "nes_maxi15", __FILE__) -{ -} - - - - -void nes_nina001_device::device_start() -{ - common_start(); -} - -void nes_nina001_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0); - chr8(0, m_chr_source); -} - -void nes_nina006_device::device_start() -{ - common_start(); -} - -void nes_nina006_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0); - chr8(0, m_chr_source); -} - - -void nes_maxi15_device::device_start() -{ - common_start(); - save_item(NAME(m_bank)); - save_item(NAME(m_reg)); -} - -void nes_maxi15_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0); - chr8(0, m_chr_source); - set_nt_mirroring(PPU_MIRROR_VERT); - - m_reg = 0; - m_bank = 0; -} - - - - - -/*------------------------------------------------- - mapper specific handlers - -------------------------------------------------*/ - -/*------------------------------------------------- - - AVE NINA-001 board emulation - - iNES: mapper 34 - - Notice that in this board the bankswitch regs - overlaps WRAM, so that writes to the regs are - then readable back in WRAM (WRAM is tested by - Impossible Mission II at start) - - In MESS: Supported. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_nina001_device::write_m) -{ - LOG_MMC(("nina-001 write_m, offset: %04x, data: %02x\n", offset, data)); - - switch (offset) - { - case 0x1ffd: - prg32(data); - break; - case 0x1ffe: - chr4_0(data, CHRROM); - break; - case 0x1fff: - chr4_4(data, CHRROM); - break; - } - - m_prgram[offset] = data; -} - -/*------------------------------------------------- - - AVE NINA-003, NINA-006 and MB-91 boards emulation - - Games: Krazy Kreatures, Poke Block, Puzzle, Pyramid, - Solitaire, Ultimate League Soccer - - iNES: mapper 79 - - In MESS: Supported. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_nina006_device::write_l) -{ - LOG_MMC(("nina-006 write_l, offset: %04x, data: %02x\n", offset, data)); - - if (!(offset & 0x0100)) - { - prg32(data >> 3); - chr8(data & 7, CHRROM); - } -} - -/*------------------------------------------------- - - AVE Maxi 15 boards emulation - - Games: Maxi 15 - - iNES: mapper 234 - - In MESS: Partially Supported. - - -------------------------------------------------*/ - -void nes_maxi15_device::update_banks() -{ - if (m_bank & 0x40) - { - prg32((m_bank & 0x0e) | (m_reg & 1)); - chr8(((m_bank & 0x0e) << 2) | ((m_reg >> 4) & 7), m_chr_source); - } - else - { - prg32(m_bank & 0x0f); - chr8(((m_bank & 0x0f) << 2) | ((m_reg >> 4) & 3), m_chr_source); - } -} - -READ8_MEMBER(nes_maxi15_device::read_h) -{ - LOG_MMC(("Maxi 15 read_h, offset: %04x\n", offset)); - - if (offset >= 0x7f80 && offset < 0x7fa0) - { - m_bank = hi_access_rom(offset); - set_nt_mirroring(BIT(m_bank, 7) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); - update_banks(); - return m_bank; - } - if (offset >= 0x7fe8 && offset < 0x7ff8) - { - m_reg = hi_access_rom(offset); - update_banks(); - return m_reg; - } - - return hi_access_rom(offset); -} diff --git a/src/devices/bus/nes/ave.cpp b/src/devices/bus/nes/ave.cpp new file mode 100644 index 00000000000..bc24f1294a5 --- /dev/null +++ b/src/devices/bus/nes/ave.cpp @@ -0,0 +1,214 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for AVE PCBs + + + Here we emulate the following PCBs + + * AVE Nina-001 [mapper 34] + * AVE Nina-006/Nina-003/MB-91 [mapper 79] + * AVE Maxi 15 [mapper 234] + + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "ave.h" + + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_NINA001 = &device_creator; +const device_type NES_NINA006 = &device_creator; +const device_type NES_MAXI15 = &device_creator; + + +nes_nina001_device::nes_nina001_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_NINA001, "NES Cart AVE Nina-001 PCB", tag, owner, clock, "nes_nina001", __FILE__) +{ +} + +nes_nina006_device::nes_nina006_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_NINA006, "NES Cart AVE Nina-006 PCB", tag, owner, clock, "nes_nina006", __FILE__) +{ +} + +nes_maxi15_device::nes_maxi15_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_MAXI15, "NES Cart AVE Maxi 15 PCB", tag, owner, clock, "nes_maxi15", __FILE__) +{ +} + + + + +void nes_nina001_device::device_start() +{ + common_start(); +} + +void nes_nina001_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + +void nes_nina006_device::device_start() +{ + common_start(); +} + +void nes_nina006_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + + +void nes_maxi15_device::device_start() +{ + common_start(); + save_item(NAME(m_bank)); + save_item(NAME(m_reg)); +} + +void nes_maxi15_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); + set_nt_mirroring(PPU_MIRROR_VERT); + + m_reg = 0; + m_bank = 0; +} + + + + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + AVE NINA-001 board emulation + + iNES: mapper 34 + + Notice that in this board the bankswitch regs + overlaps WRAM, so that writes to the regs are + then readable back in WRAM (WRAM is tested by + Impossible Mission II at start) + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_nina001_device::write_m) +{ + LOG_MMC(("nina-001 write_m, offset: %04x, data: %02x\n", offset, data)); + + switch (offset) + { + case 0x1ffd: + prg32(data); + break; + case 0x1ffe: + chr4_0(data, CHRROM); + break; + case 0x1fff: + chr4_4(data, CHRROM); + break; + } + + m_prgram[offset] = data; +} + +/*------------------------------------------------- + + AVE NINA-003, NINA-006 and MB-91 boards emulation + + Games: Krazy Kreatures, Poke Block, Puzzle, Pyramid, + Solitaire, Ultimate League Soccer + + iNES: mapper 79 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_nina006_device::write_l) +{ + LOG_MMC(("nina-006 write_l, offset: %04x, data: %02x\n", offset, data)); + + if (!(offset & 0x0100)) + { + prg32(data >> 3); + chr8(data & 7, CHRROM); + } +} + +/*------------------------------------------------- + + AVE Maxi 15 boards emulation + + Games: Maxi 15 + + iNES: mapper 234 + + In MESS: Partially Supported. + + -------------------------------------------------*/ + +void nes_maxi15_device::update_banks() +{ + if (m_bank & 0x40) + { + prg32((m_bank & 0x0e) | (m_reg & 1)); + chr8(((m_bank & 0x0e) << 2) | ((m_reg >> 4) & 7), m_chr_source); + } + else + { + prg32(m_bank & 0x0f); + chr8(((m_bank & 0x0f) << 2) | ((m_reg >> 4) & 3), m_chr_source); + } +} + +READ8_MEMBER(nes_maxi15_device::read_h) +{ + LOG_MMC(("Maxi 15 read_h, offset: %04x\n", offset)); + + if (offset >= 0x7f80 && offset < 0x7fa0) + { + m_bank = hi_access_rom(offset); + set_nt_mirroring(BIT(m_bank, 7) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + update_banks(); + return m_bank; + } + if (offset >= 0x7fe8 && offset < 0x7ff8) + { + m_reg = hi_access_rom(offset); + update_banks(); + return m_reg; + } + + return hi_access_rom(offset); +} diff --git a/src/devices/bus/nes/bandai.c b/src/devices/bus/nes/bandai.c deleted file mode 100644 index 4aa54055969..00000000000 --- a/src/devices/bus/nes/bandai.c +++ /dev/null @@ -1,479 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Fabio Priuli -/*********************************************************************************************************** - - - NES/Famicom cartridge emulation for Bandai PCBs - - - Here we emulate the following PCBs - - * Bandai FCG [mapper 16] (older design, regs are only accessed in 0x6000-0x7fff range) - * Bandai LZ93D50 [mapper 16] (this extends FCG by solving issues when writing to 0x8000-0xffff) - * Bandai LZ93D50 + 24C01 EEPROM [mapper 159] - * Bandai LZ93D50 + 24C02 EEPROM [mapper 16] - * Bandai Famicom Jump 2 (aka LZ93D50 + SRAM) [mapper 153] - * Bandai Oeka Kids [mapper 96] - - * Bandai Datach Joint ROM System [mapper 157] is emulated in a separate source file - to implement also the subslot, but the PCB is basically a Bandai LZ93D50 + 24C02 EEPROM - pcb with added barcode reader and subslot - - * Bandai Karaoke Studio [mapper 188] is emulated in a separate source file - to implement also the subslot and the mic inputs - - - TODO: - - investigate why EEPROM does not work - - add support to the PPU for the code necessary to Oeka Kids games (also needed by UNL-DANCE2000 PCB) - - check the cause for the flickering in Famicom Jump 2 - - ***********************************************************************************************************/ - - -#include "emu.h" -#include "bandai.h" - -#include "cpu/m6502/m6502.h" - -#ifdef NES_PCB_DEBUG -#define VERBOSE 1 -#else -#define VERBOSE 0 -#endif - -#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) - - - -//------------------------------------------------- -// constructor -//------------------------------------------------- - -const device_type NES_OEKAKIDS = &device_creator; -const device_type NES_FCG = &device_creator; -const device_type NES_LZ93D50 = &device_creator; -const device_type NES_LZ93D50_24C01 = &device_creator; -const device_type NES_LZ93D50_24C02 = &device_creator; -const device_type NES_FJUMP2 = &device_creator; - - -nes_oekakids_device::nes_oekakids_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_OEKAKIDS, "NES Cart Bandai Oeka Kids PCB", tag, owner, clock, "nes_oeka", __FILE__) -{ -} - -nes_fcg_device::nes_fcg_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) - : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source) -{ -} - -nes_fcg_device::nes_fcg_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_FCG, "NES Cart Bandai FCG PCB", tag, owner, clock, "nes_fcg", __FILE__) -{ -} - -nes_lz93d50_device::nes_lz93d50_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) - : nes_fcg_device(mconfig, type, name, tag, owner, clock, shortname, source) -{ -} - -nes_lz93d50_device::nes_lz93d50_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_fcg_device(mconfig, NES_LZ93D50, "NES Cart Bandai LZ93D50 PCB", tag, owner, clock, "nes_lz93d50", __FILE__) -{ -} - -nes_lz93d50_24c01_device::nes_lz93d50_24c01_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) - : nes_lz93d50_device(mconfig, type, name, tag, owner, clock, shortname, source), - m_i2cmem(*this, "i2cmem") -{ -} - -nes_lz93d50_24c01_device::nes_lz93d50_24c01_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_lz93d50_device(mconfig, NES_LZ93D50_24C01, "NES Cart Bandai LZ93D50 + 24C01 PCB", tag, owner, clock, "nes_lz93d50_ep1", __FILE__), - m_i2cmem(*this, "i2cmem") -{ -} - -nes_lz93d50_24c02_device::nes_lz93d50_24c02_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_lz93d50_24c01_device(mconfig, NES_LZ93D50_24C02, "NES Cart Bandai LZ93D50 + 24C02 PCB", tag, owner, clock, "nes_lz93d50_ep2", __FILE__) -{ -} - -nes_fjump2_device::nes_fjump2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_lz93d50_device(mconfig, NES_FJUMP2, "NES Cart Bandai Famicom Jump II PCB", tag, owner, clock, "nes_fjump2", __FILE__) -{ -} - - - -void nes_oekakids_device::device_start() -{ - common_start(); - save_item(NAME(m_latch)); - save_item(NAME(m_reg)); -} - -void nes_oekakids_device::pcb_reset() -{ - prg32(0); - chr4_0(0, CHRRAM); - chr4_4(3, CHRRAM); - set_nt_mirroring(PPU_MIRROR_LOW); - m_latch = 0; - m_reg = 0; -} - -void nes_fcg_device::device_start() -{ - common_start(); - irq_timer = timer_alloc(TIMER_IRQ); - irq_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1)); - - save_item(NAME(m_irq_enable)); - save_item(NAME(m_irq_count)); -} - -void nes_fcg_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(0); - prg16_cdef(m_prg_chunks - 1); - chr8(0, m_chr_source); - - m_irq_enable = 0; - m_irq_count = 0; -} - -void nes_lz93d50_24c01_device::device_start() -{ - common_start(); - irq_timer = timer_alloc(TIMER_IRQ); - irq_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1)); - - save_item(NAME(m_irq_enable)); - save_item(NAME(m_irq_count)); - save_item(NAME(m_i2c_dir)); -} - -void nes_lz93d50_24c01_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(0); - prg16_cdef(m_prg_chunks - 1); - chr8(0, m_chr_source); - - m_irq_enable = 0; - m_irq_count = 0; - m_i2c_dir = 0; -} - -void nes_fjump2_device::device_start() -{ - common_start(); - irq_timer = timer_alloc(TIMER_IRQ); - irq_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1)); - - save_item(NAME(m_reg)); -} - -void nes_fjump2_device::pcb_reset() -{ - chr8(0, CHRRAM); - memset(m_reg, 0, sizeof(m_reg)); - set_prg(); - - m_irq_enable = 0; -} - - - -/*------------------------------------------------- - mapper specific handlers - -------------------------------------------------*/ - -/*------------------------------------------------- - - Bandai Oeka Kids board emulation - - Games: Oeka Kids - Anpanman no Hiragana Daisuki, Oeka - Kids - Anpanman to Oekaki Shiyou!! - - This board can swap CHR whenever a PPU address line is - changed and we still do not emulate this. - - iNES: mapper 96 - - In MESS: Preliminary Support. - - -------------------------------------------------*/ - - -WRITE8_MEMBER(nes_oekakids_device::nt_w) -{ - int page = ((offset & 0xc00) >> 10); - -#if 0 - if (!(offset & 0x1000) && (offset & 0x3ff) < 0x3c0) - { - m_latch = (offset & 0x300) >> 8; - chr4_0(m_reg | m_latch, CHRRAM); - } -#endif - - m_nt_access[page][offset & 0x3ff] = data; -} - -READ8_MEMBER(nes_oekakids_device::nt_r) -{ - int page = ((offset & 0xc00) >> 10); - -#if 0 - if (!(offset & 0x1000) && (offset & 0x3ff) < 0x3c0) - { - m_latch = (offset & 0x300) >> 8; - chr4_0(m_reg | m_latch, CHRRAM); - } -#endif - - return m_nt_access[page][offset & 0x3ff]; -} - -void nes_oekakids_device::update_chr() -{ - chr4_0(m_reg | m_latch, CHRRAM); - chr4_4(m_reg | 0x03, CHRRAM); -} - -// this only monitors accesses to $2007 while we would need to monitor accesses to $2006... -void nes_oekakids_device::ppu_latch(offs_t offset) -{ -#if 0 - if ((offset & 0x3000) == 0x2000) - { - m_latch = (offset & 0x300) >> 8; - update_chr(); - } -#endif -} - -WRITE8_MEMBER(nes_oekakids_device::write_h) -{ - LOG_MMC(("oeka kids write_h, offset: %04x, data: %02x\n", offset, data)); - - prg32(data & 0x03); - m_reg = data & 0x04; - update_chr(); -} - -/*------------------------------------------------- - - Bandai FCG / LZ93D50 boards emulation - - There are several variants: plain board with or without SRAM, - board + 24C01 EEPROM, board + 24C02 EEPROM, board + Barcode - Reader (DATACH). - We currently only emulate the base hardware. - - Games: Crayon Shin-Chan - Ora to Poi Poi, Dragon Ball Z Gaiden, - Dragon Ball Z II & III, Rokudenashi Blues, SD Gundam - Gaiden - KGM2, Dragon Ball Z, Magical Taruruuto-kun, SD Gundam - Gaiden [with EEPROM], Dragon Ball, Dragon Ball 3, Famicom Jump, - Famicom Jump II [no EEPROM], Datach Games - - At the moment, we don't support EEPROM I/O - - iNES: mappers 16, 153 (see below), 157 & 159 - - In MESS: Supported - - -------------------------------------------------*/ - -void nes_fcg_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) -{ - if (id == TIMER_IRQ) - { - if (m_irq_enable) - { - // 16bit counter, IRQ fired when the counter goes from 1 to 0 - // after firing, the counter is *not* reloaded, but next clock - // counter wraps around from 0 to 0xffff - if (!m_irq_count) - m_irq_count = 0xffff; - else - m_irq_count--; - - if (!m_irq_count) - { - m_maincpu->set_input_line(M6502_IRQ_LINE, ASSERT_LINE); - m_irq_enable = 0; - } - } - } -} - -WRITE8_MEMBER(nes_fcg_device::fcg_write) -{ - LOG_MMC(("lz93d50_write, offset: %04x, data: %02x\n", offset, data)); - - switch (offset & 0x0f) - { - case 0: case 1: case 2: case 3: - case 4: case 5: case 6: case 7: - chr1_x(offset & 0x07, data, m_chr_source); - break; - case 8: - prg16_89ab(data); - break; - case 9: - switch (data & 0x03) - { - case 0: set_nt_mirroring(PPU_MIRROR_VERT); break; - case 1: set_nt_mirroring(PPU_MIRROR_HORZ); break; - case 2: set_nt_mirroring(PPU_MIRROR_LOW); break; - case 3: set_nt_mirroring(PPU_MIRROR_HIGH); break; - } - break; - case 0x0a: - m_irq_enable = data & 0x01; - m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); - break; - case 0x0b: - m_irq_count = (m_irq_count & 0xff00) | data; - break; - case 0x0c: - m_irq_count = (m_irq_count & 0x00ff) | (data << 8); - break; - default: - logerror("lz93d50_write uncaught write, offset: %04x, data: %02x\n", offset, data); - break; - } -} - -WRITE8_MEMBER(nes_fcg_device::write_m) -{ - LOG_MMC(("lz93d50 write_m, offset: %04x, data: %02x\n", offset, data)); - - if (m_battery.empty() && m_prgram.empty()) - fcg_write(space, offset & 0x0f, data, mem_mask); - else if (!m_battery.empty()) - m_battery[offset] = data; - else - m_prgram[offset] = data; -} - -// FCG board does not access regs in 0x8000-0xffff space! -// only later design lz93d50 (and its variants do)! - -WRITE8_MEMBER(nes_lz93d50_24c01_device::write_h) -{ - LOG_MMC(("lz93d50_24c01 write_h, offset: %04x, data: %02x\n", offset, data)); - - switch (offset & 0x0f) - { - case 0x0d: - m_i2cmem->write_scl(BIT(data, 5)); - m_i2cmem->write_sda(BIT(data, 6)); - m_i2c_dir = BIT(data, 7); - break; - default: - fcg_write(space, offset & 0x0f, data, mem_mask); - break; - } -} - -READ8_MEMBER(nes_lz93d50_24c01_device::read_m) -{ - LOG_MMC(("lz93d50 EEPROM read, offset: %04x\n", offset)); - if (m_i2c_dir) - return (m_i2cmem->read_sda() & 1) << 4; - else - return 0; -} - -//------------------------------------------------- -// SERIAL I2C DEVICE -//------------------------------------------------- - -MACHINE_CONFIG_FRAGMENT( bandai_i2c_24c01 ) - MCFG_24C01_ADD("i2cmem") -MACHINE_CONFIG_END - -machine_config_constructor nes_lz93d50_24c01_device::device_mconfig_additions() const -{ - return MACHINE_CONFIG_NAME( bandai_i2c_24c01 ); -} - - -MACHINE_CONFIG_FRAGMENT( bandai_i2c_24c02 ) - MCFG_24C02_ADD("i2cmem") -MACHINE_CONFIG_END - -machine_config_constructor nes_lz93d50_24c02_device::device_mconfig_additions() const -{ - return MACHINE_CONFIG_NAME( bandai_i2c_24c02 ); -} - - -/*------------------------------------------------- - - Bandai BANDAI-JUMP2 boards emulation - - This is a variant of LZ93D50, with SRAM and no EEPROM - The board is only used by Famicom Jump II, which - has no CHR and 512K of PRG, so it is not completely - clear if the CHR regs of LZ93D50 (i.e. offset & 0xf < 8) - would switch also CHR or if they are only used to select - upper 256K of PRG - - iNES: mappers 153 - - In MESS: Supported - - -------------------------------------------------*/ - -void nes_fjump2_device::set_prg() -{ - UINT8 prg_base = 0; - - for (int i = 0; i < 4; i++) - prg_base |= (m_reg[i] << 4); - - prg16_89ab(prg_base | m_reg[4]); - prg16_cdef(prg_base | 0x0f); -} - -READ8_MEMBER(nes_fjump2_device::read_m) -{ - LOG_MMC(("fjump2 read_m, offset: %04x\n", offset)); - return m_battery[offset & (m_battery.size() - 1)]; -} - -WRITE8_MEMBER(nes_fjump2_device::write_m) -{ - LOG_MMC(("fjump2 write_m, offset: %04x, data: %02x\n", offset, data)); - m_battery[offset & (m_battery.size() - 1)] = data; -} - -WRITE8_MEMBER(nes_fjump2_device::write_h) -{ - LOG_MMC(("fjump2 write_h, offset: %04x, data: %02x\n", offset, data)); - - switch (offset & 0x0f) - { - case 0: case 1: case 2: case 3: - m_reg[offset & 0x0f] = BIT(data,0); - set_prg(); - break; - case 4: case 5: case 6: case 7: - // these have been verified to be disabled in this board - break; - case 8: - m_reg[4] = data & 0x0f; - set_prg(); - break; - default: - fcg_write(space, offset & 0x0f, data, mem_mask); - break; - } -} diff --git a/src/devices/bus/nes/bandai.cpp b/src/devices/bus/nes/bandai.cpp new file mode 100644 index 00000000000..4aa54055969 --- /dev/null +++ b/src/devices/bus/nes/bandai.cpp @@ -0,0 +1,479 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for Bandai PCBs + + + Here we emulate the following PCBs + + * Bandai FCG [mapper 16] (older design, regs are only accessed in 0x6000-0x7fff range) + * Bandai LZ93D50 [mapper 16] (this extends FCG by solving issues when writing to 0x8000-0xffff) + * Bandai LZ93D50 + 24C01 EEPROM [mapper 159] + * Bandai LZ93D50 + 24C02 EEPROM [mapper 16] + * Bandai Famicom Jump 2 (aka LZ93D50 + SRAM) [mapper 153] + * Bandai Oeka Kids [mapper 96] + + * Bandai Datach Joint ROM System [mapper 157] is emulated in a separate source file + to implement also the subslot, but the PCB is basically a Bandai LZ93D50 + 24C02 EEPROM + pcb with added barcode reader and subslot + + * Bandai Karaoke Studio [mapper 188] is emulated in a separate source file + to implement also the subslot and the mic inputs + + + TODO: + - investigate why EEPROM does not work + - add support to the PPU for the code necessary to Oeka Kids games (also needed by UNL-DANCE2000 PCB) + - check the cause for the flickering in Famicom Jump 2 + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "bandai.h" + +#include "cpu/m6502/m6502.h" + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_OEKAKIDS = &device_creator; +const device_type NES_FCG = &device_creator; +const device_type NES_LZ93D50 = &device_creator; +const device_type NES_LZ93D50_24C01 = &device_creator; +const device_type NES_LZ93D50_24C02 = &device_creator; +const device_type NES_FJUMP2 = &device_creator; + + +nes_oekakids_device::nes_oekakids_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_OEKAKIDS, "NES Cart Bandai Oeka Kids PCB", tag, owner, clock, "nes_oeka", __FILE__) +{ +} + +nes_fcg_device::nes_fcg_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +nes_fcg_device::nes_fcg_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_FCG, "NES Cart Bandai FCG PCB", tag, owner, clock, "nes_fcg", __FILE__) +{ +} + +nes_lz93d50_device::nes_lz93d50_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : nes_fcg_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +nes_lz93d50_device::nes_lz93d50_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_fcg_device(mconfig, NES_LZ93D50, "NES Cart Bandai LZ93D50 PCB", tag, owner, clock, "nes_lz93d50", __FILE__) +{ +} + +nes_lz93d50_24c01_device::nes_lz93d50_24c01_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : nes_lz93d50_device(mconfig, type, name, tag, owner, clock, shortname, source), + m_i2cmem(*this, "i2cmem") +{ +} + +nes_lz93d50_24c01_device::nes_lz93d50_24c01_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_lz93d50_device(mconfig, NES_LZ93D50_24C01, "NES Cart Bandai LZ93D50 + 24C01 PCB", tag, owner, clock, "nes_lz93d50_ep1", __FILE__), + m_i2cmem(*this, "i2cmem") +{ +} + +nes_lz93d50_24c02_device::nes_lz93d50_24c02_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_lz93d50_24c01_device(mconfig, NES_LZ93D50_24C02, "NES Cart Bandai LZ93D50 + 24C02 PCB", tag, owner, clock, "nes_lz93d50_ep2", __FILE__) +{ +} + +nes_fjump2_device::nes_fjump2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_lz93d50_device(mconfig, NES_FJUMP2, "NES Cart Bandai Famicom Jump II PCB", tag, owner, clock, "nes_fjump2", __FILE__) +{ +} + + + +void nes_oekakids_device::device_start() +{ + common_start(); + save_item(NAME(m_latch)); + save_item(NAME(m_reg)); +} + +void nes_oekakids_device::pcb_reset() +{ + prg32(0); + chr4_0(0, CHRRAM); + chr4_4(3, CHRRAM); + set_nt_mirroring(PPU_MIRROR_LOW); + m_latch = 0; + m_reg = 0; +} + +void nes_fcg_device::device_start() +{ + common_start(); + irq_timer = timer_alloc(TIMER_IRQ); + irq_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1)); + + save_item(NAME(m_irq_enable)); + save_item(NAME(m_irq_count)); +} + +void nes_fcg_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + + m_irq_enable = 0; + m_irq_count = 0; +} + +void nes_lz93d50_24c01_device::device_start() +{ + common_start(); + irq_timer = timer_alloc(TIMER_IRQ); + irq_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1)); + + save_item(NAME(m_irq_enable)); + save_item(NAME(m_irq_count)); + save_item(NAME(m_i2c_dir)); +} + +void nes_lz93d50_24c01_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + + m_irq_enable = 0; + m_irq_count = 0; + m_i2c_dir = 0; +} + +void nes_fjump2_device::device_start() +{ + common_start(); + irq_timer = timer_alloc(TIMER_IRQ); + irq_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1)); + + save_item(NAME(m_reg)); +} + +void nes_fjump2_device::pcb_reset() +{ + chr8(0, CHRRAM); + memset(m_reg, 0, sizeof(m_reg)); + set_prg(); + + m_irq_enable = 0; +} + + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + Bandai Oeka Kids board emulation + + Games: Oeka Kids - Anpanman no Hiragana Daisuki, Oeka + Kids - Anpanman to Oekaki Shiyou!! + + This board can swap CHR whenever a PPU address line is + changed and we still do not emulate this. + + iNES: mapper 96 + + In MESS: Preliminary Support. + + -------------------------------------------------*/ + + +WRITE8_MEMBER(nes_oekakids_device::nt_w) +{ + int page = ((offset & 0xc00) >> 10); + +#if 0 + if (!(offset & 0x1000) && (offset & 0x3ff) < 0x3c0) + { + m_latch = (offset & 0x300) >> 8; + chr4_0(m_reg | m_latch, CHRRAM); + } +#endif + + m_nt_access[page][offset & 0x3ff] = data; +} + +READ8_MEMBER(nes_oekakids_device::nt_r) +{ + int page = ((offset & 0xc00) >> 10); + +#if 0 + if (!(offset & 0x1000) && (offset & 0x3ff) < 0x3c0) + { + m_latch = (offset & 0x300) >> 8; + chr4_0(m_reg | m_latch, CHRRAM); + } +#endif + + return m_nt_access[page][offset & 0x3ff]; +} + +void nes_oekakids_device::update_chr() +{ + chr4_0(m_reg | m_latch, CHRRAM); + chr4_4(m_reg | 0x03, CHRRAM); +} + +// this only monitors accesses to $2007 while we would need to monitor accesses to $2006... +void nes_oekakids_device::ppu_latch(offs_t offset) +{ +#if 0 + if ((offset & 0x3000) == 0x2000) + { + m_latch = (offset & 0x300) >> 8; + update_chr(); + } +#endif +} + +WRITE8_MEMBER(nes_oekakids_device::write_h) +{ + LOG_MMC(("oeka kids write_h, offset: %04x, data: %02x\n", offset, data)); + + prg32(data & 0x03); + m_reg = data & 0x04; + update_chr(); +} + +/*------------------------------------------------- + + Bandai FCG / LZ93D50 boards emulation + + There are several variants: plain board with or without SRAM, + board + 24C01 EEPROM, board + 24C02 EEPROM, board + Barcode + Reader (DATACH). + We currently only emulate the base hardware. + + Games: Crayon Shin-Chan - Ora to Poi Poi, Dragon Ball Z Gaiden, + Dragon Ball Z II & III, Rokudenashi Blues, SD Gundam + Gaiden - KGM2, Dragon Ball Z, Magical Taruruuto-kun, SD Gundam + Gaiden [with EEPROM], Dragon Ball, Dragon Ball 3, Famicom Jump, + Famicom Jump II [no EEPROM], Datach Games + + At the moment, we don't support EEPROM I/O + + iNES: mappers 16, 153 (see below), 157 & 159 + + In MESS: Supported + + -------------------------------------------------*/ + +void nes_fcg_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (id == TIMER_IRQ) + { + if (m_irq_enable) + { + // 16bit counter, IRQ fired when the counter goes from 1 to 0 + // after firing, the counter is *not* reloaded, but next clock + // counter wraps around from 0 to 0xffff + if (!m_irq_count) + m_irq_count = 0xffff; + else + m_irq_count--; + + if (!m_irq_count) + { + m_maincpu->set_input_line(M6502_IRQ_LINE, ASSERT_LINE); + m_irq_enable = 0; + } + } + } +} + +WRITE8_MEMBER(nes_fcg_device::fcg_write) +{ + LOG_MMC(("lz93d50_write, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x0f) + { + case 0: case 1: case 2: case 3: + case 4: case 5: case 6: case 7: + chr1_x(offset & 0x07, data, m_chr_source); + break; + case 8: + prg16_89ab(data); + break; + case 9: + switch (data & 0x03) + { + case 0: set_nt_mirroring(PPU_MIRROR_VERT); break; + case 1: set_nt_mirroring(PPU_MIRROR_HORZ); break; + case 2: set_nt_mirroring(PPU_MIRROR_LOW); break; + case 3: set_nt_mirroring(PPU_MIRROR_HIGH); break; + } + break; + case 0x0a: + m_irq_enable = data & 0x01; + m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); + break; + case 0x0b: + m_irq_count = (m_irq_count & 0xff00) | data; + break; + case 0x0c: + m_irq_count = (m_irq_count & 0x00ff) | (data << 8); + break; + default: + logerror("lz93d50_write uncaught write, offset: %04x, data: %02x\n", offset, data); + break; + } +} + +WRITE8_MEMBER(nes_fcg_device::write_m) +{ + LOG_MMC(("lz93d50 write_m, offset: %04x, data: %02x\n", offset, data)); + + if (m_battery.empty() && m_prgram.empty()) + fcg_write(space, offset & 0x0f, data, mem_mask); + else if (!m_battery.empty()) + m_battery[offset] = data; + else + m_prgram[offset] = data; +} + +// FCG board does not access regs in 0x8000-0xffff space! +// only later design lz93d50 (and its variants do)! + +WRITE8_MEMBER(nes_lz93d50_24c01_device::write_h) +{ + LOG_MMC(("lz93d50_24c01 write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x0f) + { + case 0x0d: + m_i2cmem->write_scl(BIT(data, 5)); + m_i2cmem->write_sda(BIT(data, 6)); + m_i2c_dir = BIT(data, 7); + break; + default: + fcg_write(space, offset & 0x0f, data, mem_mask); + break; + } +} + +READ8_MEMBER(nes_lz93d50_24c01_device::read_m) +{ + LOG_MMC(("lz93d50 EEPROM read, offset: %04x\n", offset)); + if (m_i2c_dir) + return (m_i2cmem->read_sda() & 1) << 4; + else + return 0; +} + +//------------------------------------------------- +// SERIAL I2C DEVICE +//------------------------------------------------- + +MACHINE_CONFIG_FRAGMENT( bandai_i2c_24c01 ) + MCFG_24C01_ADD("i2cmem") +MACHINE_CONFIG_END + +machine_config_constructor nes_lz93d50_24c01_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( bandai_i2c_24c01 ); +} + + +MACHINE_CONFIG_FRAGMENT( bandai_i2c_24c02 ) + MCFG_24C02_ADD("i2cmem") +MACHINE_CONFIG_END + +machine_config_constructor nes_lz93d50_24c02_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( bandai_i2c_24c02 ); +} + + +/*------------------------------------------------- + + Bandai BANDAI-JUMP2 boards emulation + + This is a variant of LZ93D50, with SRAM and no EEPROM + The board is only used by Famicom Jump II, which + has no CHR and 512K of PRG, so it is not completely + clear if the CHR regs of LZ93D50 (i.e. offset & 0xf < 8) + would switch also CHR or if they are only used to select + upper 256K of PRG + + iNES: mappers 153 + + In MESS: Supported + + -------------------------------------------------*/ + +void nes_fjump2_device::set_prg() +{ + UINT8 prg_base = 0; + + for (int i = 0; i < 4; i++) + prg_base |= (m_reg[i] << 4); + + prg16_89ab(prg_base | m_reg[4]); + prg16_cdef(prg_base | 0x0f); +} + +READ8_MEMBER(nes_fjump2_device::read_m) +{ + LOG_MMC(("fjump2 read_m, offset: %04x\n", offset)); + return m_battery[offset & (m_battery.size() - 1)]; +} + +WRITE8_MEMBER(nes_fjump2_device::write_m) +{ + LOG_MMC(("fjump2 write_m, offset: %04x, data: %02x\n", offset, data)); + m_battery[offset & (m_battery.size() - 1)] = data; +} + +WRITE8_MEMBER(nes_fjump2_device::write_h) +{ + LOG_MMC(("fjump2 write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x0f) + { + case 0: case 1: case 2: case 3: + m_reg[offset & 0x0f] = BIT(data,0); + set_prg(); + break; + case 4: case 5: case 6: case 7: + // these have been verified to be disabled in this board + break; + case 8: + m_reg[4] = data & 0x0f; + set_prg(); + break; + default: + fcg_write(space, offset & 0x0f, data, mem_mask); + break; + } +} diff --git a/src/devices/bus/nes/benshieng.c b/src/devices/bus/nes/benshieng.c deleted file mode 100644 index b96c75e6297..00000000000 --- a/src/devices/bus/nes/benshieng.c +++ /dev/null @@ -1,105 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Fabio Priuli -/*********************************************************************************************************** - - - NES/Famicom cartridge emulation for Benshieng PCBs - - - Here we emulate the following PCBs used by Benshieng multigame carts series - - ***********************************************************************************************************/ - - -#include "emu.h" -#include "benshieng.h" - - -#ifdef NES_PCB_DEBUG -#define VERBOSE 1 -#else -#define VERBOSE 0 -#endif - -#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) - - -//------------------------------------------------- -// constructor -//------------------------------------------------- - -const device_type NES_BENSHIENG = &device_creator; - - -nes_benshieng_device::nes_benshieng_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_BENSHIENG, "NES Cart Benshieng PCB", tag, owner, clock, "nes_benshieng", __FILE__) -{ -} - - - - -void nes_benshieng_device::device_start() -{ - common_start(); - save_item(NAME(m_dipsetting)); - save_item(NAME(m_mmc_prg_bank)); - save_item(NAME(m_mmc_vrom_bank)); -} - -void nes_benshieng_device::pcb_reset() -{ - m_dipsetting = 0; - - m_mmc_prg_bank[0] = 0xff; - m_mmc_prg_bank[1] = 0xff; - m_mmc_prg_bank[2] = 0xff; - m_mmc_prg_bank[3] = 0xff; - memset(m_mmc_vrom_bank, 0, sizeof(m_mmc_vrom_bank)); - update_banks(); -} - - - -/*------------------------------------------------- - mapper specific handlers - -------------------------------------------------*/ - -/*------------------------------------------------- - - BMC-BS-5 - - Games: a few 4 in 1 multicarts - - -------------------------------------------------*/ - -void nes_benshieng_device::update_banks() -{ - prg8_89(m_mmc_prg_bank[0]); - prg8_ab(m_mmc_prg_bank[1]); - prg8_cd(m_mmc_prg_bank[2]); - prg8_ef(m_mmc_prg_bank[3]); - chr2_0(m_mmc_vrom_bank[0], CHRROM); - chr2_2(m_mmc_vrom_bank[1], CHRROM); - chr2_4(m_mmc_vrom_bank[2], CHRROM); - chr2_6(m_mmc_vrom_bank[3], CHRROM); -} - -WRITE8_MEMBER(nes_benshieng_device::write_h) -{ - UINT8 helper = (offset & 0xc00) >> 10; - LOG_MMC(("benshieng write_h, offset: %04x, data: %02x\n", offset, data)); -// m_mmc_dipsetting = ioport("CARTDIPS")->read(); - - switch (offset & 0x7000) - { - case 0x0000: - m_mmc_vrom_bank[helper] = offset & 0x1f; - break; - case 0x2000: - if (BIT(offset, m_dipsetting + 4)) // mmc_dipsetting is always zero atm, given we have no way to add cart-based DIPs - m_mmc_prg_bank[helper] = offset & 0x0f; - break; - } - update_banks(); -} diff --git a/src/devices/bus/nes/benshieng.cpp b/src/devices/bus/nes/benshieng.cpp new file mode 100644 index 00000000000..b96c75e6297 --- /dev/null +++ b/src/devices/bus/nes/benshieng.cpp @@ -0,0 +1,105 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for Benshieng PCBs + + + Here we emulate the following PCBs used by Benshieng multigame carts series + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "benshieng.h" + + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_BENSHIENG = &device_creator; + + +nes_benshieng_device::nes_benshieng_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_BENSHIENG, "NES Cart Benshieng PCB", tag, owner, clock, "nes_benshieng", __FILE__) +{ +} + + + + +void nes_benshieng_device::device_start() +{ + common_start(); + save_item(NAME(m_dipsetting)); + save_item(NAME(m_mmc_prg_bank)); + save_item(NAME(m_mmc_vrom_bank)); +} + +void nes_benshieng_device::pcb_reset() +{ + m_dipsetting = 0; + + m_mmc_prg_bank[0] = 0xff; + m_mmc_prg_bank[1] = 0xff; + m_mmc_prg_bank[2] = 0xff; + m_mmc_prg_bank[3] = 0xff; + memset(m_mmc_vrom_bank, 0, sizeof(m_mmc_vrom_bank)); + update_banks(); +} + + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + BMC-BS-5 + + Games: a few 4 in 1 multicarts + + -------------------------------------------------*/ + +void nes_benshieng_device::update_banks() +{ + prg8_89(m_mmc_prg_bank[0]); + prg8_ab(m_mmc_prg_bank[1]); + prg8_cd(m_mmc_prg_bank[2]); + prg8_ef(m_mmc_prg_bank[3]); + chr2_0(m_mmc_vrom_bank[0], CHRROM); + chr2_2(m_mmc_vrom_bank[1], CHRROM); + chr2_4(m_mmc_vrom_bank[2], CHRROM); + chr2_6(m_mmc_vrom_bank[3], CHRROM); +} + +WRITE8_MEMBER(nes_benshieng_device::write_h) +{ + UINT8 helper = (offset & 0xc00) >> 10; + LOG_MMC(("benshieng write_h, offset: %04x, data: %02x\n", offset, data)); +// m_mmc_dipsetting = ioport("CARTDIPS")->read(); + + switch (offset & 0x7000) + { + case 0x0000: + m_mmc_vrom_bank[helper] = offset & 0x1f; + break; + case 0x2000: + if (BIT(offset, m_dipsetting + 4)) // mmc_dipsetting is always zero atm, given we have no way to add cart-based DIPs + m_mmc_prg_bank[helper] = offset & 0x0f; + break; + } + update_banks(); +} diff --git a/src/devices/bus/nes/bootleg.c b/src/devices/bus/nes/bootleg.c deleted file mode 100644 index 23b13b51711..00000000000 --- a/src/devices/bus/nes/bootleg.c +++ /dev/null @@ -1,1635 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Fabio Priuli -/*********************************************************************************************************** - - - NES/Famicom cartridge emulation for Bootleg PCBs - - - Here we emulate the PCBs used in FDS2NES conversions which are common in the Taiwanese & HK markets - Notice that many of these have unusual PRG sizes (32KB+8KB, 32KB+24KB) partially mapped in the WRAM - area, or WRAM overlapping the usual PRG area, so that we often skip the usual bankswitching mechanisms - in favor of direct handling of the PRG accesses - - TODO: - - review all PCBs and fix the starting banks (which are often the main problem of not working games) - - investigate pcbs listed in FCEUmm but with apparently no dumps available (LE05 and LH53) - - ***********************************************************************************************************/ - - -#include "emu.h" -#include "bootleg.h" - -#include "cpu/m6502/m6502.h" -#include "video/ppu2c0x.h" // this has to be included so that IRQ functions can access PPU_BOTTOM_VISIBLE_SCANLINE - - -#ifdef NES_PCB_DEBUG -#define VERBOSE 1 -#else -#define VERBOSE 0 -#endif - -#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) - - -//------------------------------------------------- -// constructor -//------------------------------------------------- - -const device_type NES_AX5705 = &device_creator; -const device_type NES_SC127 = &device_creator; -const device_type NES_MARIOBABY = &device_creator; -const device_type NES_ASN = &device_creator; -const device_type NES_SMB3PIRATE = &device_creator; -const device_type NES_BTL_DNINJA = &device_creator; -const device_type NES_WHIRLWIND_2706 = &device_creator; -const device_type NES_SMB2J = &device_creator; -const device_type NES_SMB2JA = &device_creator; -const device_type NES_SMB2JB = &device_creator; -const device_type NES_09034A = &device_creator; -const device_type NES_TOBIDASE = &device_creator; -const device_type NES_LH32 = &device_creator; -const device_type NES_LH10 = &device_creator; -const device_type NES_LH53 = &device_creator; -const device_type NES_2708 = &device_creator; -const device_type NES_AC08 = &device_creator; -const device_type NES_UNL_BB = &device_creator; -const device_type NES_MMALEE = &device_creator; -const device_type NES_SHUIGUAN = &device_creator; - - -nes_ax5705_device::nes_ax5705_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_AX5705, "NES Cart AX5705 PCB", tag, owner, clock, "nes_ax5705", __FILE__) -{ -} - -nes_sc127_device::nes_sc127_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_SC127, "NES Cart SC-127 PCB", tag, owner, clock, "nes_sc127", __FILE__) -{ -} - -nes_mbaby_device::nes_mbaby_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_MARIOBABY, "NES Cart Mario Baby Bootleg PCB", tag, owner, clock, "nes_mbaby", __FILE__) -{ -} - -nes_asn_device::nes_asn_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_ASN, "NES Cart Ai Senshi Nicol Bootleg PCB", tag, owner, clock, "nes_asn", __FILE__) -{ -} - -nes_smb3p_device::nes_smb3p_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_SMB3PIRATE, "NES Cart Super Mario Bros. 3 Pirate PCB", tag, owner, clock, "nes_smb3p", __FILE__) -{ -} - -nes_btl_dn_device::nes_btl_dn_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_BTL_DNINJA, "NES Cart DragonNinja Pirate PCB", tag, owner, clock, "nes_btl_dn", __FILE__) -{ -} - -nes_whirl2706_device::nes_whirl2706_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_WHIRLWIND_2706, "NES Cart Whirlwind 2706 PCB", tag, owner, clock, "nes_whirl2706", __FILE__) -{ -} - -nes_smb2j_device::nes_smb2j_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_SMB2J, "NES Cart Super Mario Bros. 2 Jpn PCB", tag, owner, clock, "nes_smb2j", __FILE__) -{ -} - -nes_smb2ja_device::nes_smb2ja_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_SMB2JA, "NES Cart Super Mario Bros. 2 Jpn (Alt) PCB", tag, owner, clock, "nes_smb2ja", __FILE__) -{ -} - -nes_smb2jb_device::nes_smb2jb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_SMB2JB, "NES Cart Super Mario Bros. 2 Jpn (Alt 2) PCB", tag, owner, clock, "nes_smb2jb", __FILE__) -{ -} - -nes_09034a_device::nes_09034a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_09034A, "NES Cart 09-034A PCB", tag, owner, clock, "nes_09034a", __FILE__) -{ -} - -nes_tobidase_device::nes_tobidase_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_TOBIDASE, "NES Cart Tobidase Daisakusen Pirate PCB", tag, owner, clock, "nes_tobidase", __FILE__) -{ -} - -nes_lh32_device::nes_lh32_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_LH32, "NES Cart LH-32 Pirate PCB", tag, owner, clock, "nes_lh32", __FILE__) -{ -} - -nes_lh10_device::nes_lh10_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_LH10, "NES Cart LH-10 Pirate PCB", tag, owner, clock, "nes_lh10", __FILE__) -{ -} - -nes_lh53_device::nes_lh53_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_LH53, "NES Cart LH-53 Pirate PCB", tag, owner, clock, "nes_lh53", __FILE__) -{ -} - -nes_2708_device::nes_2708_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_2708, "NES Cart BTL-2708 Pirate PCB", tag, owner, clock, "nes_2708", __FILE__) -{ -} - -nes_ac08_device::nes_ac08_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_AC08, "NES Cart AC08 Pirate PCB", tag, owner, clock, "nes_ac08", __FILE__) -{ -} - -nes_unl_bb_device::nes_unl_bb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_UNL_BB, "NES Cart FDS+CHR Pirate PCB", tag, owner, clock, "nes_unl_bb", __FILE__) -{ -} - -nes_mmalee_device::nes_mmalee_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_MMALEE, "NES Cart Super Mario Bros. Malee 2 Pirate PCB", tag, owner, clock, "nes_mmalee", __FILE__) -{ -} - -nes_shuiguan_device::nes_shuiguan_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_SHUIGUAN, "NES Cart Shui Guan Pipe Pirate PCB", tag, owner, clock, "nes_shuiguan", __FILE__) -{ -} - - - - -void nes_ax5705_device::device_start() -{ - common_start(); - save_item(NAME(m_mmc_prg_bank)); - save_item(NAME(m_mmc_vrom_bank)); -} - -void nes_ax5705_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - chr8(0, m_chr_source); - - m_mmc_prg_bank[0] = 0; - m_mmc_prg_bank[1] = 1; - prg8_89(m_mmc_prg_bank[0]); - prg8_ab(m_mmc_prg_bank[1]); - prg8_cd(0xfe); - prg8_ef(0xff); - - memset(m_mmc_vrom_bank, 0, sizeof(m_mmc_vrom_bank)); -} - -void nes_sc127_device::device_start() -{ - common_start(); - save_item(NAME(m_irq_enable)); - save_item(NAME(m_irq_count)); -} - -void nes_sc127_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0xff); - chr8(0, m_chr_source); - - m_irq_enable = 0; - m_irq_count = 0; -} - -void nes_mbaby_device::device_start() -{ - common_start(); - irq_timer = timer_alloc(TIMER_IRQ); - irq_timer->reset(); - timer_freq = machine().device("maincpu")->cycles_to_attotime(24576); - - save_item(NAME(m_irq_enable)); - save_item(NAME(m_latch)); -} - -void nes_mbaby_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32((m_prg_chunks - 1) >> 1); - chr8(0, m_chr_source); - - m_irq_enable = 0; - m_latch = 0; -} - -void nes_asn_device::device_start() -{ - common_start(); - save_item(NAME(m_latch)); -} - -void nes_asn_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32((m_prg_chunks - 1) >> 1); - chr8(0, m_chr_source); - - m_latch = 0; -} - -void nes_smb3p_device::device_start() -{ - common_start(); - irq_timer = timer_alloc(TIMER_IRQ); - irq_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1)); - - save_item(NAME(m_irq_enable)); - save_item(NAME(m_irq_count)); -} - -void nes_smb3p_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg8_89((m_prg_chunks << 1) - 1); - prg8_ab(0); - prg8_cd(0); - prg8_ef((m_prg_chunks << 1) - 1); - chr8(0, m_chr_source); - - m_irq_enable = 0; - m_irq_count = 0; -} - -void nes_btl_dn_device::device_start() -{ - common_start(); - save_item(NAME(m_irq_count)); -} - -void nes_btl_dn_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(0); - prg16_cdef(m_prg_chunks - 1); - chr8(0, m_chr_source); - - m_irq_count = 0; -} - -void nes_whirl2706_device::device_start() -{ - common_start(); - save_item(NAME(m_latch)); -} - -void nes_whirl2706_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0xff); - chr8(0, m_chr_source); - - m_latch = 0; -} - -void nes_smb2j_device::device_start() -{ - common_start(); - irq_timer = timer_alloc(TIMER_IRQ); - irq_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1)); - - save_item(NAME(m_irq_enable)); - save_item(NAME(m_irq_count)); -} - -void nes_smb2j_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - chr8(0, m_chr_source); - prg8_89(1); - prg8_ab(0); - prg8_cd(0); - prg8_ef(9); - - m_irq_enable = 0; - m_irq_count = 0; -} - -void nes_smb2ja_device::device_start() -{ - common_start(); - irq_timer = timer_alloc(TIMER_IRQ); - irq_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1)); - - save_item(NAME(m_irq_enable)); - save_item(NAME(m_irq_count)); -} - -void nes_smb2ja_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg8_89(0xfc); - prg8_ab(0xfd); - prg8_cd(0xfe); - prg8_ef(0xff); - chr8(0, m_chr_source); - - m_irq_enable = 0; - m_irq_count = 0; -} - -void nes_smb2jb_device::device_start() -{ - common_start(); - irq_timer = timer_alloc(TIMER_IRQ); - irq_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1)); - - save_item(NAME(m_irq_enable)); - save_item(NAME(m_irq_count)); -} - -void nes_smb2jb_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg8_89(0x08); - prg8_ab(0x09); - prg8_cd(0); - prg8_ef(0x0b); - chr8(0, m_chr_source); - - m_irq_enable = 0; - m_irq_count = 0; -} - -void nes_09034a_device::device_start() -{ - common_start(); - save_item(NAME(m_reg)); -} - -void nes_09034a_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0); - chr8(0, m_chr_source); - m_reg = 0; -} - -void nes_tobidase_device::device_start() -{ - common_start(); - save_item(NAME(m_latch)); -} - -void nes_tobidase_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(2); - chr8(0, m_chr_source); - - m_latch = 0; -} - -void nes_lh32_device::device_start() -{ - common_start(); - save_item(NAME(m_latch)); -} - -void nes_lh32_device::pcb_reset() -{ - chr8(0, CHRRAM); - - prg32((m_prg_chunks - 1) >> 1); - // 0xc000-0xdfff reads/writes WRAM - m_latch = 0xf; -} - -void nes_lh10_device::device_start() -{ - common_start(); - save_item(NAME(m_latch)); - save_item(NAME(m_reg)); -} - -void nes_lh10_device::pcb_reset() -{ - chr8(0, CHRRAM); - - prg8_89(0); - prg8_ab(0); - // 0xc000-0xdfff reads/writes WRAM - prg8_ef(0xff); - memset(m_reg, 0, sizeof(m_reg)); - m_latch = 0; -} - -void nes_lh53_device::device_start() -{ - common_start(); - irq_timer = timer_alloc(TIMER_IRQ); - irq_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1)); - - save_item(NAME(m_irq_enable)); - save_item(NAME(m_irq_count)); - save_item(NAME(m_reg)); -} - -void nes_lh53_device::pcb_reset() -{ - chr8(0, CHRRAM); - - prg8_89(0xc); - prg8_ab(0xd); // last 2K are overlayed by WRAM - prg8_cd(0xe); // first 6K are overlayed by WRAM - prg8_ef(0xf); - m_reg = 0; - m_irq_count = 0; - m_irq_enable = 0; -} - -void nes_2708_device::device_start() -{ - common_start(); - save_item(NAME(m_reg)); -} - -void nes_2708_device::pcb_reset() -{ - chr8(0, CHRRAM); - - prg32(7); - // the upper PRG banks never change, but there are 8K of WRAM overlayed to the ROM area based on reg1 - m_reg[0] = 0; - m_reg[1] = 0; -} - -void nes_ac08_device::device_start() -{ - common_start(); - save_item(NAME(m_latch)); -} - -void nes_ac08_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - chr8(0, m_chr_source); - prg32(0xff); - m_latch = 0xff; -} - -void nes_unl_bb_device::device_start() -{ - common_start(); - save_item(NAME(m_reg)); -} - -void nes_unl_bb_device::pcb_reset() -{ - chr8(0, CHRROM); - prg32(0xff); - // the upper PRG banks never change, but there are 8K of WRAM overlayed to the ROM area based on reg1 - m_reg[0] = 0xff; - m_reg[1] = 0; -} - -void nes_mmalee_device::device_start() -{ - common_start(); -} - -void nes_mmalee_device::pcb_reset() -{ - chr8(0, CHRROM); - prg32(0); -} - -void nes_shuiguan_device::device_start() -{ - common_start(); - irq_timer = timer_alloc(TIMER_IRQ); - // always running and checking for IRQ every 114 cycles? or resetting every frame? - irq_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(114)); - - save_item(NAME(m_irq_enable)); - save_item(NAME(m_irq_count)); - save_item(NAME(m_mmc_vrom_bank)); -} - -void nes_shuiguan_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32((m_prg_chunks << 1) - 1); - chr8(0, m_chr_source); - - m_irq_enable = 0; - m_irq_count = 0; - memset(m_mmc_vrom_bank, 0, sizeof(m_mmc_vrom_bank)); -} - - - -/*------------------------------------------------- - mapper specific handlers - -------------------------------------------------*/ - -/*------------------------------------------------- - - Board UNL-AX5705 - - Games: Super Mario Bros. Pocker Mali (Crayon Shin-chan pirate hack) - - In MESS: Supported - - -------------------------------------------------*/ - -void nes_ax5705_device::set_prg() -{ - prg8_89(m_mmc_prg_bank[0]); - prg8_ab(m_mmc_prg_bank[1]); -} - -WRITE8_MEMBER(nes_ax5705_device::write_h) -{ - UINT8 bank; - LOG_MMC(("ax5705 write_h, offset: %04x, data: %02x\n", offset, data)); - - switch (offset & 0x700f) - { - case 0x0000: - m_mmc_prg_bank[0] = (data & 0x05) | ((data & 0x08) >> 2) | ((data & 0x02) << 2); - set_prg(); - break; - case 0x0008: - set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); - break; - case 0x2000: - m_mmc_prg_bank[1] = (data & 0x05) | ((data & 0x08) >> 2) | ((data & 0x02) << 2); - set_prg(); - break; - /* CHR banks 0, 1, 4, 5 */ - case 0x2008: - case 0x200a: - case 0x4008: - case 0x400a: - bank = ((offset & 0x4000) ? 4 : 0) + ((offset & 0x0002) ? 1 : 0); - m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0xf0) | (data & 0x0f); - chr1_x(bank, m_mmc_vrom_bank[bank], CHRROM); - break; - case 0x2009: - case 0x200b: - case 0x4009: - case 0x400b: - bank = ((offset & 0x4000) ? 4 : 0) + ((offset & 0x0002) ? 1 : 0); - m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0x0f) | ((data & 0x04) << 3) | ((data & 0x02) << 5) | ((data & 0x09) << 4); - chr1_x(bank, m_mmc_vrom_bank[bank], CHRROM); - break; - /* CHR banks 2, 3, 6, 7 */ - case 0x4000: - case 0x4002: - case 0x6000: - case 0x6002: - bank = 2 + ((offset & 0x2000) ? 4 : 0) + ((offset & 0x0002) ? 1 : 0); - m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0xf0) | (data & 0x0f); - chr1_x(bank, m_mmc_vrom_bank[bank], CHRROM); - break; - case 0x4001: - case 0x4003: - case 0x6001: - case 0x6003: - bank = 2 + ((offset & 0x2000) ? 4 : 0) + ((offset & 0x0002) ? 1 : 0); - m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0x0f) | ((data & 0x04) << 3) | ((data & 0x02) << 5) | ((data & 0x09) << 4); - chr1_x(bank, m_mmc_vrom_bank[bank], CHRROM); - break; - } -} - -/*------------------------------------------------- - - SC-127 Board - - Games: Wario World II (Kirby Hack) - - iNES: mapper 35 - - In MESS: Supported - - -------------------------------------------------*/ - -void nes_sc127_device::hblank_irq(int scanline, int vblank, int blanked) -{ - if (scanline < PPU_BOTTOM_VISIBLE_SCANLINE && m_irq_enable) - { - m_irq_count--; - - if (!blanked && (m_irq_count == 0)) - { - LOG_MMC(("irq fired, scanline: %d (MAME %d, beam pos: %d)\n", scanline, - machine().first_screen()->vpos(), machine().first_screen()->hpos())); - m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE); - m_irq_enable = 0; - } - } -} - -WRITE8_MEMBER(nes_sc127_device::write_h) -{ - LOG_MMC(("sc127 write_h, offset: %04x, data: %02x\n", offset, data)); - - switch (offset) - { - case 0x0000: - prg8_89(data); - break; - case 0x0001: - prg8_ab(data); - break; - case 0x0002: -// m_mmc_prg_bank[offset & 0x02] = data; - prg8_cd(data); - break; - case 0x1000: - case 0x1001: - case 0x1002: - case 0x1003: - case 0x1004: - case 0x1005: - case 0x1006: - case 0x1007: -// m_mmc_vrom_bank[offset & 0x07] = data; - chr1_x(offset & 0x07, data, CHRROM); - break; - case 0x4002: - m_irq_enable = 0; - break; - case 0x4003: - m_irq_enable = 1; - break; - case 0x4005: - m_irq_count = data; - break; - case 0x5001: - set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); - break; - } -} - -/*------------------------------------------------- - - BTL-MARIOBABY - - Games: Mario Baby, Ai Senshi Nicol - - iNES: mapper 42 - - In MESS: Supported. - - -------------------------------------------------*/ - -void nes_mbaby_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) -{ - if (id == TIMER_IRQ) - { - m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE); - irq_timer->adjust(attotime::never); - } -} - -WRITE8_MEMBER(nes_mbaby_device::write_h) -{ - LOG_MMC(("Mario Baby write_h, offset: %04x, data: %02x\n", offset, data)); - - if (offset >= 0x7000) - { - switch (offset & 0x03) - { - case 0x00: - m_latch = data; - break; - case 0x01: - set_nt_mirroring(BIT(data, 3) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); - break; - case 0x02: - /* Check if IRQ is being enabled */ - if (!m_irq_enable && (data & 0x02)) - { - m_irq_enable = 1; - irq_timer->adjust(timer_freq); - } - if (!(data & 0x02)) - { - m_irq_enable = 0; - irq_timer->adjust(attotime::never); - } - break; - } - } -} - -READ8_MEMBER(nes_mbaby_device::read_m) -{ - LOG_MMC(("Mario Baby read_m, offset: %04x\n", offset)); - return m_prg[(m_latch * 0x2000) + (offset & 0x1fff)]; -} - -/*------------------------------------------------- - - BTL-AISENSHINICOL - - Games: Ai Senshi Nicol - - iNES: mapper 42 with no IRQ and no NT, but CHR switch - - In MESS: Partially Supported. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_asn_device::write_h) -{ - LOG_MMC(("Ai Senshi Nicol write_h, offset: %04x, data: %02x\n", offset, data)); - - if (offset == 0x0000) - chr8(data, CHRROM); - - if (offset == 0x7000) - m_latch = data; -} - -READ8_MEMBER(nes_asn_device::read_m) -{ - LOG_MMC(("Ai Senshi Nicol read_m, offset: %04x\n", offset)); - return m_prg[((m_latch * 0x2000) + (offset & 0x1fff)) & (m_prg_size - 1)]; -} - - -/*------------------------------------------------- - - BTL-SMB3 - - Games: Super Mario Bros. 3 Pirate - - iNES: mapper 106 - - In MESS: Supported. - - -------------------------------------------------*/ - -void nes_smb3p_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) -{ - if (id == TIMER_IRQ) - { - if (m_irq_enable) - { - if (m_irq_count == 0xffff) - { - m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE); - m_irq_enable = 0; - } - else - m_irq_count++; - } - } -} - -WRITE8_MEMBER(nes_smb3p_device::write_h) -{ - LOG_MMC(("btl_smb3_w, offset: %04x, data: %02x\n", offset, data)); - switch (offset & 0x0f) - { - case 0x00: - case 0x02: - chr1_x(offset & 0x07, data & 0xfe, CHRROM); - break; - case 0x01: - case 0x03: - chr1_x(offset & 0x07, data | 0x01, CHRROM); - break; - case 0x04: case 0x05: - case 0x06: case 0x07: - chr1_x(offset & 0x07, data, CHRROM); - break; - case 0x08: - prg8_89(data | 0x10); - break; - case 0x09: - prg8_ab(data); - break; - case 0x0a: - prg8_cd(data); - break; - case 0x0b: - prg8_ef(data | 0x10); - break; - case 0x0c: - set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); - break; - case 0x0d: - m_irq_count = 0; - m_irq_enable = 0; - break; - case 0x0e: - m_irq_count = (m_irq_count & 0xff00) | data; - break; - case 0x0f: - m_irq_count = (m_irq_count & 0x00ff) | (data << 8); - m_irq_enable = 1; - break; - } -} - -/*------------------------------------------------- - - BTL-DRAGONNINJA - - Games: Dragon Ninja (Bootleg), Super Mario Bros. 8 - - iNES: mapper 222 - - In MESS: Unsupported. - - -------------------------------------------------*/ - -/* Scanline based IRQ ? */ -void nes_btl_dn_device::hblank_irq(int scanline, int vblank, int blanked ) -{ - if (!m_irq_count || ++m_irq_count < 240) - return; - - m_irq_count = 0; - m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE); -} - -WRITE8_MEMBER(nes_btl_dn_device::write_h) -{ - UINT8 bank; - LOG_MMC(("btl_dn write_h, offset: %04x, data: %02x\n", offset, data)); - - switch (offset & 0x7003) - { - case 0x0000: - prg8_89(data); - break; - case 0x1000: - set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); - break; - case 0x2000: - prg8_ab(data); - break; - case 0x3000: - case 0x3002: - case 0x4000: - case 0x4002: - case 0x5000: - case 0x5002: - case 0x6000: - case 0x6002: - bank = ((offset & 0x7000) - 0x3000) / 0x0800 + ((offset & 0x0002) >> 1); - chr1_x(bank, data, CHRROM); - break; - case 0x7000: - m_irq_count = data; - break; - } -} - -/*------------------------------------------------- - - BOOTLEG FC VERSIONS OF FDS GAMES - - -------------------------------------------------*/ - -/*------------------------------------------------- - - WHIRLWIND-2706 - - Games: Meikyuu Jiin Dababa (FDS conversion) and a few - others - - This PCB maps PRG in 0x6000-0x7fff - - iNES: mapper 108 - - In MESS: Supported. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_whirl2706_device::write_h) -{ - LOG_MMC(("whirl2706 write_h, offset: %04x, data: %02x\n", offset, data)); - m_latch = data; -} - -READ8_MEMBER(nes_whirl2706_device::read_m) -{ - LOG_MMC(("whirl2706 read_m, offset: %04x\n", offset)); - return m_prg[(m_latch * 0x2000 + (offset & 0x1fff)) & (m_prg_size - 1)]; -} - -/*------------------------------------------------- - - Bootleg Board SMB2J - - Games: Super Mario Bros. 2 Pirate (LF36) - - iNES: mapper 43 - - In MESS: Supported. - - -------------------------------------------------*/ - -void nes_smb2j_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) -{ - if (id == TIMER_IRQ) - { - if (m_irq_enable) - { - if (m_irq_count == 0xfff) - { - m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE); - m_irq_enable = 0; - m_irq_count = 0; - } - else - m_irq_count++; - } - } -} - -WRITE8_MEMBER(nes_smb2j_device::write_l) -{ - LOG_MMC(("smb2j write_l, offset: %04x, data: %02x\n", offset, data)); - offset += 0x100; - - if (offset == 0x122) // $4122 - m_irq_enable = data & 3; // maybe also m_irq_count = 0?!? -} - -WRITE8_MEMBER(nes_smb2j_device::write_h) -{ - LOG_MMC(("smb2j write_h, offset: %04x, data: %02x\n", offset, data)); - - if (offset == 0x122) // $8122 too? - m_irq_enable = data & 3; -} - -WRITE8_MEMBER(nes_smb2j_device::write_ex) -{ - LOG_MMC(("smb2j write_ex, offset: %04x, data: %02x\n", offset, data)); - - if (offset == 2) - { - int temp = 0; - - // According to hardware tests - if (data & 1) - temp = 3; - else - temp = 4 + ((data & 7) >> 1); - - prg8_cd(temp); - } -} - -READ8_MEMBER(nes_smb2j_device::read_l) -{ - LOG_MMC(("smb2j read_l, offset: %04x\n", offset)); - offset += 0x100; - - if (offset >= 0x1000) - return m_prg[0x10000 + (offset & 0x0fff)]; - - return m_open_bus; // open bus -} - -READ8_MEMBER(nes_smb2j_device::read_m) -{ - LOG_MMC(("smb2j read_m, offset: %04x\n", offset)); - return m_prg[0x4000 + offset]; -} - -/*------------------------------------------------- - - BTL-SMB2A - - Games: Super Mario Bros. 2 Pirate (Jpn version of SMB2) - - iNES: mapper 40 - - In MESS: Supported. - - -------------------------------------------------*/ - -void nes_smb2ja_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) -{ - if (id == TIMER_IRQ) - { - if (m_irq_enable) - { - if (m_irq_count == 0xfff) - { - m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE); - m_irq_enable = 0; - m_irq_count = 0; - } - else - m_irq_count++; - } - } -} - -WRITE8_MEMBER(nes_smb2ja_device::write_h) -{ - LOG_MMC(("smb2ja write_h, offset: %04x, data: %02x\n", offset, data)); - - switch (offset & 0x6000) - { - case 0x0000: - m_irq_enable = 0; - m_irq_count = 0; - break; - case 0x2000: - m_irq_enable = 1; - break; - case 0x6000: - prg8_cd(data); - break; - } -} - -READ8_MEMBER(nes_smb2ja_device::read_m) -{ - LOG_MMC(("smb2ja read_m, offset: %04x\n", offset)); - return m_prg[(0xfe * 0x2000 + (offset & 0x1fff)) & (m_prg_size - 1)]; -} - -/*------------------------------------------------- - - BTL-SMB2B - - Games: Super Mario Bros. 2 Pirate (Jpn version of SMB2) - - This was marked as Alt. Levels. is it true? - - iNES: mapper 50 - - In MESS: Partially Supported. - - -------------------------------------------------*/ - -void nes_smb2jb_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) -{ - if (id == TIMER_IRQ) - { - if (m_irq_enable) - { - if (m_irq_count == 0xfff) - { - m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE); - m_irq_enable = 0; - m_irq_count = 0; - } - else - m_irq_count++; - } - } -} - -WRITE8_MEMBER(nes_smb2jb_device::write_l) -{ - UINT8 prg; - LOG_MMC(("smb2jb write_l, offset: %04x, data: %02x\n", offset, data)); - offset += 0x100; - - switch (offset & 0x1e0) - { - case 0x020: - case 0x0a0: - prg = (data & 0x08) | ((data & 0x06) >> 1) | ((data & 0x01) << 2); - prg8_cd(prg); - break; - case 0x120: - case 0x1a0: - m_irq_enable = data & 0x01; - break; - } -} - -READ8_MEMBER(nes_smb2jb_device::read_m) -{ - LOG_MMC(("smb2jb read_m, offset: %04x\n", offset)); - return m_prg[((0x0f * 0x2000) + (offset & 0x1fff)) & (m_prg_size - 1)]; -} - -/* This goes to 0x4020-0x403f & 0x40a0-0x40bf */ -WRITE8_MEMBER(nes_smb2jb_device::write_ex) -{ - UINT8 prg; - LOG_MMC(("smb2jb write_ex, offset: %04x, data: %02x\n", offset, data)); - - if ((offset < 0x20) || (offset >= 0x80 && offset < 0xa0)) - { - prg = (data & 0x08) | ((data & 0x06) >> 1) | ((data & 0x01) << 2); - prg8_cd(prg); - } -} - -/*------------------------------------------------- - - (UNL-)09-034A - - Games: Zanac FDS conversion with two PRG chips and - no CHRROM and Volleyball FDS conversion with two PRG - chips and CHRROM. - Originally dumps were marked as UNL-SMB2J pcb - - iNES: - - In MESS: Partially Supported. Need to emulate IRQ - (needed by smb2 conversion?) - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_09034a_device::write_ex) -{ - LOG_MMC(("09-034a write_ex, offset: %04x, data: %02x\n", offset, data)); - - if (offset == 7) // $4027 - m_reg = data & 1; -} - -READ8_MEMBER(nes_09034a_device::read_m) -{ - LOG_MMC(("09-034a read_m, offset: %04x\n", offset)); - // in 0x6000-0x7fff is mapped the 2nd PRG chip which starts after 32K (hence the +4) - return m_prg[((m_reg + 4) * 0x2000) + offset]; -} - -/*------------------------------------------------- - - Bootleg Board used for FDS conversion - - Games: Tobidase Daisakusen (FDS conversion) - - This PCB maps PRG in 0x6000-0x7fff - - iNES: mapper 120 - - In MESS: Partially Supported. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_tobidase_device::write_l) -{ - LOG_MMC(("tobidase write_h, offset: %04x, data: %02x\n", offset, data)); - offset += 0x4100; - - if ((offset & 0x63c0) == 0x41c0) - m_latch = data & 0x0f; -} - -READ8_MEMBER(nes_tobidase_device::read_m) -{ - LOG_MMC(("tobidase read_m, offset: %04x\n", offset)); - if (m_latch >= 0x0c) - m_latch -= 4; - return m_prg[(m_latch * 0x2000) + (offset & 0x1fff)]; -} - -/*------------------------------------------------- - - UNL-LH32 - - Games: Monty no Doki Doki Daidassou (FDS conversion) - - This PCB maps WRAM in 0xc000-0xdfff and PRG in 0x6000-0x7fff - - iNES: - - In MESS: Supported. - --------------------------------------------------*/ - -READ8_MEMBER(nes_lh32_device::read_m) -{ - LOG_MMC(("lh32 read_m, offset: %04x\n", offset)); - return m_prg[(m_latch * 0x2000) + (offset & 0x1fff)]; -} - -READ8_MEMBER(nes_lh32_device::read_h) -{ - LOG_MMC(("lh32 read_h, offset: %04x\n", offset)); - - if (offset >= 0x4000 && offset < 0x6000) - return m_prgram[offset & 0x1fff]; - - return hi_access_rom(offset); -} - -WRITE8_MEMBER(nes_lh32_device::write_m) -{ - LOG_MMC(("lh32 write_m, offset: %04x, data: %02x\n", offset, data)); - - if (offset == 0) // 0x6000 only? - { -// printf("write %x\n", data); - m_latch = data & 0xf; - } -} - -WRITE8_MEMBER(nes_lh32_device::write_h) -{ - LOG_MMC(("lh32 write_h, offset: %04x, data: %02x\n", offset, data)); - - if (offset >= 0x4000 && offset < 0x6000) - m_prgram[offset & 0x1fff] = data; -} - -/*------------------------------------------------- - - UNL-LH10 - - Games: Fuuun Shaolin Kyo (FDS conversion) - - This PCB maps WRAM in 0xc000-0xdfff and PRG in 0x6000-0x7fff - This is very similar to KS7037 (not sure which conversion - uses that one) - - iNES: - - In MESS: Supported. - - -------------------------------------------------*/ - -void nes_lh10_device::update_prg() -{ - prg8_89(m_reg[6]); - prg8_ab(m_reg[7]); -} - -READ8_MEMBER(nes_lh10_device::read_m) -{ - LOG_MMC(("lh10 read_m, offset: %04x\n", offset)); - return m_prg[(0x0e * 0x2000) + (offset & 0x1fff)]; -} - -READ8_MEMBER(nes_lh10_device::read_h) -{ - LOG_MMC(("lh10 read_h, offset: %04x\n", offset)); - - if (offset >= 0x4000 && offset < 0x6000) - return m_prgram[offset & 0x1fff]; - - return hi_access_rom(offset); -} - -WRITE8_MEMBER(nes_lh10_device::write_h) -{ - LOG_MMC(("lh10 write_h, offset: %04x, data: %02x\n", offset, data)); - - if (offset >= 0x4000 && offset < 0x6000) - m_prgram[offset & 0x1fff] = data; - - else - { - switch (offset & 0x6001) - { - case 0x0000: - m_latch = data & 7; - break; - case 0x0001: - m_reg[m_latch] = data; - update_prg(); - break; - } - } -} - -/*------------------------------------------------- - - UNL-LH53 - - Games: Nazo no Murasamejou (FDS conversion) - - This PCB maps WRAM (w/battery) in 0xb800-0xd7ff and - PRG in 0x6000-0x7fff - - iNES: - - In MESS: Preliminar Support only. - - -------------------------------------------------*/ - -void nes_lh53_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) -{ - if (id == TIMER_IRQ) - { - if (m_irq_enable) - { - m_irq_count++; - if (m_irq_count > 7560)//value from FCEUMM... - { - m_irq_count = 0; - m_maincpu->set_input_line(M6502_IRQ_LINE, ASSERT_LINE); - } - } - } -} - -READ8_MEMBER(nes_lh53_device::read_m) -{ - LOG_MMC(("lh53 read_m, offset: %04x\n", offset)); - return m_prg[(m_reg * 0x2000) + (offset & 0x1fff)]; -} - -READ8_MEMBER(nes_lh53_device::read_h) -{ - LOG_MMC(("lh53 read_h, offset: %04x\n", offset)); - - if (offset >= 0x3800 && offset < 0x5800) - return m_battery[offset & 0x1fff]; - - return hi_access_rom(offset); -} - -WRITE8_MEMBER(nes_lh53_device::write_h) -{ - LOG_MMC(("lh53 write_h, offset: %04x, data: %02x\n", offset, data)); - - if (offset >= 0x3800 && offset < 0x5800) - m_battery[offset & 0x1fff] = data; - - else - { - switch (offset & 0x7000) - { - case 0x6000: - m_irq_enable = BIT(data, 1); - m_irq_count = 0; - if (!m_irq_enable) - m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); - break; - case 0x7000: - m_reg = data & 0x0f; - break; - } - } -} - -/*------------------------------------------------- - - BTL-2708 - - Games: Doki Doki Panic (FDS conversion) - - iNES: mapper 103? - - This board has a very unique setup, with 8KB of WRAM - in 0x6000-0x7fff and other 8KB of WRAM in 0xb800-0xd7ff - which can be switched in 2KB chunks (we attempt to - emulate this by intercepting reads in that area before - they get to the PRG banks...) - - In MESS: Supported. - - -------------------------------------------------*/ - -READ8_MEMBER(nes_2708_device::read_m) -{ - LOG_MMC(("btl-2708 read_m, offset: %04x\n", offset)); - if (!m_reg[1]) - return m_prgram[offset]; // lower 8K of WRAM - else - return m_prg[(m_reg[0] * 0x2000) + (offset & 0x1fff)]; -} - -WRITE8_MEMBER(nes_2708_device::write_m) -{ - LOG_MMC(("btl-2708 write_m, offset: %04x, data: %02x\n", offset, data)); -// if (!m_reg[1]) - m_prgram[offset] = data; // lower 8K of WRAM -} - -READ8_MEMBER(nes_2708_device::read_h) -{ - LOG_MMC(("btl-2708 read_h, offset: %04x\n", offset)); - - if (offset >= 0x3800 && offset < 0x5800 && !m_reg[1]) - return m_prgram[0x2000 + ((offset - 0x3800) & 0x1fff)]; // higher 8K of WRAM - - return hi_access_rom(offset); -} - -WRITE8_MEMBER(nes_2708_device::write_h) -{ - LOG_MMC(("btl-2708 write_h, offset: %04x, data: %02x\n", offset, data)); - - if (offset >= 0x3800 && offset < 0x5800/* && !m_reg[1]*/) - m_prgram[0x2000 + ((offset - 0x3800) & 0x1fff)] = data; // higher 8K of WRAM - - switch (offset & 0x7000) - { - case 0x0000: - m_reg[0] = data & 0x0f; // PRG bank in 0x6000-0x7fff - break; - case 0x6000: - set_nt_mirroring(BIT(data, 3) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); - break; - case 0x7000: - m_reg[1] = BIT(data, 4); // bit4 enables the two WRAM banks - break; - } -} - -/*------------------------------------------------- - - UNL-AC08 - - Games: Green Beret (FDS conversions) - - iNES: - - This board has two PRG chips. The first (128K) is - connected to 0x6000-0x7fff and switches among the - 16x8K banks; the second (32K) is fixed in 0x8000-0xffff - - In MESS: Supported. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_ac08_device::write_ex) -{ - LOG_MMC(("AC-08 write_ex, offset: %04x, data: %02x\n", offset, data)); - if (offset == 5) // $4025 - set_nt_mirroring(!BIT(data, 3) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ); -} - -READ8_MEMBER(nes_ac08_device::read_m) -{ - LOG_MMC(("AC-08 read_m, offset: %04x\n", offset)); - return m_prg[(m_latch * 0x2000) + (offset & 0x1fff)]; -} - -WRITE8_MEMBER(nes_ac08_device::write_h) -{ - LOG_MMC(("AC-08 write_h, offset: %04x, data: %02x\n", offset, data)); - - if (offset == 1) - m_latch = (data >> 1) & 0x0f; - else - m_latch = data & 0x0f; // apparently there also is a Castlevania FDS conversion using same board with different banking lines -} - -/*------------------------------------------------- - - UNL-BB - - Games: Bubble Bobble and other FDS conversions with CHRROM! - - iNES: - - - In MESS: Supported. - - -------------------------------------------------*/ - -READ8_MEMBER(nes_unl_bb_device::read_m) -{ - LOG_MMC(("unl-bb read_m, offset: %04x\n", offset)); - return m_prg[(((m_reg[0] & 3 & m_prg_mask) * 0x2000) + (offset & 0x1fff))]; -} - -WRITE8_MEMBER(nes_unl_bb_device::write_h) -{ - LOG_MMC(("unl-bb write_h, offset: %04x, data: %02x\n", offset, data)); - - if (!(offset & 0x1000)) - { - m_reg[0] = data; - m_reg[1] = data; - } - else - m_reg[1] = data & 1; // Pro Wrestling uses this - - chr8(m_reg[1] & 3, m_chr_source); -} - -/*------------------------------------------------- - - BTL-MARIO1-MALEE2 (aka Genius Merio Bros) - - Games: Super Mario Bros Malee 2 - - iNES: - - This PCB has two PRG chips (32K+2K) + one CHR chip (8K) - + 2KB of WRAM - The second PRG chip (2K) is connected at 0x6000-0x6800 - while WRAM is at 0x7000-0x7800 - - In MESS: Supported. - - -------------------------------------------------*/ - -READ8_MEMBER(nes_mmalee_device::read_m) -{ - LOG_MMC(("mmalee read_m, offset: %04x\n", offset)); - - if (offset < 0x0800) - return m_prg[0x8000 + offset]; - else if (!m_prgram.empty() && offset >= 0x1000 && offset < 0x1800) // WRAM only in these 2K - return m_prgram[offset & 0x7ff]; - - return ((offset + 0x6000) & 0xff00) >> 8; -} - -WRITE8_MEMBER(nes_mmalee_device::write_m) -{ - LOG_MMC(("mmalee write_m, offset: %04x, data: %02x\n", offset, data)); - - if (!m_prgram.empty() && offset >= 0x1000 && offset < 0x1800) // WRAM only in these 2K - m_prgram[offset & 0x7ff] = data; -} - -/*------------------------------------------------- - - BTL-SHUIGUANPIPE - - Games: Shui Guan Pipe (Gimmick Pirate) - - iNES: - - In MESS: Supported, but there are glitches (PPU or IRQ?) - - -------------------------------------------------*/ - -// timer always running and checking IRQ every 114 CPU cycles? -void nes_shuiguan_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) -{ - if (id == TIMER_IRQ) - { - m_irq_count++; - m_irq_count &= 0xff; - - if (m_irq_enable && !m_irq_count) - m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE); - } -} - -WRITE8_MEMBER(nes_shuiguan_device::write_h) -{ - int bank; - LOG_MMC(("shuiguan write_h, offset: %04x, data: %02x\n", offset, data)); - - switch (offset & 0x7000) - { - case 0x0000: - if (offset & 0x800 && !(offset & 0x0c)) // 0x8800-0x8803 + N*0x10 - prg8_89(data); - break; - case 0x1000: - if (offset & 0x800 && !(offset & 0x0c)) // 0x9800-0x9803 + N*0x10 - { - switch (data & 0x03) - { - case 0: set_nt_mirroring(PPU_MIRROR_VERT); break; - case 1: set_nt_mirroring(PPU_MIRROR_HORZ); break; - case 2: set_nt_mirroring(PPU_MIRROR_LOW); break; - case 3: set_nt_mirroring(PPU_MIRROR_HIGH); break; - } - } - break; - case 0x2000: - if (!(offset & 0x800) && !(offset & 0x0c)) // 0xa000-0xa003 + N*0x10 - prg8_cd(data); - if (offset & 0x800 && !(offset & 0x0c)) // 0xa800-0xa803 + N*0x10 - prg8_ab(data); - break; - case 0x3000: - case 0x4000: - case 0x5000: - case 0x6000: - bank = (((offset + 0x1000) >> 11) | (offset >> 3)) & 0x07; - if (offset & 4) - m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0x0f) | ((data & 0x0f) << 4); - else - m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0xf0) | ((data & 0x0f) << 0); - chr1_x(bank, m_mmc_vrom_bank[bank], m_chr_source); - break; - case 0x7000: - switch (offset & 0x0c) - { - case 0x00: m_irq_count = (m_irq_count & 0xf0) | ((data & 0x0f) << 0); break; - case 0x04: m_irq_count = (m_irq_count & 0x0f) | ((data & 0x0f) << 4); break; - case 0x08: m_irq_enable= data; break; - case 0x0c: break; - } - break; - } -} - -READ8_MEMBER(nes_shuiguan_device::read_m) -{ - // always first bank?? - LOG_MMC(("shuiguan read_m, offset: %04x\n", offset)); - return m_prg[offset & 0x1fff]; -} diff --git a/src/devices/bus/nes/bootleg.cpp b/src/devices/bus/nes/bootleg.cpp new file mode 100644 index 00000000000..23b13b51711 --- /dev/null +++ b/src/devices/bus/nes/bootleg.cpp @@ -0,0 +1,1635 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for Bootleg PCBs + + + Here we emulate the PCBs used in FDS2NES conversions which are common in the Taiwanese & HK markets + Notice that many of these have unusual PRG sizes (32KB+8KB, 32KB+24KB) partially mapped in the WRAM + area, or WRAM overlapping the usual PRG area, so that we often skip the usual bankswitching mechanisms + in favor of direct handling of the PRG accesses + + TODO: + - review all PCBs and fix the starting banks (which are often the main problem of not working games) + - investigate pcbs listed in FCEUmm but with apparently no dumps available (LE05 and LH53) + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "bootleg.h" + +#include "cpu/m6502/m6502.h" +#include "video/ppu2c0x.h" // this has to be included so that IRQ functions can access PPU_BOTTOM_VISIBLE_SCANLINE + + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_AX5705 = &device_creator; +const device_type NES_SC127 = &device_creator; +const device_type NES_MARIOBABY = &device_creator; +const device_type NES_ASN = &device_creator; +const device_type NES_SMB3PIRATE = &device_creator; +const device_type NES_BTL_DNINJA = &device_creator; +const device_type NES_WHIRLWIND_2706 = &device_creator; +const device_type NES_SMB2J = &device_creator; +const device_type NES_SMB2JA = &device_creator; +const device_type NES_SMB2JB = &device_creator; +const device_type NES_09034A = &device_creator; +const device_type NES_TOBIDASE = &device_creator; +const device_type NES_LH32 = &device_creator; +const device_type NES_LH10 = &device_creator; +const device_type NES_LH53 = &device_creator; +const device_type NES_2708 = &device_creator; +const device_type NES_AC08 = &device_creator; +const device_type NES_UNL_BB = &device_creator; +const device_type NES_MMALEE = &device_creator; +const device_type NES_SHUIGUAN = &device_creator; + + +nes_ax5705_device::nes_ax5705_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_AX5705, "NES Cart AX5705 PCB", tag, owner, clock, "nes_ax5705", __FILE__) +{ +} + +nes_sc127_device::nes_sc127_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_SC127, "NES Cart SC-127 PCB", tag, owner, clock, "nes_sc127", __FILE__) +{ +} + +nes_mbaby_device::nes_mbaby_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_MARIOBABY, "NES Cart Mario Baby Bootleg PCB", tag, owner, clock, "nes_mbaby", __FILE__) +{ +} + +nes_asn_device::nes_asn_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_ASN, "NES Cart Ai Senshi Nicol Bootleg PCB", tag, owner, clock, "nes_asn", __FILE__) +{ +} + +nes_smb3p_device::nes_smb3p_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_SMB3PIRATE, "NES Cart Super Mario Bros. 3 Pirate PCB", tag, owner, clock, "nes_smb3p", __FILE__) +{ +} + +nes_btl_dn_device::nes_btl_dn_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_BTL_DNINJA, "NES Cart DragonNinja Pirate PCB", tag, owner, clock, "nes_btl_dn", __FILE__) +{ +} + +nes_whirl2706_device::nes_whirl2706_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_WHIRLWIND_2706, "NES Cart Whirlwind 2706 PCB", tag, owner, clock, "nes_whirl2706", __FILE__) +{ +} + +nes_smb2j_device::nes_smb2j_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_SMB2J, "NES Cart Super Mario Bros. 2 Jpn PCB", tag, owner, clock, "nes_smb2j", __FILE__) +{ +} + +nes_smb2ja_device::nes_smb2ja_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_SMB2JA, "NES Cart Super Mario Bros. 2 Jpn (Alt) PCB", tag, owner, clock, "nes_smb2ja", __FILE__) +{ +} + +nes_smb2jb_device::nes_smb2jb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_SMB2JB, "NES Cart Super Mario Bros. 2 Jpn (Alt 2) PCB", tag, owner, clock, "nes_smb2jb", __FILE__) +{ +} + +nes_09034a_device::nes_09034a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_09034A, "NES Cart 09-034A PCB", tag, owner, clock, "nes_09034a", __FILE__) +{ +} + +nes_tobidase_device::nes_tobidase_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_TOBIDASE, "NES Cart Tobidase Daisakusen Pirate PCB", tag, owner, clock, "nes_tobidase", __FILE__) +{ +} + +nes_lh32_device::nes_lh32_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_LH32, "NES Cart LH-32 Pirate PCB", tag, owner, clock, "nes_lh32", __FILE__) +{ +} + +nes_lh10_device::nes_lh10_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_LH10, "NES Cart LH-10 Pirate PCB", tag, owner, clock, "nes_lh10", __FILE__) +{ +} + +nes_lh53_device::nes_lh53_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_LH53, "NES Cart LH-53 Pirate PCB", tag, owner, clock, "nes_lh53", __FILE__) +{ +} + +nes_2708_device::nes_2708_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_2708, "NES Cart BTL-2708 Pirate PCB", tag, owner, clock, "nes_2708", __FILE__) +{ +} + +nes_ac08_device::nes_ac08_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_AC08, "NES Cart AC08 Pirate PCB", tag, owner, clock, "nes_ac08", __FILE__) +{ +} + +nes_unl_bb_device::nes_unl_bb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_UNL_BB, "NES Cart FDS+CHR Pirate PCB", tag, owner, clock, "nes_unl_bb", __FILE__) +{ +} + +nes_mmalee_device::nes_mmalee_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_MMALEE, "NES Cart Super Mario Bros. Malee 2 Pirate PCB", tag, owner, clock, "nes_mmalee", __FILE__) +{ +} + +nes_shuiguan_device::nes_shuiguan_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_SHUIGUAN, "NES Cart Shui Guan Pipe Pirate PCB", tag, owner, clock, "nes_shuiguan", __FILE__) +{ +} + + + + +void nes_ax5705_device::device_start() +{ + common_start(); + save_item(NAME(m_mmc_prg_bank)); + save_item(NAME(m_mmc_vrom_bank)); +} + +void nes_ax5705_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + chr8(0, m_chr_source); + + m_mmc_prg_bank[0] = 0; + m_mmc_prg_bank[1] = 1; + prg8_89(m_mmc_prg_bank[0]); + prg8_ab(m_mmc_prg_bank[1]); + prg8_cd(0xfe); + prg8_ef(0xff); + + memset(m_mmc_vrom_bank, 0, sizeof(m_mmc_vrom_bank)); +} + +void nes_sc127_device::device_start() +{ + common_start(); + save_item(NAME(m_irq_enable)); + save_item(NAME(m_irq_count)); +} + +void nes_sc127_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0xff); + chr8(0, m_chr_source); + + m_irq_enable = 0; + m_irq_count = 0; +} + +void nes_mbaby_device::device_start() +{ + common_start(); + irq_timer = timer_alloc(TIMER_IRQ); + irq_timer->reset(); + timer_freq = machine().device("maincpu")->cycles_to_attotime(24576); + + save_item(NAME(m_irq_enable)); + save_item(NAME(m_latch)); +} + +void nes_mbaby_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32((m_prg_chunks - 1) >> 1); + chr8(0, m_chr_source); + + m_irq_enable = 0; + m_latch = 0; +} + +void nes_asn_device::device_start() +{ + common_start(); + save_item(NAME(m_latch)); +} + +void nes_asn_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32((m_prg_chunks - 1) >> 1); + chr8(0, m_chr_source); + + m_latch = 0; +} + +void nes_smb3p_device::device_start() +{ + common_start(); + irq_timer = timer_alloc(TIMER_IRQ); + irq_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1)); + + save_item(NAME(m_irq_enable)); + save_item(NAME(m_irq_count)); +} + +void nes_smb3p_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg8_89((m_prg_chunks << 1) - 1); + prg8_ab(0); + prg8_cd(0); + prg8_ef((m_prg_chunks << 1) - 1); + chr8(0, m_chr_source); + + m_irq_enable = 0; + m_irq_count = 0; +} + +void nes_btl_dn_device::device_start() +{ + common_start(); + save_item(NAME(m_irq_count)); +} + +void nes_btl_dn_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + + m_irq_count = 0; +} + +void nes_whirl2706_device::device_start() +{ + common_start(); + save_item(NAME(m_latch)); +} + +void nes_whirl2706_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0xff); + chr8(0, m_chr_source); + + m_latch = 0; +} + +void nes_smb2j_device::device_start() +{ + common_start(); + irq_timer = timer_alloc(TIMER_IRQ); + irq_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1)); + + save_item(NAME(m_irq_enable)); + save_item(NAME(m_irq_count)); +} + +void nes_smb2j_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + chr8(0, m_chr_source); + prg8_89(1); + prg8_ab(0); + prg8_cd(0); + prg8_ef(9); + + m_irq_enable = 0; + m_irq_count = 0; +} + +void nes_smb2ja_device::device_start() +{ + common_start(); + irq_timer = timer_alloc(TIMER_IRQ); + irq_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1)); + + save_item(NAME(m_irq_enable)); + save_item(NAME(m_irq_count)); +} + +void nes_smb2ja_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg8_89(0xfc); + prg8_ab(0xfd); + prg8_cd(0xfe); + prg8_ef(0xff); + chr8(0, m_chr_source); + + m_irq_enable = 0; + m_irq_count = 0; +} + +void nes_smb2jb_device::device_start() +{ + common_start(); + irq_timer = timer_alloc(TIMER_IRQ); + irq_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1)); + + save_item(NAME(m_irq_enable)); + save_item(NAME(m_irq_count)); +} + +void nes_smb2jb_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg8_89(0x08); + prg8_ab(0x09); + prg8_cd(0); + prg8_ef(0x0b); + chr8(0, m_chr_source); + + m_irq_enable = 0; + m_irq_count = 0; +} + +void nes_09034a_device::device_start() +{ + common_start(); + save_item(NAME(m_reg)); +} + +void nes_09034a_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); + m_reg = 0; +} + +void nes_tobidase_device::device_start() +{ + common_start(); + save_item(NAME(m_latch)); +} + +void nes_tobidase_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(2); + chr8(0, m_chr_source); + + m_latch = 0; +} + +void nes_lh32_device::device_start() +{ + common_start(); + save_item(NAME(m_latch)); +} + +void nes_lh32_device::pcb_reset() +{ + chr8(0, CHRRAM); + + prg32((m_prg_chunks - 1) >> 1); + // 0xc000-0xdfff reads/writes WRAM + m_latch = 0xf; +} + +void nes_lh10_device::device_start() +{ + common_start(); + save_item(NAME(m_latch)); + save_item(NAME(m_reg)); +} + +void nes_lh10_device::pcb_reset() +{ + chr8(0, CHRRAM); + + prg8_89(0); + prg8_ab(0); + // 0xc000-0xdfff reads/writes WRAM + prg8_ef(0xff); + memset(m_reg, 0, sizeof(m_reg)); + m_latch = 0; +} + +void nes_lh53_device::device_start() +{ + common_start(); + irq_timer = timer_alloc(TIMER_IRQ); + irq_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1)); + + save_item(NAME(m_irq_enable)); + save_item(NAME(m_irq_count)); + save_item(NAME(m_reg)); +} + +void nes_lh53_device::pcb_reset() +{ + chr8(0, CHRRAM); + + prg8_89(0xc); + prg8_ab(0xd); // last 2K are overlayed by WRAM + prg8_cd(0xe); // first 6K are overlayed by WRAM + prg8_ef(0xf); + m_reg = 0; + m_irq_count = 0; + m_irq_enable = 0; +} + +void nes_2708_device::device_start() +{ + common_start(); + save_item(NAME(m_reg)); +} + +void nes_2708_device::pcb_reset() +{ + chr8(0, CHRRAM); + + prg32(7); + // the upper PRG banks never change, but there are 8K of WRAM overlayed to the ROM area based on reg1 + m_reg[0] = 0; + m_reg[1] = 0; +} + +void nes_ac08_device::device_start() +{ + common_start(); + save_item(NAME(m_latch)); +} + +void nes_ac08_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + chr8(0, m_chr_source); + prg32(0xff); + m_latch = 0xff; +} + +void nes_unl_bb_device::device_start() +{ + common_start(); + save_item(NAME(m_reg)); +} + +void nes_unl_bb_device::pcb_reset() +{ + chr8(0, CHRROM); + prg32(0xff); + // the upper PRG banks never change, but there are 8K of WRAM overlayed to the ROM area based on reg1 + m_reg[0] = 0xff; + m_reg[1] = 0; +} + +void nes_mmalee_device::device_start() +{ + common_start(); +} + +void nes_mmalee_device::pcb_reset() +{ + chr8(0, CHRROM); + prg32(0); +} + +void nes_shuiguan_device::device_start() +{ + common_start(); + irq_timer = timer_alloc(TIMER_IRQ); + // always running and checking for IRQ every 114 cycles? or resetting every frame? + irq_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(114)); + + save_item(NAME(m_irq_enable)); + save_item(NAME(m_irq_count)); + save_item(NAME(m_mmc_vrom_bank)); +} + +void nes_shuiguan_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32((m_prg_chunks << 1) - 1); + chr8(0, m_chr_source); + + m_irq_enable = 0; + m_irq_count = 0; + memset(m_mmc_vrom_bank, 0, sizeof(m_mmc_vrom_bank)); +} + + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + Board UNL-AX5705 + + Games: Super Mario Bros. Pocker Mali (Crayon Shin-chan pirate hack) + + In MESS: Supported + + -------------------------------------------------*/ + +void nes_ax5705_device::set_prg() +{ + prg8_89(m_mmc_prg_bank[0]); + prg8_ab(m_mmc_prg_bank[1]); +} + +WRITE8_MEMBER(nes_ax5705_device::write_h) +{ + UINT8 bank; + LOG_MMC(("ax5705 write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x700f) + { + case 0x0000: + m_mmc_prg_bank[0] = (data & 0x05) | ((data & 0x08) >> 2) | ((data & 0x02) << 2); + set_prg(); + break; + case 0x0008: + set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + break; + case 0x2000: + m_mmc_prg_bank[1] = (data & 0x05) | ((data & 0x08) >> 2) | ((data & 0x02) << 2); + set_prg(); + break; + /* CHR banks 0, 1, 4, 5 */ + case 0x2008: + case 0x200a: + case 0x4008: + case 0x400a: + bank = ((offset & 0x4000) ? 4 : 0) + ((offset & 0x0002) ? 1 : 0); + m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0xf0) | (data & 0x0f); + chr1_x(bank, m_mmc_vrom_bank[bank], CHRROM); + break; + case 0x2009: + case 0x200b: + case 0x4009: + case 0x400b: + bank = ((offset & 0x4000) ? 4 : 0) + ((offset & 0x0002) ? 1 : 0); + m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0x0f) | ((data & 0x04) << 3) | ((data & 0x02) << 5) | ((data & 0x09) << 4); + chr1_x(bank, m_mmc_vrom_bank[bank], CHRROM); + break; + /* CHR banks 2, 3, 6, 7 */ + case 0x4000: + case 0x4002: + case 0x6000: + case 0x6002: + bank = 2 + ((offset & 0x2000) ? 4 : 0) + ((offset & 0x0002) ? 1 : 0); + m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0xf0) | (data & 0x0f); + chr1_x(bank, m_mmc_vrom_bank[bank], CHRROM); + break; + case 0x4001: + case 0x4003: + case 0x6001: + case 0x6003: + bank = 2 + ((offset & 0x2000) ? 4 : 0) + ((offset & 0x0002) ? 1 : 0); + m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0x0f) | ((data & 0x04) << 3) | ((data & 0x02) << 5) | ((data & 0x09) << 4); + chr1_x(bank, m_mmc_vrom_bank[bank], CHRROM); + break; + } +} + +/*------------------------------------------------- + + SC-127 Board + + Games: Wario World II (Kirby Hack) + + iNES: mapper 35 + + In MESS: Supported + + -------------------------------------------------*/ + +void nes_sc127_device::hblank_irq(int scanline, int vblank, int blanked) +{ + if (scanline < PPU_BOTTOM_VISIBLE_SCANLINE && m_irq_enable) + { + m_irq_count--; + + if (!blanked && (m_irq_count == 0)) + { + LOG_MMC(("irq fired, scanline: %d (MAME %d, beam pos: %d)\n", scanline, + machine().first_screen()->vpos(), machine().first_screen()->hpos())); + m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE); + m_irq_enable = 0; + } + } +} + +WRITE8_MEMBER(nes_sc127_device::write_h) +{ + LOG_MMC(("sc127 write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset) + { + case 0x0000: + prg8_89(data); + break; + case 0x0001: + prg8_ab(data); + break; + case 0x0002: +// m_mmc_prg_bank[offset & 0x02] = data; + prg8_cd(data); + break; + case 0x1000: + case 0x1001: + case 0x1002: + case 0x1003: + case 0x1004: + case 0x1005: + case 0x1006: + case 0x1007: +// m_mmc_vrom_bank[offset & 0x07] = data; + chr1_x(offset & 0x07, data, CHRROM); + break; + case 0x4002: + m_irq_enable = 0; + break; + case 0x4003: + m_irq_enable = 1; + break; + case 0x4005: + m_irq_count = data; + break; + case 0x5001: + set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + break; + } +} + +/*------------------------------------------------- + + BTL-MARIOBABY + + Games: Mario Baby, Ai Senshi Nicol + + iNES: mapper 42 + + In MESS: Supported. + + -------------------------------------------------*/ + +void nes_mbaby_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (id == TIMER_IRQ) + { + m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE); + irq_timer->adjust(attotime::never); + } +} + +WRITE8_MEMBER(nes_mbaby_device::write_h) +{ + LOG_MMC(("Mario Baby write_h, offset: %04x, data: %02x\n", offset, data)); + + if (offset >= 0x7000) + { + switch (offset & 0x03) + { + case 0x00: + m_latch = data; + break; + case 0x01: + set_nt_mirroring(BIT(data, 3) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + break; + case 0x02: + /* Check if IRQ is being enabled */ + if (!m_irq_enable && (data & 0x02)) + { + m_irq_enable = 1; + irq_timer->adjust(timer_freq); + } + if (!(data & 0x02)) + { + m_irq_enable = 0; + irq_timer->adjust(attotime::never); + } + break; + } + } +} + +READ8_MEMBER(nes_mbaby_device::read_m) +{ + LOG_MMC(("Mario Baby read_m, offset: %04x\n", offset)); + return m_prg[(m_latch * 0x2000) + (offset & 0x1fff)]; +} + +/*------------------------------------------------- + + BTL-AISENSHINICOL + + Games: Ai Senshi Nicol + + iNES: mapper 42 with no IRQ and no NT, but CHR switch + + In MESS: Partially Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_asn_device::write_h) +{ + LOG_MMC(("Ai Senshi Nicol write_h, offset: %04x, data: %02x\n", offset, data)); + + if (offset == 0x0000) + chr8(data, CHRROM); + + if (offset == 0x7000) + m_latch = data; +} + +READ8_MEMBER(nes_asn_device::read_m) +{ + LOG_MMC(("Ai Senshi Nicol read_m, offset: %04x\n", offset)); + return m_prg[((m_latch * 0x2000) + (offset & 0x1fff)) & (m_prg_size - 1)]; +} + + +/*------------------------------------------------- + + BTL-SMB3 + + Games: Super Mario Bros. 3 Pirate + + iNES: mapper 106 + + In MESS: Supported. + + -------------------------------------------------*/ + +void nes_smb3p_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (id == TIMER_IRQ) + { + if (m_irq_enable) + { + if (m_irq_count == 0xffff) + { + m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE); + m_irq_enable = 0; + } + else + m_irq_count++; + } + } +} + +WRITE8_MEMBER(nes_smb3p_device::write_h) +{ + LOG_MMC(("btl_smb3_w, offset: %04x, data: %02x\n", offset, data)); + switch (offset & 0x0f) + { + case 0x00: + case 0x02: + chr1_x(offset & 0x07, data & 0xfe, CHRROM); + break; + case 0x01: + case 0x03: + chr1_x(offset & 0x07, data | 0x01, CHRROM); + break; + case 0x04: case 0x05: + case 0x06: case 0x07: + chr1_x(offset & 0x07, data, CHRROM); + break; + case 0x08: + prg8_89(data | 0x10); + break; + case 0x09: + prg8_ab(data); + break; + case 0x0a: + prg8_cd(data); + break; + case 0x0b: + prg8_ef(data | 0x10); + break; + case 0x0c: + set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + break; + case 0x0d: + m_irq_count = 0; + m_irq_enable = 0; + break; + case 0x0e: + m_irq_count = (m_irq_count & 0xff00) | data; + break; + case 0x0f: + m_irq_count = (m_irq_count & 0x00ff) | (data << 8); + m_irq_enable = 1; + break; + } +} + +/*------------------------------------------------- + + BTL-DRAGONNINJA + + Games: Dragon Ninja (Bootleg), Super Mario Bros. 8 + + iNES: mapper 222 + + In MESS: Unsupported. + + -------------------------------------------------*/ + +/* Scanline based IRQ ? */ +void nes_btl_dn_device::hblank_irq(int scanline, int vblank, int blanked ) +{ + if (!m_irq_count || ++m_irq_count < 240) + return; + + m_irq_count = 0; + m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE); +} + +WRITE8_MEMBER(nes_btl_dn_device::write_h) +{ + UINT8 bank; + LOG_MMC(("btl_dn write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x7003) + { + case 0x0000: + prg8_89(data); + break; + case 0x1000: + set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + break; + case 0x2000: + prg8_ab(data); + break; + case 0x3000: + case 0x3002: + case 0x4000: + case 0x4002: + case 0x5000: + case 0x5002: + case 0x6000: + case 0x6002: + bank = ((offset & 0x7000) - 0x3000) / 0x0800 + ((offset & 0x0002) >> 1); + chr1_x(bank, data, CHRROM); + break; + case 0x7000: + m_irq_count = data; + break; + } +} + +/*------------------------------------------------- + + BOOTLEG FC VERSIONS OF FDS GAMES + + -------------------------------------------------*/ + +/*------------------------------------------------- + + WHIRLWIND-2706 + + Games: Meikyuu Jiin Dababa (FDS conversion) and a few + others + + This PCB maps PRG in 0x6000-0x7fff + + iNES: mapper 108 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_whirl2706_device::write_h) +{ + LOG_MMC(("whirl2706 write_h, offset: %04x, data: %02x\n", offset, data)); + m_latch = data; +} + +READ8_MEMBER(nes_whirl2706_device::read_m) +{ + LOG_MMC(("whirl2706 read_m, offset: %04x\n", offset)); + return m_prg[(m_latch * 0x2000 + (offset & 0x1fff)) & (m_prg_size - 1)]; +} + +/*------------------------------------------------- + + Bootleg Board SMB2J + + Games: Super Mario Bros. 2 Pirate (LF36) + + iNES: mapper 43 + + In MESS: Supported. + + -------------------------------------------------*/ + +void nes_smb2j_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (id == TIMER_IRQ) + { + if (m_irq_enable) + { + if (m_irq_count == 0xfff) + { + m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE); + m_irq_enable = 0; + m_irq_count = 0; + } + else + m_irq_count++; + } + } +} + +WRITE8_MEMBER(nes_smb2j_device::write_l) +{ + LOG_MMC(("smb2j write_l, offset: %04x, data: %02x\n", offset, data)); + offset += 0x100; + + if (offset == 0x122) // $4122 + m_irq_enable = data & 3; // maybe also m_irq_count = 0?!? +} + +WRITE8_MEMBER(nes_smb2j_device::write_h) +{ + LOG_MMC(("smb2j write_h, offset: %04x, data: %02x\n", offset, data)); + + if (offset == 0x122) // $8122 too? + m_irq_enable = data & 3; +} + +WRITE8_MEMBER(nes_smb2j_device::write_ex) +{ + LOG_MMC(("smb2j write_ex, offset: %04x, data: %02x\n", offset, data)); + + if (offset == 2) + { + int temp = 0; + + // According to hardware tests + if (data & 1) + temp = 3; + else + temp = 4 + ((data & 7) >> 1); + + prg8_cd(temp); + } +} + +READ8_MEMBER(nes_smb2j_device::read_l) +{ + LOG_MMC(("smb2j read_l, offset: %04x\n", offset)); + offset += 0x100; + + if (offset >= 0x1000) + return m_prg[0x10000 + (offset & 0x0fff)]; + + return m_open_bus; // open bus +} + +READ8_MEMBER(nes_smb2j_device::read_m) +{ + LOG_MMC(("smb2j read_m, offset: %04x\n", offset)); + return m_prg[0x4000 + offset]; +} + +/*------------------------------------------------- + + BTL-SMB2A + + Games: Super Mario Bros. 2 Pirate (Jpn version of SMB2) + + iNES: mapper 40 + + In MESS: Supported. + + -------------------------------------------------*/ + +void nes_smb2ja_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (id == TIMER_IRQ) + { + if (m_irq_enable) + { + if (m_irq_count == 0xfff) + { + m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE); + m_irq_enable = 0; + m_irq_count = 0; + } + else + m_irq_count++; + } + } +} + +WRITE8_MEMBER(nes_smb2ja_device::write_h) +{ + LOG_MMC(("smb2ja write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x6000) + { + case 0x0000: + m_irq_enable = 0; + m_irq_count = 0; + break; + case 0x2000: + m_irq_enable = 1; + break; + case 0x6000: + prg8_cd(data); + break; + } +} + +READ8_MEMBER(nes_smb2ja_device::read_m) +{ + LOG_MMC(("smb2ja read_m, offset: %04x\n", offset)); + return m_prg[(0xfe * 0x2000 + (offset & 0x1fff)) & (m_prg_size - 1)]; +} + +/*------------------------------------------------- + + BTL-SMB2B + + Games: Super Mario Bros. 2 Pirate (Jpn version of SMB2) + + This was marked as Alt. Levels. is it true? + + iNES: mapper 50 + + In MESS: Partially Supported. + + -------------------------------------------------*/ + +void nes_smb2jb_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (id == TIMER_IRQ) + { + if (m_irq_enable) + { + if (m_irq_count == 0xfff) + { + m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE); + m_irq_enable = 0; + m_irq_count = 0; + } + else + m_irq_count++; + } + } +} + +WRITE8_MEMBER(nes_smb2jb_device::write_l) +{ + UINT8 prg; + LOG_MMC(("smb2jb write_l, offset: %04x, data: %02x\n", offset, data)); + offset += 0x100; + + switch (offset & 0x1e0) + { + case 0x020: + case 0x0a0: + prg = (data & 0x08) | ((data & 0x06) >> 1) | ((data & 0x01) << 2); + prg8_cd(prg); + break; + case 0x120: + case 0x1a0: + m_irq_enable = data & 0x01; + break; + } +} + +READ8_MEMBER(nes_smb2jb_device::read_m) +{ + LOG_MMC(("smb2jb read_m, offset: %04x\n", offset)); + return m_prg[((0x0f * 0x2000) + (offset & 0x1fff)) & (m_prg_size - 1)]; +} + +/* This goes to 0x4020-0x403f & 0x40a0-0x40bf */ +WRITE8_MEMBER(nes_smb2jb_device::write_ex) +{ + UINT8 prg; + LOG_MMC(("smb2jb write_ex, offset: %04x, data: %02x\n", offset, data)); + + if ((offset < 0x20) || (offset >= 0x80 && offset < 0xa0)) + { + prg = (data & 0x08) | ((data & 0x06) >> 1) | ((data & 0x01) << 2); + prg8_cd(prg); + } +} + +/*------------------------------------------------- + + (UNL-)09-034A + + Games: Zanac FDS conversion with two PRG chips and + no CHRROM and Volleyball FDS conversion with two PRG + chips and CHRROM. + Originally dumps were marked as UNL-SMB2J pcb + + iNES: + + In MESS: Partially Supported. Need to emulate IRQ + (needed by smb2 conversion?) + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_09034a_device::write_ex) +{ + LOG_MMC(("09-034a write_ex, offset: %04x, data: %02x\n", offset, data)); + + if (offset == 7) // $4027 + m_reg = data & 1; +} + +READ8_MEMBER(nes_09034a_device::read_m) +{ + LOG_MMC(("09-034a read_m, offset: %04x\n", offset)); + // in 0x6000-0x7fff is mapped the 2nd PRG chip which starts after 32K (hence the +4) + return m_prg[((m_reg + 4) * 0x2000) + offset]; +} + +/*------------------------------------------------- + + Bootleg Board used for FDS conversion + + Games: Tobidase Daisakusen (FDS conversion) + + This PCB maps PRG in 0x6000-0x7fff + + iNES: mapper 120 + + In MESS: Partially Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_tobidase_device::write_l) +{ + LOG_MMC(("tobidase write_h, offset: %04x, data: %02x\n", offset, data)); + offset += 0x4100; + + if ((offset & 0x63c0) == 0x41c0) + m_latch = data & 0x0f; +} + +READ8_MEMBER(nes_tobidase_device::read_m) +{ + LOG_MMC(("tobidase read_m, offset: %04x\n", offset)); + if (m_latch >= 0x0c) + m_latch -= 4; + return m_prg[(m_latch * 0x2000) + (offset & 0x1fff)]; +} + +/*------------------------------------------------- + + UNL-LH32 + + Games: Monty no Doki Doki Daidassou (FDS conversion) + + This PCB maps WRAM in 0xc000-0xdfff and PRG in 0x6000-0x7fff + + iNES: + + In MESS: Supported. + +-------------------------------------------------*/ + +READ8_MEMBER(nes_lh32_device::read_m) +{ + LOG_MMC(("lh32 read_m, offset: %04x\n", offset)); + return m_prg[(m_latch * 0x2000) + (offset & 0x1fff)]; +} + +READ8_MEMBER(nes_lh32_device::read_h) +{ + LOG_MMC(("lh32 read_h, offset: %04x\n", offset)); + + if (offset >= 0x4000 && offset < 0x6000) + return m_prgram[offset & 0x1fff]; + + return hi_access_rom(offset); +} + +WRITE8_MEMBER(nes_lh32_device::write_m) +{ + LOG_MMC(("lh32 write_m, offset: %04x, data: %02x\n", offset, data)); + + if (offset == 0) // 0x6000 only? + { +// printf("write %x\n", data); + m_latch = data & 0xf; + } +} + +WRITE8_MEMBER(nes_lh32_device::write_h) +{ + LOG_MMC(("lh32 write_h, offset: %04x, data: %02x\n", offset, data)); + + if (offset >= 0x4000 && offset < 0x6000) + m_prgram[offset & 0x1fff] = data; +} + +/*------------------------------------------------- + + UNL-LH10 + + Games: Fuuun Shaolin Kyo (FDS conversion) + + This PCB maps WRAM in 0xc000-0xdfff and PRG in 0x6000-0x7fff + This is very similar to KS7037 (not sure which conversion + uses that one) + + iNES: + + In MESS: Supported. + + -------------------------------------------------*/ + +void nes_lh10_device::update_prg() +{ + prg8_89(m_reg[6]); + prg8_ab(m_reg[7]); +} + +READ8_MEMBER(nes_lh10_device::read_m) +{ + LOG_MMC(("lh10 read_m, offset: %04x\n", offset)); + return m_prg[(0x0e * 0x2000) + (offset & 0x1fff)]; +} + +READ8_MEMBER(nes_lh10_device::read_h) +{ + LOG_MMC(("lh10 read_h, offset: %04x\n", offset)); + + if (offset >= 0x4000 && offset < 0x6000) + return m_prgram[offset & 0x1fff]; + + return hi_access_rom(offset); +} + +WRITE8_MEMBER(nes_lh10_device::write_h) +{ + LOG_MMC(("lh10 write_h, offset: %04x, data: %02x\n", offset, data)); + + if (offset >= 0x4000 && offset < 0x6000) + m_prgram[offset & 0x1fff] = data; + + else + { + switch (offset & 0x6001) + { + case 0x0000: + m_latch = data & 7; + break; + case 0x0001: + m_reg[m_latch] = data; + update_prg(); + break; + } + } +} + +/*------------------------------------------------- + + UNL-LH53 + + Games: Nazo no Murasamejou (FDS conversion) + + This PCB maps WRAM (w/battery) in 0xb800-0xd7ff and + PRG in 0x6000-0x7fff + + iNES: + + In MESS: Preliminar Support only. + + -------------------------------------------------*/ + +void nes_lh53_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (id == TIMER_IRQ) + { + if (m_irq_enable) + { + m_irq_count++; + if (m_irq_count > 7560)//value from FCEUMM... + { + m_irq_count = 0; + m_maincpu->set_input_line(M6502_IRQ_LINE, ASSERT_LINE); + } + } + } +} + +READ8_MEMBER(nes_lh53_device::read_m) +{ + LOG_MMC(("lh53 read_m, offset: %04x\n", offset)); + return m_prg[(m_reg * 0x2000) + (offset & 0x1fff)]; +} + +READ8_MEMBER(nes_lh53_device::read_h) +{ + LOG_MMC(("lh53 read_h, offset: %04x\n", offset)); + + if (offset >= 0x3800 && offset < 0x5800) + return m_battery[offset & 0x1fff]; + + return hi_access_rom(offset); +} + +WRITE8_MEMBER(nes_lh53_device::write_h) +{ + LOG_MMC(("lh53 write_h, offset: %04x, data: %02x\n", offset, data)); + + if (offset >= 0x3800 && offset < 0x5800) + m_battery[offset & 0x1fff] = data; + + else + { + switch (offset & 0x7000) + { + case 0x6000: + m_irq_enable = BIT(data, 1); + m_irq_count = 0; + if (!m_irq_enable) + m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); + break; + case 0x7000: + m_reg = data & 0x0f; + break; + } + } +} + +/*------------------------------------------------- + + BTL-2708 + + Games: Doki Doki Panic (FDS conversion) + + iNES: mapper 103? + + This board has a very unique setup, with 8KB of WRAM + in 0x6000-0x7fff and other 8KB of WRAM in 0xb800-0xd7ff + which can be switched in 2KB chunks (we attempt to + emulate this by intercepting reads in that area before + they get to the PRG banks...) + + In MESS: Supported. + + -------------------------------------------------*/ + +READ8_MEMBER(nes_2708_device::read_m) +{ + LOG_MMC(("btl-2708 read_m, offset: %04x\n", offset)); + if (!m_reg[1]) + return m_prgram[offset]; // lower 8K of WRAM + else + return m_prg[(m_reg[0] * 0x2000) + (offset & 0x1fff)]; +} + +WRITE8_MEMBER(nes_2708_device::write_m) +{ + LOG_MMC(("btl-2708 write_m, offset: %04x, data: %02x\n", offset, data)); +// if (!m_reg[1]) + m_prgram[offset] = data; // lower 8K of WRAM +} + +READ8_MEMBER(nes_2708_device::read_h) +{ + LOG_MMC(("btl-2708 read_h, offset: %04x\n", offset)); + + if (offset >= 0x3800 && offset < 0x5800 && !m_reg[1]) + return m_prgram[0x2000 + ((offset - 0x3800) & 0x1fff)]; // higher 8K of WRAM + + return hi_access_rom(offset); +} + +WRITE8_MEMBER(nes_2708_device::write_h) +{ + LOG_MMC(("btl-2708 write_h, offset: %04x, data: %02x\n", offset, data)); + + if (offset >= 0x3800 && offset < 0x5800/* && !m_reg[1]*/) + m_prgram[0x2000 + ((offset - 0x3800) & 0x1fff)] = data; // higher 8K of WRAM + + switch (offset & 0x7000) + { + case 0x0000: + m_reg[0] = data & 0x0f; // PRG bank in 0x6000-0x7fff + break; + case 0x6000: + set_nt_mirroring(BIT(data, 3) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + break; + case 0x7000: + m_reg[1] = BIT(data, 4); // bit4 enables the two WRAM banks + break; + } +} + +/*------------------------------------------------- + + UNL-AC08 + + Games: Green Beret (FDS conversions) + + iNES: + + This board has two PRG chips. The first (128K) is + connected to 0x6000-0x7fff and switches among the + 16x8K banks; the second (32K) is fixed in 0x8000-0xffff + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_ac08_device::write_ex) +{ + LOG_MMC(("AC-08 write_ex, offset: %04x, data: %02x\n", offset, data)); + if (offset == 5) // $4025 + set_nt_mirroring(!BIT(data, 3) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ); +} + +READ8_MEMBER(nes_ac08_device::read_m) +{ + LOG_MMC(("AC-08 read_m, offset: %04x\n", offset)); + return m_prg[(m_latch * 0x2000) + (offset & 0x1fff)]; +} + +WRITE8_MEMBER(nes_ac08_device::write_h) +{ + LOG_MMC(("AC-08 write_h, offset: %04x, data: %02x\n", offset, data)); + + if (offset == 1) + m_latch = (data >> 1) & 0x0f; + else + m_latch = data & 0x0f; // apparently there also is a Castlevania FDS conversion using same board with different banking lines +} + +/*------------------------------------------------- + + UNL-BB + + Games: Bubble Bobble and other FDS conversions with CHRROM! + + iNES: + + + In MESS: Supported. + + -------------------------------------------------*/ + +READ8_MEMBER(nes_unl_bb_device::read_m) +{ + LOG_MMC(("unl-bb read_m, offset: %04x\n", offset)); + return m_prg[(((m_reg[0] & 3 & m_prg_mask) * 0x2000) + (offset & 0x1fff))]; +} + +WRITE8_MEMBER(nes_unl_bb_device::write_h) +{ + LOG_MMC(("unl-bb write_h, offset: %04x, data: %02x\n", offset, data)); + + if (!(offset & 0x1000)) + { + m_reg[0] = data; + m_reg[1] = data; + } + else + m_reg[1] = data & 1; // Pro Wrestling uses this + + chr8(m_reg[1] & 3, m_chr_source); +} + +/*------------------------------------------------- + + BTL-MARIO1-MALEE2 (aka Genius Merio Bros) + + Games: Super Mario Bros Malee 2 + + iNES: + + This PCB has two PRG chips (32K+2K) + one CHR chip (8K) + + 2KB of WRAM + The second PRG chip (2K) is connected at 0x6000-0x6800 + while WRAM is at 0x7000-0x7800 + + In MESS: Supported. + + -------------------------------------------------*/ + +READ8_MEMBER(nes_mmalee_device::read_m) +{ + LOG_MMC(("mmalee read_m, offset: %04x\n", offset)); + + if (offset < 0x0800) + return m_prg[0x8000 + offset]; + else if (!m_prgram.empty() && offset >= 0x1000 && offset < 0x1800) // WRAM only in these 2K + return m_prgram[offset & 0x7ff]; + + return ((offset + 0x6000) & 0xff00) >> 8; +} + +WRITE8_MEMBER(nes_mmalee_device::write_m) +{ + LOG_MMC(("mmalee write_m, offset: %04x, data: %02x\n", offset, data)); + + if (!m_prgram.empty() && offset >= 0x1000 && offset < 0x1800) // WRAM only in these 2K + m_prgram[offset & 0x7ff] = data; +} + +/*------------------------------------------------- + + BTL-SHUIGUANPIPE + + Games: Shui Guan Pipe (Gimmick Pirate) + + iNES: + + In MESS: Supported, but there are glitches (PPU or IRQ?) + + -------------------------------------------------*/ + +// timer always running and checking IRQ every 114 CPU cycles? +void nes_shuiguan_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (id == TIMER_IRQ) + { + m_irq_count++; + m_irq_count &= 0xff; + + if (m_irq_enable && !m_irq_count) + m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE); + } +} + +WRITE8_MEMBER(nes_shuiguan_device::write_h) +{ + int bank; + LOG_MMC(("shuiguan write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x7000) + { + case 0x0000: + if (offset & 0x800 && !(offset & 0x0c)) // 0x8800-0x8803 + N*0x10 + prg8_89(data); + break; + case 0x1000: + if (offset & 0x800 && !(offset & 0x0c)) // 0x9800-0x9803 + N*0x10 + { + switch (data & 0x03) + { + case 0: set_nt_mirroring(PPU_MIRROR_VERT); break; + case 1: set_nt_mirroring(PPU_MIRROR_HORZ); break; + case 2: set_nt_mirroring(PPU_MIRROR_LOW); break; + case 3: set_nt_mirroring(PPU_MIRROR_HIGH); break; + } + } + break; + case 0x2000: + if (!(offset & 0x800) && !(offset & 0x0c)) // 0xa000-0xa003 + N*0x10 + prg8_cd(data); + if (offset & 0x800 && !(offset & 0x0c)) // 0xa800-0xa803 + N*0x10 + prg8_ab(data); + break; + case 0x3000: + case 0x4000: + case 0x5000: + case 0x6000: + bank = (((offset + 0x1000) >> 11) | (offset >> 3)) & 0x07; + if (offset & 4) + m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0x0f) | ((data & 0x0f) << 4); + else + m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0xf0) | ((data & 0x0f) << 0); + chr1_x(bank, m_mmc_vrom_bank[bank], m_chr_source); + break; + case 0x7000: + switch (offset & 0x0c) + { + case 0x00: m_irq_count = (m_irq_count & 0xf0) | ((data & 0x0f) << 0); break; + case 0x04: m_irq_count = (m_irq_count & 0x0f) | ((data & 0x0f) << 4); break; + case 0x08: m_irq_enable= data; break; + case 0x0c: break; + } + break; + } +} + +READ8_MEMBER(nes_shuiguan_device::read_m) +{ + // always first bank?? + LOG_MMC(("shuiguan read_m, offset: %04x\n", offset)); + return m_prg[offset & 0x1fff]; +} diff --git a/src/devices/bus/nes/camerica.c b/src/devices/bus/nes/camerica.c deleted file mode 100644 index 61c41dd7867..00000000000 --- a/src/devices/bus/nes/camerica.c +++ /dev/null @@ -1,225 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Fabio Priuli -/*********************************************************************************************************** - - - NES/Famicom cartridge emulation for Camerica/Codemasters PCBs - - - Here we emulate the following PCBs - - * Camerica BF9093, BF9097, BF909X [mapper 71, two variants] - * Camerica BF9096 Boards [mapper 232] - * Camerica Golden Five [mapper 104] - - Aladdin Deck Enhancer pass-thru cart and the corresponding minicarts - (ALGNV11 & ALGQV11 PCBs) are emulated in a separate source file. - - - TODO: - - check what causes flickering from PPU in Fire Hawk, Poogie and Big Nose (same PPU issue as Back to - Future 2&3?) - - not all the Golden Five games work. investigate! - - ***********************************************************************************************************/ - - -#include "emu.h" -#include "camerica.h" - - -#ifdef NES_PCB_DEBUG -#define VERBOSE 1 -#else -#define VERBOSE 0 -#endif - -#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) - - -//------------------------------------------------- -// constructor -//------------------------------------------------- - -const device_type NES_BF9093 = &device_creator; -const device_type NES_BF9096 = &device_creator; -const device_type NES_GOLDEN5 = &device_creator; - - -nes_bf9093_device::nes_bf9093_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_BF9093, "NES Cart Camerica BF9093 PCB", tag, owner, clock, "nes_bf9093", __FILE__) -{ -} - -nes_bf9096_device::nes_bf9096_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_BF9096, "NES Cart Camerica BF9096 PCB", tag, owner, clock, "nes_bf9096", __FILE__) -{ -} - -nes_golden5_device::nes_golden5_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_GOLDEN5, "NES Cart Camerica Golden 5 PCB", tag, owner, clock, "nes_golden5", __FILE__) -{ -} - - - - -void nes_bf9093_device::device_start() -{ - common_start(); -} - -void nes_bf9093_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0xff); - chr8(0, m_chr_source); -} - -void nes_bf9096_device::device_start() -{ - common_start(); - save_item(NAME(m_latch)); - save_item(NAME(m_bank_base)); -} - -void nes_bf9096_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - chr8(0, m_chr_source); - - m_latch = 0x00; - m_bank_base = 0x0c; - prg16_89ab(m_bank_base | m_latch); - prg16_cdef(m_bank_base | 3); -} - -void nes_golden5_device::device_start() -{ - common_start(); - save_item(NAME(m_latch)); -} - -void nes_golden5_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - chr8(0, m_chr_source); - - m_latch = 0x00; - m_bank_base = 0x00; - prg16_89ab(m_bank_base | m_latch); - prg16_cdef(m_bank_base | 0x0f); -} - - - - - -/*------------------------------------------------- - mapper specific handlers - -------------------------------------------------*/ - -/*------------------------------------------------- - - Camerica Boards (BF9093, BF9097, BF909X, ALGNV11) - - Games: Linus Spacehead's Cosmic Crusade, Micro Machines, - Mig-29, Stunt Kids - - To emulate NT mirroring for BF9097 board (missing in BF9093) - we use crc_hack, however Fire Hawk is broken (but without - mirroring there would be no helicopter graphics). - - iNES: mapper 71 - - In MESS: Partially Supported. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_bf9093_device::write_h) -{ - LOG_MMC(("bf9093 write_h, offset: %04x, data: %02x\n", offset, data)); - - switch (offset & 0x7000) - { - case 0x0000: - case 0x1000: - if (m_pcb_ctrl_mirror) - set_nt_mirroring(BIT(data, 4) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW); - break; - case 0x4000: - case 0x5000: - case 0x6000: - case 0x7000: - prg16_89ab(data); - break; - } -} - -/*------------------------------------------------- - - Camerica BF9096 & ALGQV11 Boards - - Games: Quattro Adventure, Quattro Arcade, Quattro Sports - - Writes to 0x8000-0xbfff set prg block to (data&0x18)>>1, - writes to 0xc000-0xffff set prg page to data&3. selected - prg are: prg16_89ab = block|page, prg_cdef = 3|page. - For more info on the hardware to bypass the NES lockout, see - Kevtris' Camerica Mappers documentation. - - iNES: mapper 232 - - In MESS: Supported. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_bf9096_device::write_h) -{ - LOG_MMC(("bf9096 write_h, offset: %04x, data: %02x\n", offset, data)); - - if (offset < 0x4000) - { - m_bank_base = ((data >> 3) & 3) << 2; - prg16_89ab(m_bank_base | m_latch); - prg16_cdef(m_bank_base | 3); - } - else - { - m_latch = data & 3; - prg16_89ab(m_bank_base | m_latch); - } -} - -/*------------------------------------------------- - - Camerica Golden Five board - - Games: Pegasus 5 in 1 - - iNES: mapper 104 - - In MESS: Supported. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_golden5_device::write_h) -{ - LOG_MMC(("golden5 write_h, offset: %04x, data: %02x\n", offset, data)); - - if (offset < 0x4000) - { - if (data & 0x08) - { - m_bank_base = (data & 0x07) << 4; - prg16_89ab(m_bank_base | m_latch); - prg16_cdef(m_bank_base | 0x0f); - } - - } - else - { - m_latch = data & 0x0f; - prg16_89ab(m_bank_base | m_latch); - } -} diff --git a/src/devices/bus/nes/camerica.cpp b/src/devices/bus/nes/camerica.cpp new file mode 100644 index 00000000000..61c41dd7867 --- /dev/null +++ b/src/devices/bus/nes/camerica.cpp @@ -0,0 +1,225 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for Camerica/Codemasters PCBs + + + Here we emulate the following PCBs + + * Camerica BF9093, BF9097, BF909X [mapper 71, two variants] + * Camerica BF9096 Boards [mapper 232] + * Camerica Golden Five [mapper 104] + + Aladdin Deck Enhancer pass-thru cart and the corresponding minicarts + (ALGNV11 & ALGQV11 PCBs) are emulated in a separate source file. + + + TODO: + - check what causes flickering from PPU in Fire Hawk, Poogie and Big Nose (same PPU issue as Back to + Future 2&3?) + - not all the Golden Five games work. investigate! + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "camerica.h" + + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_BF9093 = &device_creator; +const device_type NES_BF9096 = &device_creator; +const device_type NES_GOLDEN5 = &device_creator; + + +nes_bf9093_device::nes_bf9093_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_BF9093, "NES Cart Camerica BF9093 PCB", tag, owner, clock, "nes_bf9093", __FILE__) +{ +} + +nes_bf9096_device::nes_bf9096_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_BF9096, "NES Cart Camerica BF9096 PCB", tag, owner, clock, "nes_bf9096", __FILE__) +{ +} + +nes_golden5_device::nes_golden5_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_GOLDEN5, "NES Cart Camerica Golden 5 PCB", tag, owner, clock, "nes_golden5", __FILE__) +{ +} + + + + +void nes_bf9093_device::device_start() +{ + common_start(); +} + +void nes_bf9093_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0xff); + chr8(0, m_chr_source); +} + +void nes_bf9096_device::device_start() +{ + common_start(); + save_item(NAME(m_latch)); + save_item(NAME(m_bank_base)); +} + +void nes_bf9096_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + chr8(0, m_chr_source); + + m_latch = 0x00; + m_bank_base = 0x0c; + prg16_89ab(m_bank_base | m_latch); + prg16_cdef(m_bank_base | 3); +} + +void nes_golden5_device::device_start() +{ + common_start(); + save_item(NAME(m_latch)); +} + +void nes_golden5_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + chr8(0, m_chr_source); + + m_latch = 0x00; + m_bank_base = 0x00; + prg16_89ab(m_bank_base | m_latch); + prg16_cdef(m_bank_base | 0x0f); +} + + + + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + Camerica Boards (BF9093, BF9097, BF909X, ALGNV11) + + Games: Linus Spacehead's Cosmic Crusade, Micro Machines, + Mig-29, Stunt Kids + + To emulate NT mirroring for BF9097 board (missing in BF9093) + we use crc_hack, however Fire Hawk is broken (but without + mirroring there would be no helicopter graphics). + + iNES: mapper 71 + + In MESS: Partially Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_bf9093_device::write_h) +{ + LOG_MMC(("bf9093 write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x7000) + { + case 0x0000: + case 0x1000: + if (m_pcb_ctrl_mirror) + set_nt_mirroring(BIT(data, 4) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW); + break; + case 0x4000: + case 0x5000: + case 0x6000: + case 0x7000: + prg16_89ab(data); + break; + } +} + +/*------------------------------------------------- + + Camerica BF9096 & ALGQV11 Boards + + Games: Quattro Adventure, Quattro Arcade, Quattro Sports + + Writes to 0x8000-0xbfff set prg block to (data&0x18)>>1, + writes to 0xc000-0xffff set prg page to data&3. selected + prg are: prg16_89ab = block|page, prg_cdef = 3|page. + For more info on the hardware to bypass the NES lockout, see + Kevtris' Camerica Mappers documentation. + + iNES: mapper 232 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_bf9096_device::write_h) +{ + LOG_MMC(("bf9096 write_h, offset: %04x, data: %02x\n", offset, data)); + + if (offset < 0x4000) + { + m_bank_base = ((data >> 3) & 3) << 2; + prg16_89ab(m_bank_base | m_latch); + prg16_cdef(m_bank_base | 3); + } + else + { + m_latch = data & 3; + prg16_89ab(m_bank_base | m_latch); + } +} + +/*------------------------------------------------- + + Camerica Golden Five board + + Games: Pegasus 5 in 1 + + iNES: mapper 104 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_golden5_device::write_h) +{ + LOG_MMC(("golden5 write_h, offset: %04x, data: %02x\n", offset, data)); + + if (offset < 0x4000) + { + if (data & 0x08) + { + m_bank_base = (data & 0x07) << 4; + prg16_89ab(m_bank_base | m_latch); + prg16_cdef(m_bank_base | 0x0f); + } + + } + else + { + m_latch = data & 0x0f; + prg16_89ab(m_bank_base | m_latch); + } +} diff --git a/src/devices/bus/nes/cne.c b/src/devices/bus/nes/cne.c deleted file mode 100644 index 76dc0a999f2..00000000000 --- a/src/devices/bus/nes/cne.c +++ /dev/null @@ -1,220 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Fabio Priuli -/*********************************************************************************************************** - - - NES/Famicom cartridge emulation for C&E PCBs - - - Here we emulate the following PCBs - - * C&E Decathlon [mapper 244] - * C&E Feng Shen Bang [mapper 246] - * C&E Sheng Huo Lie Zhuan [mapper 240] - - ***********************************************************************************************************/ - - -#include "emu.h" -#include "cne.h" - - -#ifdef NES_PCB_DEBUG -#define VERBOSE 1 -#else -#define VERBOSE 0 -#endif - -#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) - - -//------------------------------------------------- -// constructor -//------------------------------------------------- - -const device_type NES_CNE_DECATHL = &device_creator; -const device_type NES_CNE_FSB = &device_creator; -const device_type NES_CNE_SHLZ = &device_creator; - - -nes_cne_decathl_device::nes_cne_decathl_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_CNE_DECATHL, "NES Cart C&E Decathlon PCB", tag, owner, clock, "nes_cne_deca", __FILE__) -{ -} - -nes_cne_fsb_device::nes_cne_fsb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_CNE_FSB, "NES Cart C&E Feng Shen Bang PCB", tag, owner, clock, "nes_cne_fsb", __FILE__) -{ -} - -nes_cne_shlz_device::nes_cne_shlz_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_CNE_SHLZ, "NES Cart C&E Sheng Huo Lie Zhuan PCB", tag, owner, clock, "nes_cne_shlz", __FILE__) -{ -} - - - -void nes_cne_decathl_device::device_start() -{ - common_start(); -} - -void nes_cne_decathl_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0); - chr8(0, m_chr_source); -} - -void nes_cne_fsb_device::device_start() -{ - common_start(); -} - -void nes_cne_fsb_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0xff); - chr8(0, m_chr_source); -} - -void nes_cne_shlz_device::device_start() -{ - common_start(); -} - -void nes_cne_shlz_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0); - chr8(0, m_chr_source); -} - - - - -/*------------------------------------------------- - mapper specific handlers - -------------------------------------------------*/ - -/*------------------------------------------------- - - C & E Bootleg Board for Decathlon - - Games: Decathlon - - Pretty simple mapper: writes to 0x8065-0x80a4 set prg32 to - offset & 3; writes to 0x80a5-0x80e4 set chr8 to offset & 7 - - iNES: mapper 244 - - In MESS: Supported. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_cne_decathl_device::write_h) -{ - LOG_MMC(("cne_decathl_w, offset: %04x, data: %02x\n", offset, data)); - - if (offset < 0x0065) - return; - if (offset < 0x00a5) - { - prg32((offset - 0x0065) & 0x03); - return; - } - if (offset < 0x00e5) - { - chr8((offset - 0x00a5) & 0x07, CHRROM); - } -} - -/*------------------------------------------------- - - C & E Bootleg Board for Fong Shen Bang - - Games: Fong Shen Bang - Zhu Lu Zhi Zhan - - Simple mapper: writes to 0x6000-0x67ff set PRG and CHR banks. - Namely, 0x6000->0x6003 select resp. prg8_89, prg8_ab, prg8_cd - and prg8_ef. 0x6004->0x6007 select resp. crh2_0, chr2_2, - chr2_4 and chr2_6. In 0x6800-0x7fff lies WRAM. Battery backed? - - iNES: mapper 246 - - In MESS: Supported. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_cne_fsb_device::write_m) -{ - LOG_MMC(("cne_fsb write_m, offset: %04x, data: %02x\n", offset, data)); - - if (offset < 0x0800) - { - switch (offset & 0x0007) - { - case 0x0000: - prg8_89(data); - break; - case 0x0001: - prg8_ab(data); - break; - case 0x0002: - prg8_cd(data); - break; - case 0x0003: - prg8_ef(data); - break; - case 0x0004: - chr2_0(data, CHRROM); - break; - case 0x0005: - chr2_2(data, CHRROM); - break; - case 0x0006: - chr2_4(data, CHRROM); - break; - case 0x0007: - chr2_6(data, CHRROM); - break; - } - } - else - m_battery[offset] = data; -} - -READ8_MEMBER(nes_cne_fsb_device::read_m) -{ - LOG_MMC(("cne_fsb read_m, offset: %04x\n", offset)); - - if (offset >= 0x0800) - return m_battery[offset]; - - return 0xff; -} - -/*------------------------------------------------- - - C & E Bootleg Board for Sheng Huo Lie Zhuan - - Games: Jing Ke Xin Zhuan, Sheng Huo Lie Zhuan - - Simple Mapper: writes to 0x4020-0x5fff sets prg32 to - data>>4 and chr8 to data&f. We currently do not map - writes to 0x4020-0x40ff (to do: verify if this produces - issues) - - iNES: mapper 240 - - In MESS: Supported. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_cne_shlz_device::write_l) -{ - LOG_MMC(("cne_shlz write_l, offset: %04x, data: %02x\n", offset, data)); - - prg32(data >> 4); - chr8(data & 0x0f, CHRROM); -} diff --git a/src/devices/bus/nes/cne.cpp b/src/devices/bus/nes/cne.cpp new file mode 100644 index 00000000000..76dc0a999f2 --- /dev/null +++ b/src/devices/bus/nes/cne.cpp @@ -0,0 +1,220 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for C&E PCBs + + + Here we emulate the following PCBs + + * C&E Decathlon [mapper 244] + * C&E Feng Shen Bang [mapper 246] + * C&E Sheng Huo Lie Zhuan [mapper 240] + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "cne.h" + + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_CNE_DECATHL = &device_creator; +const device_type NES_CNE_FSB = &device_creator; +const device_type NES_CNE_SHLZ = &device_creator; + + +nes_cne_decathl_device::nes_cne_decathl_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_CNE_DECATHL, "NES Cart C&E Decathlon PCB", tag, owner, clock, "nes_cne_deca", __FILE__) +{ +} + +nes_cne_fsb_device::nes_cne_fsb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_CNE_FSB, "NES Cart C&E Feng Shen Bang PCB", tag, owner, clock, "nes_cne_fsb", __FILE__) +{ +} + +nes_cne_shlz_device::nes_cne_shlz_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_CNE_SHLZ, "NES Cart C&E Sheng Huo Lie Zhuan PCB", tag, owner, clock, "nes_cne_shlz", __FILE__) +{ +} + + + +void nes_cne_decathl_device::device_start() +{ + common_start(); +} + +void nes_cne_decathl_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + +void nes_cne_fsb_device::device_start() +{ + common_start(); +} + +void nes_cne_fsb_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0xff); + chr8(0, m_chr_source); +} + +void nes_cne_shlz_device::device_start() +{ + common_start(); +} + +void nes_cne_shlz_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + + + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + C & E Bootleg Board for Decathlon + + Games: Decathlon + + Pretty simple mapper: writes to 0x8065-0x80a4 set prg32 to + offset & 3; writes to 0x80a5-0x80e4 set chr8 to offset & 7 + + iNES: mapper 244 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_cne_decathl_device::write_h) +{ + LOG_MMC(("cne_decathl_w, offset: %04x, data: %02x\n", offset, data)); + + if (offset < 0x0065) + return; + if (offset < 0x00a5) + { + prg32((offset - 0x0065) & 0x03); + return; + } + if (offset < 0x00e5) + { + chr8((offset - 0x00a5) & 0x07, CHRROM); + } +} + +/*------------------------------------------------- + + C & E Bootleg Board for Fong Shen Bang + + Games: Fong Shen Bang - Zhu Lu Zhi Zhan + + Simple mapper: writes to 0x6000-0x67ff set PRG and CHR banks. + Namely, 0x6000->0x6003 select resp. prg8_89, prg8_ab, prg8_cd + and prg8_ef. 0x6004->0x6007 select resp. crh2_0, chr2_2, + chr2_4 and chr2_6. In 0x6800-0x7fff lies WRAM. Battery backed? + + iNES: mapper 246 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_cne_fsb_device::write_m) +{ + LOG_MMC(("cne_fsb write_m, offset: %04x, data: %02x\n", offset, data)); + + if (offset < 0x0800) + { + switch (offset & 0x0007) + { + case 0x0000: + prg8_89(data); + break; + case 0x0001: + prg8_ab(data); + break; + case 0x0002: + prg8_cd(data); + break; + case 0x0003: + prg8_ef(data); + break; + case 0x0004: + chr2_0(data, CHRROM); + break; + case 0x0005: + chr2_2(data, CHRROM); + break; + case 0x0006: + chr2_4(data, CHRROM); + break; + case 0x0007: + chr2_6(data, CHRROM); + break; + } + } + else + m_battery[offset] = data; +} + +READ8_MEMBER(nes_cne_fsb_device::read_m) +{ + LOG_MMC(("cne_fsb read_m, offset: %04x\n", offset)); + + if (offset >= 0x0800) + return m_battery[offset]; + + return 0xff; +} + +/*------------------------------------------------- + + C & E Bootleg Board for Sheng Huo Lie Zhuan + + Games: Jing Ke Xin Zhuan, Sheng Huo Lie Zhuan + + Simple Mapper: writes to 0x4020-0x5fff sets prg32 to + data>>4 and chr8 to data&f. We currently do not map + writes to 0x4020-0x40ff (to do: verify if this produces + issues) + + iNES: mapper 240 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_cne_shlz_device::write_l) +{ + LOG_MMC(("cne_shlz write_l, offset: %04x, data: %02x\n", offset, data)); + + prg32(data >> 4); + chr8(data & 0x0f, CHRROM); +} diff --git a/src/devices/bus/nes/cony.c b/src/devices/bus/nes/cony.c deleted file mode 100644 index a64063ebc8a..00000000000 --- a/src/devices/bus/nes/cony.c +++ /dev/null @@ -1,397 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Fabio Priuli -/*********************************************************************************************************** - - - NES/Famicom cartridge emulation for Cony/Yoko PCBs - - - Here we emulate the following PCBs - - * UNL-CONY [mapper 83] - * UNL-YOKO - - TODO: fix glitches and emulate properly the variants - - ***********************************************************************************************************/ - - -#include "emu.h" -#include "cony.h" - -#include "cpu/m6502/m6502.h" - - -#ifdef NES_PCB_DEBUG -#define VERBOSE 1 -#else -#define VERBOSE 0 -#endif - -#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) - - -//------------------------------------------------- -// constructor -//------------------------------------------------- - -const device_type NES_CONY = &device_creator; -const device_type NES_YOKO = &device_creator; - - -nes_cony_device::nes_cony_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) - : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source) -{ -} - -nes_cony_device::nes_cony_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_CONY, "NES Cart Cony PCB", tag, owner, clock, "nes_cony", __FILE__) -{ -} - -nes_yoko_device::nes_yoko_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_cony_device(mconfig, NES_YOKO, "NES Cart Yoko PCB", tag, owner, clock, "nes_yoko", __FILE__) -{ -} - - - - -void nes_cony_device::device_start() -{ - common_start(); - irq_timer = timer_alloc(TIMER_IRQ); - irq_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1)); - - save_item(NAME(m_irq_enable)); - save_item(NAME(m_irq_count)); - - save_item(NAME(m_low_reg)); - save_item(NAME(m_reg)); - save_item(NAME(m_extra1)); - save_item(NAME(m_latch1)); - save_item(NAME(m_latch2)); -} - -void nes_cony_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(0); - prg8_cd(0x1e); - prg8_ef(0x1f); - chr8(0, m_chr_source); - - m_irq_enable = 0; - m_irq_count = 0; - - m_latch1 = 0; - m_latch2 = 0; - m_extra1 = 0; - - memset(m_low_reg, 0, sizeof(m_low_reg)); - memset(m_reg, 0, sizeof(m_reg)); - m_reg[9] = 0x0f; -} - -void nes_yoko_device::device_start() -{ - common_start(); - irq_timer = timer_alloc(TIMER_IRQ); - irq_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1)); - - save_item(NAME(m_irq_enable)); - save_item(NAME(m_irq_count)); - - save_item(NAME(m_low_reg)); - save_item(NAME(m_reg)); - save_item(NAME(m_extra1)); - save_item(NAME(m_extra2)); - save_item(NAME(m_latch1)); - save_item(NAME(m_latch2)); -} - -void nes_yoko_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(0); - prg8_cd(0x1e); - prg8_ef(0x1f); - chr8(0, m_chr_source); - - m_irq_enable = 0; - m_irq_count = 0; - - m_latch1 = 0; - m_latch2 = 0; - m_extra1 = 0; - m_extra2 = 0; - - memset(m_low_reg, 0, sizeof(m_low_reg)); - memset(m_reg, 0, sizeof(m_reg)); - m_reg[9] = 0x0f; -} - - - - - -/*------------------------------------------------- - mapper specific handlers - -------------------------------------------------*/ - -/*------------------------------------------------- - - Cony Bootleg Board - - Games: Dragon Ball Party, Fatal Fury 2, Street Blaster II - Pro, World Heroes 2 - - iNES: mapper 83 - - In MESS: Supported. - - -------------------------------------------------*/ - -void nes_cony_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) -{ - if (id == TIMER_IRQ) - { - if (m_irq_enable) - { - if (!m_irq_count) - { - m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE); - m_irq_enable = 0; - m_irq_count = 0xffff; - } - else - m_irq_count--; - } - } -} - -WRITE8_MEMBER(nes_cony_device::write_l) -{ - LOG_MMC(("cony write_l, offset: %04x, data: %02x\n", offset, data)); - - if (offset >= 0x1000 && offset < 0x1103) // from 0x5100-0x51ff - m_low_reg[offset & 0x03] = data; -} - -READ8_MEMBER(nes_cony_device::read_l) -{ - LOG_MMC(("cony read_l, offset: %04x\n", offset)); - - if (offset == 0x0f00) // 0x5000 - { - // read dipswitch bit! - currently unimplemented - } - if (offset >= 0x1000 && offset < 0x1103) // from 0x5100-0x51ff - return m_low_reg[offset & 0x03]; - else - return 0x00; -} - -void nes_cony_device::set_prg() -{ - prg16_89ab(m_reg[8] & 0x3f); - prg16_cdef((m_reg[8] & 0x30) | 0x0f); -} - -void nes_cony_device::set_chr() -{ - // FIXME: here we emulate at least 3 different boards!!! - // one board switches 1k VROM banks only - // one writes to 0x8000 and then switches 2k VROM banks only - // one writes to 0x831n (n=2,3,4,5) and then switches 2k VROM banks only - // we should split them and possibly document the proper behavior of each variant - if (m_latch1 && !m_latch2) - { - chr2_0(m_reg[0], CHRROM); - chr2_2(m_reg[1], CHRROM); - chr2_4(m_reg[6], CHRROM); - chr2_6(m_reg[7], CHRROM); - } - else - { - chr1_0(m_reg[0] | ((m_reg[8] & 0x30) << 4), CHRROM); - chr1_1(m_reg[1] | ((m_reg[8] & 0x30) << 4), CHRROM); - chr1_2(m_reg[2] | ((m_reg[8] & 0x30) << 4), CHRROM); - chr1_3(m_reg[3] | ((m_reg[8] & 0x30) << 4), CHRROM); - chr1_4(m_reg[4] | ((m_reg[8] & 0x30) << 4), CHRROM); - chr1_5(m_reg[5] | ((m_reg[8] & 0x30) << 4), CHRROM); - chr1_6(m_reg[6] | ((m_reg[8] & 0x30) << 4), CHRROM); - chr1_7(m_reg[7] | ((m_reg[8] & 0x30) << 4), CHRROM); - } -} - -WRITE8_MEMBER(nes_cony_device::write_h) -{ - LOG_MMC(("cony write_h, offset: %04x, data: %02x\n", offset, data)); - - switch (offset) - { - case 0x0000: - m_latch1 = 1; - case 0x3000: - case 0x30ff: - case 0x31ff: - m_reg[8] = data; - set_prg(); - set_chr(); - break; - case 0x0100: - m_extra1 = data & 0x80; - switch (data & 0x03) - { - case 0: - set_nt_mirroring(PPU_MIRROR_VERT); - break; - case 1: - set_nt_mirroring(PPU_MIRROR_HORZ); - break; - case 2: - set_nt_mirroring(PPU_MIRROR_LOW); - break; - case 3: - set_nt_mirroring(PPU_MIRROR_HIGH); - break; - } - break; - case 0x0200: - m_irq_count = (m_irq_count & 0xff00) | data; - break; - case 0x0201: - m_irq_enable = m_extra1; - m_irq_count = (data << 8) | (m_irq_count & 0xff); - break; - case 0x0300: - prg8_89(data); - break; - case 0x0301: - prg8_ab(data); - break; - case 0x0302: - prg8_cd(data); - break; - case 0x0312: - case 0x0313: - case 0x0314: - case 0x0315: - m_latch2 = 1; - case 0x0310: - case 0x0311: - case 0x0316: - case 0x0317: - m_reg[offset - 0x0310] = data; - set_chr(); - break; - case 0x0318: - m_reg[9] = data; // unused? - set_prg(); - break; - } -} - -/*------------------------------------------------- - - Yoko Bootleg Board - - Games: Mortal Kombat II, Master Figther VI' - - - Very similar to Cony board - - In MESS: Supported. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_yoko_device::write_l) -{ - LOG_MMC(("yoko write_l, offset: %04x, data: %02x\n", offset, data)); - - if (offset >= 0x1300) // from 0x5400 - m_low_reg[offset & 0x03] = data; -} - -READ8_MEMBER(nes_yoko_device::read_l) -{ - LOG_MMC(("yoko read_l, offset: %04x\n", offset)); - - if (offset >= 0x0f00 && offset < 0x1300) // 0x5000 - { - // read dipswitch bit! - currently unimplemented - } - if (offset >= 0x1300) // from 0x5400 - return m_low_reg[offset & 0x03]; - else - return 0x00; -} - -void nes_yoko_device::set_prg() -{ - if (m_extra1 & 0x10) - { - int base = (m_extra2 & 0x08) << 1; - prg8_89(base | (m_reg[0] & 0x0f)); - prg8_ab(base | (m_reg[1] & 0x0f)); - prg8_cd(base | (m_reg[2] & 0x0f)); - prg8_ef(base | 0x0f); - } - else if (m_extra1 & 0x08) - prg32(m_extra2 >> 1); - else - { - prg16_89ab(m_extra2); - prg16_cdef(0xff); - } -} - -void nes_yoko_device::set_chr() -{ - chr2_0(m_reg[4], CHRROM); - chr2_2(m_reg[5], CHRROM); - chr2_4(m_reg[6], CHRROM); - chr2_6(m_reg[7], CHRROM); -} - -WRITE8_MEMBER(nes_yoko_device::write_h) -{ - LOG_MMC(("yoko write_h, offset: %04x, data: %02x\n", offset, data)); - - switch (offset & 0x0c17) - { - case 0x0000: - m_extra2 = data; - set_prg(); - break; - case 0x400: - m_extra1 = data; - if (data & 1) - set_nt_mirroring(PPU_MIRROR_HORZ); - else - set_nt_mirroring(PPU_MIRROR_VERT); - set_prg(); - break; - case 0x0800: - m_irq_count = (m_irq_count & 0xff00) | data; - break; - case 0x0801: - m_irq_enable = m_extra1 & 0x80; - m_irq_count = (data << 8) | (m_irq_count & 0xff); - break; - case 0x0c00: - case 0x0c01: - case 0x0c02: - m_reg[offset & 3] = data; - set_prg(); - break; - case 0x0c10: - case 0x0c11: - case 0x0c16: - case 0x0c17: - m_reg[4 + (offset & 3)] = data; - set_chr(); - break; - } -} diff --git a/src/devices/bus/nes/cony.cpp b/src/devices/bus/nes/cony.cpp new file mode 100644 index 00000000000..a64063ebc8a --- /dev/null +++ b/src/devices/bus/nes/cony.cpp @@ -0,0 +1,397 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for Cony/Yoko PCBs + + + Here we emulate the following PCBs + + * UNL-CONY [mapper 83] + * UNL-YOKO + + TODO: fix glitches and emulate properly the variants + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "cony.h" + +#include "cpu/m6502/m6502.h" + + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_CONY = &device_creator; +const device_type NES_YOKO = &device_creator; + + +nes_cony_device::nes_cony_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +nes_cony_device::nes_cony_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_CONY, "NES Cart Cony PCB", tag, owner, clock, "nes_cony", __FILE__) +{ +} + +nes_yoko_device::nes_yoko_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_cony_device(mconfig, NES_YOKO, "NES Cart Yoko PCB", tag, owner, clock, "nes_yoko", __FILE__) +{ +} + + + + +void nes_cony_device::device_start() +{ + common_start(); + irq_timer = timer_alloc(TIMER_IRQ); + irq_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1)); + + save_item(NAME(m_irq_enable)); + save_item(NAME(m_irq_count)); + + save_item(NAME(m_low_reg)); + save_item(NAME(m_reg)); + save_item(NAME(m_extra1)); + save_item(NAME(m_latch1)); + save_item(NAME(m_latch2)); +} + +void nes_cony_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg8_cd(0x1e); + prg8_ef(0x1f); + chr8(0, m_chr_source); + + m_irq_enable = 0; + m_irq_count = 0; + + m_latch1 = 0; + m_latch2 = 0; + m_extra1 = 0; + + memset(m_low_reg, 0, sizeof(m_low_reg)); + memset(m_reg, 0, sizeof(m_reg)); + m_reg[9] = 0x0f; +} + +void nes_yoko_device::device_start() +{ + common_start(); + irq_timer = timer_alloc(TIMER_IRQ); + irq_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1)); + + save_item(NAME(m_irq_enable)); + save_item(NAME(m_irq_count)); + + save_item(NAME(m_low_reg)); + save_item(NAME(m_reg)); + save_item(NAME(m_extra1)); + save_item(NAME(m_extra2)); + save_item(NAME(m_latch1)); + save_item(NAME(m_latch2)); +} + +void nes_yoko_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg8_cd(0x1e); + prg8_ef(0x1f); + chr8(0, m_chr_source); + + m_irq_enable = 0; + m_irq_count = 0; + + m_latch1 = 0; + m_latch2 = 0; + m_extra1 = 0; + m_extra2 = 0; + + memset(m_low_reg, 0, sizeof(m_low_reg)); + memset(m_reg, 0, sizeof(m_reg)); + m_reg[9] = 0x0f; +} + + + + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + Cony Bootleg Board + + Games: Dragon Ball Party, Fatal Fury 2, Street Blaster II + Pro, World Heroes 2 + + iNES: mapper 83 + + In MESS: Supported. + + -------------------------------------------------*/ + +void nes_cony_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (id == TIMER_IRQ) + { + if (m_irq_enable) + { + if (!m_irq_count) + { + m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE); + m_irq_enable = 0; + m_irq_count = 0xffff; + } + else + m_irq_count--; + } + } +} + +WRITE8_MEMBER(nes_cony_device::write_l) +{ + LOG_MMC(("cony write_l, offset: %04x, data: %02x\n", offset, data)); + + if (offset >= 0x1000 && offset < 0x1103) // from 0x5100-0x51ff + m_low_reg[offset & 0x03] = data; +} + +READ8_MEMBER(nes_cony_device::read_l) +{ + LOG_MMC(("cony read_l, offset: %04x\n", offset)); + + if (offset == 0x0f00) // 0x5000 + { + // read dipswitch bit! - currently unimplemented + } + if (offset >= 0x1000 && offset < 0x1103) // from 0x5100-0x51ff + return m_low_reg[offset & 0x03]; + else + return 0x00; +} + +void nes_cony_device::set_prg() +{ + prg16_89ab(m_reg[8] & 0x3f); + prg16_cdef((m_reg[8] & 0x30) | 0x0f); +} + +void nes_cony_device::set_chr() +{ + // FIXME: here we emulate at least 3 different boards!!! + // one board switches 1k VROM banks only + // one writes to 0x8000 and then switches 2k VROM banks only + // one writes to 0x831n (n=2,3,4,5) and then switches 2k VROM banks only + // we should split them and possibly document the proper behavior of each variant + if (m_latch1 && !m_latch2) + { + chr2_0(m_reg[0], CHRROM); + chr2_2(m_reg[1], CHRROM); + chr2_4(m_reg[6], CHRROM); + chr2_6(m_reg[7], CHRROM); + } + else + { + chr1_0(m_reg[0] | ((m_reg[8] & 0x30) << 4), CHRROM); + chr1_1(m_reg[1] | ((m_reg[8] & 0x30) << 4), CHRROM); + chr1_2(m_reg[2] | ((m_reg[8] & 0x30) << 4), CHRROM); + chr1_3(m_reg[3] | ((m_reg[8] & 0x30) << 4), CHRROM); + chr1_4(m_reg[4] | ((m_reg[8] & 0x30) << 4), CHRROM); + chr1_5(m_reg[5] | ((m_reg[8] & 0x30) << 4), CHRROM); + chr1_6(m_reg[6] | ((m_reg[8] & 0x30) << 4), CHRROM); + chr1_7(m_reg[7] | ((m_reg[8] & 0x30) << 4), CHRROM); + } +} + +WRITE8_MEMBER(nes_cony_device::write_h) +{ + LOG_MMC(("cony write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset) + { + case 0x0000: + m_latch1 = 1; + case 0x3000: + case 0x30ff: + case 0x31ff: + m_reg[8] = data; + set_prg(); + set_chr(); + break; + case 0x0100: + m_extra1 = data & 0x80; + switch (data & 0x03) + { + case 0: + set_nt_mirroring(PPU_MIRROR_VERT); + break; + case 1: + set_nt_mirroring(PPU_MIRROR_HORZ); + break; + case 2: + set_nt_mirroring(PPU_MIRROR_LOW); + break; + case 3: + set_nt_mirroring(PPU_MIRROR_HIGH); + break; + } + break; + case 0x0200: + m_irq_count = (m_irq_count & 0xff00) | data; + break; + case 0x0201: + m_irq_enable = m_extra1; + m_irq_count = (data << 8) | (m_irq_count & 0xff); + break; + case 0x0300: + prg8_89(data); + break; + case 0x0301: + prg8_ab(data); + break; + case 0x0302: + prg8_cd(data); + break; + case 0x0312: + case 0x0313: + case 0x0314: + case 0x0315: + m_latch2 = 1; + case 0x0310: + case 0x0311: + case 0x0316: + case 0x0317: + m_reg[offset - 0x0310] = data; + set_chr(); + break; + case 0x0318: + m_reg[9] = data; // unused? + set_prg(); + break; + } +} + +/*------------------------------------------------- + + Yoko Bootleg Board + + Games: Mortal Kombat II, Master Figther VI' + + + Very similar to Cony board + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_yoko_device::write_l) +{ + LOG_MMC(("yoko write_l, offset: %04x, data: %02x\n", offset, data)); + + if (offset >= 0x1300) // from 0x5400 + m_low_reg[offset & 0x03] = data; +} + +READ8_MEMBER(nes_yoko_device::read_l) +{ + LOG_MMC(("yoko read_l, offset: %04x\n", offset)); + + if (offset >= 0x0f00 && offset < 0x1300) // 0x5000 + { + // read dipswitch bit! - currently unimplemented + } + if (offset >= 0x1300) // from 0x5400 + return m_low_reg[offset & 0x03]; + else + return 0x00; +} + +void nes_yoko_device::set_prg() +{ + if (m_extra1 & 0x10) + { + int base = (m_extra2 & 0x08) << 1; + prg8_89(base | (m_reg[0] & 0x0f)); + prg8_ab(base | (m_reg[1] & 0x0f)); + prg8_cd(base | (m_reg[2] & 0x0f)); + prg8_ef(base | 0x0f); + } + else if (m_extra1 & 0x08) + prg32(m_extra2 >> 1); + else + { + prg16_89ab(m_extra2); + prg16_cdef(0xff); + } +} + +void nes_yoko_device::set_chr() +{ + chr2_0(m_reg[4], CHRROM); + chr2_2(m_reg[5], CHRROM); + chr2_4(m_reg[6], CHRROM); + chr2_6(m_reg[7], CHRROM); +} + +WRITE8_MEMBER(nes_yoko_device::write_h) +{ + LOG_MMC(("yoko write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x0c17) + { + case 0x0000: + m_extra2 = data; + set_prg(); + break; + case 0x400: + m_extra1 = data; + if (data & 1) + set_nt_mirroring(PPU_MIRROR_HORZ); + else + set_nt_mirroring(PPU_MIRROR_VERT); + set_prg(); + break; + case 0x0800: + m_irq_count = (m_irq_count & 0xff00) | data; + break; + case 0x0801: + m_irq_enable = m_extra1 & 0x80; + m_irq_count = (data << 8) | (m_irq_count & 0xff); + break; + case 0x0c00: + case 0x0c01: + case 0x0c02: + m_reg[offset & 3] = data; + set_prg(); + break; + case 0x0c10: + case 0x0c11: + case 0x0c16: + case 0x0c17: + m_reg[4 + (offset & 3)] = data; + set_chr(); + break; + } +} diff --git a/src/devices/bus/nes/datach.c b/src/devices/bus/nes/datach.c deleted file mode 100644 index 1bf562976ed..00000000000 --- a/src/devices/bus/nes/datach.c +++ /dev/null @@ -1,420 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Fabio Priuli -/*********************************************************************************************************** - - - NES/Famicom cartridge emulation for Bandai Datach PCBs - - - Here we emulate the Bandai Datach Joint ROM System [mapper 157]. - The base unit features: a Bandai LZ93D50 + 24C02 EEPROM PCB - + barcode reader + subslot for PRG cart - - - ***********************************************************************************************************/ - - -#include "emu.h" -#include "datach.h" -#include "cpu/m6502/m6502.h" - -#ifdef NES_PCB_DEBUG -#define VERBOSE 1 -#else -#define VERBOSE 0 -#endif - -#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) - -#define EEPROM_INTERNAL 0 -#define EEPROM_EXTERNAL 1 - - -#define TEST_EEPROM 0 - -//-------------------------------- -// -// Datach Cartslot implementation -// -//-------------------------------- - -//------------------------------------------------- -// sub-cart interface -//------------------------------------------------- - -datach_cart_interface::datach_cart_interface(const machine_config &mconfig, device_t &device) - : device_slot_card_interface(mconfig, device), - m_i2cmem(*this, "i2cmem"), - m_rom(NULL) -{ -} - -datach_cart_interface::~datach_cart_interface() -{ -} - -READ8_MEMBER(datach_cart_interface::read) -{ - if (offset < 0x4000) - return m_rom[(m_bank * 0x4000) + (offset & 0x3fff)]; - else - return m_rom[(0x0f * 0x4000) + (offset & 0x3fff)]; -} - -//------------------------------------------------- -// sub-cart slot device -//------------------------------------------------- - -const device_type NES_DATACH_SLOT = &device_creator; - -nes_datach_slot_device::nes_datach_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : - device_t(mconfig, NES_DATACH_SLOT, "NES Datach Cartridge Slot", tag, owner, clock, "nes_datach_slot", __FILE__), - device_image_interface(mconfig, *this), - device_slot_interface(mconfig, *this) -{ -} - -nes_datach_slot_device::~nes_datach_slot_device() -{ -} - - -void nes_datach_slot_device::device_start() -{ - m_cart = dynamic_cast(get_card_device()); -} - -READ8_MEMBER(nes_datach_slot_device::read) -{ - if (m_cart) - return m_cart->read(space, offset, mem_mask); - - return 0xff; -} - -bool nes_datach_slot_device::call_load() -{ - if (m_cart) - { - UINT8 *ROM = m_cart->get_cart_base(); - - if (!ROM) - return IMAGE_INIT_FAIL; - - // Existing Datach carts are all 256K, so we only load files of this size - if (software_entry() == NULL) - { - if (length() != 0x40000 && length() != 0x40010) - return IMAGE_INIT_FAIL; - - int shift = length() - 0x40000; - UINT8 temp[0x40010]; - fread(&temp, length()); - memcpy(ROM, temp + shift, 0x40000); - - // double check that iNES files are really mapper 157 - // (or 16, since some older .nes files marked Datach as mapper 16) - if (length() == 0x40010) - { - UINT8 mapper = (temp[6] & 0xf0) >> 4; - mapper |= temp[7] & 0xf0; - if (mapper != 157 && mapper != 16) - { - return IMAGE_INIT_FAIL; - } - } - } - else - { - if (get_software_region_length("rom") != 0x40000) - return IMAGE_INIT_FAIL; - - memcpy(ROM, get_software_region("rom"), 0x40000); - } - } - - return IMAGE_INIT_PASS; -} - - -bool nes_datach_slot_device::call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry) -{ - load_software_part_region(*this, swlist, swname, start_entry ); - return TRUE; -} - -void nes_datach_slot_device::get_default_card_software(std::string &result) -{ - // any way to detect the game with X24C01? - software_get_default_slot(result, "datach_rom"); -} - - -//-------------------------------- -// -// Datach Minicart implementation -// -// Two kinds of PCB exist -// * ROM only, used by most games -// * ROM + X24C01 EEPROM, used by -// Battle Rush -// -//-------------------------------- - -ROM_START( datach_rom ) - ROM_REGION(0x40000, "datachrom", ROMREGION_ERASEFF) -ROM_END - -const device_type NES_DATACH_ROM = &device_creator; -const device_type NES_DATACH_24C01 = &device_creator; - -nes_datach_rom_device::nes_datach_rom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) - : device_t(mconfig, type, name, tag, owner, clock, shortname, source), - datach_cart_interface( mconfig, *this ) -{ -} - -nes_datach_rom_device::nes_datach_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : device_t(mconfig, NES_DATACH_ROM, "NES Datach ROM", tag, owner, clock, "nes_datach_rom", __FILE__), - datach_cart_interface( mconfig, *this ) -{ -} - -nes_datach_24c01_device::nes_datach_24c01_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_datach_rom_device(mconfig, NES_DATACH_24C01, "NES Datach + 24C01 PCB", tag, owner, clock, "nes_datach_ep1", __FILE__) -{ -} - - -void nes_datach_rom_device::device_start() -{ - m_rom = (UINT8*)memregion("datachrom")->base(); - save_item(NAME(m_bank)); -} - -void nes_datach_rom_device::device_reset() -{ - m_bank = 0; -} - -const rom_entry *nes_datach_rom_device::device_rom_region() const -{ - return ROM_NAME( datach_rom ); -} - -UINT8 *nes_datach_rom_device::get_cart_base() -{ - return m_rom; -} - - -MACHINE_CONFIG_FRAGMENT( subcart_i2c_24c01 ) - MCFG_24C01_ADD("i2cmem") -MACHINE_CONFIG_END - -machine_config_constructor nes_datach_24c01_device::device_mconfig_additions() const -{ - return MACHINE_CONFIG_NAME( subcart_i2c_24c01 ); -} - - -//--------------------------------- -// -// Datach Base Unit implementation -// -//--------------------------------- - -const device_type NES_DATACH = &device_creator; - - -nes_datach_device::nes_datach_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_lz93d50_device(mconfig, NES_DATACH, "NES Cart Bandai Datach PCB", tag, owner, clock, "nes_datach", __FILE__), - m_i2cmem(*this, "i2cmem"), - m_reader(*this, "datach"), - m_subslot(*this, "datach_slot") -{ -} - - -void nes_datach_device::device_start() -{ - common_start(); - irq_timer = timer_alloc(TIMER_IRQ); - serial_timer = timer_alloc(TIMER_SERIAL); - irq_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1)); - serial_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1000)); - - save_item(NAME(m_irq_enable)); - save_item(NAME(m_irq_count)); - save_item(NAME(m_datach_latch)); -} - -void nes_datach_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(0); - prg16_cdef(m_prg_chunks - 1); - chr8(0, m_chr_source); - - m_irq_enable = 0; - m_irq_count = 0; - m_datach_latch = 0; - m_i2c_in_use = EEPROM_INTERNAL; -} - - -/*------------------------------------------------- - mapper specific handlers - -------------------------------------------------*/ - -/*------------------------------------------------- - - Bandai LZ93D50 + Datach barcode reader emulation - - Games: Datach Games - - iNES: mappers 157 - - In MESS: Supported - - TODO: Datach carts should actually be handled - separately! Original carts were minicarts to be - inserted in a smaller slot of the Barcode reader - FC cart. The Barcode reader acts as a passthrough - but it has no internal ROM (it does not work if - you don't have any minicart inserted) - - TODO2: This class should be derived from the - LZ93D50 + X24C02 class, since the main board - has this EEPROM. Moreover, Datach - Battle Rush - has a second X24C01 EEPROM that we don't emulate yet... - - -------------------------------------------------*/ - - -READ8_MEMBER(nes_datach_device::read_m) -{ - LOG_MMC(("Datach read_m, offset: %04x\n", offset)); - UINT8 i2c_val = 0; -#if TEST_EEPROM - if (m_i2c_dir) - { - if (m_i2c_in_use == EEPROM_INTERNAL) - i2c_val = (m_i2cmem->read_sda() & 1) << 4; - if (m_i2c_in_use == EEPROM_EXTERNAL && m_subslot->m_cart && m_subslot->m_cart->m_i2cmem) - i2c_val = (m_subslot->m_cart->m_i2cmem->read_sda() & 1) << 4; - } -#endif - return m_datach_latch | i2c_val; -} - - -READ8_MEMBER(nes_datach_device::read_h) -{ - LOG_MMC(("Datach read_h, offset: %04x\n", offset)); - // this shall be the proper code, but it's a bit slower, so we access directly the subcart below - //return m_subslot->read(space, offset, mem_mask); - - if (m_subslot->m_cart) - return m_subslot->m_cart->read(space, offset, mem_mask); - else // this is "fake" in the sense that we fill CPU space with 0xff if no Datach cart is loaded - return hi_access_rom(offset); -} - -WRITE8_MEMBER(nes_datach_device::write_h) -{ - LOG_MMC(("Datach write_h, offset: %04x, data: %02x\n", offset, data)); - - switch (offset & 0x0f) - { - case 0: case 1: case 2: case 3: - case 4: case 5: case 6: case 7: - // these don't switch CHR bank (if you try this, both Battle Rush and SD Gundam Wars will have glitches!) - // bit3 goes to SCL of the external EEPROM (and we use write=1 to enable reading from this EEPROM) - // docs from naruko don't specify the bit, our choice comes from observation of writes performed by Battle Rush -#if TEST_EEPROM - if (m_subslot->m_cart && m_subslot->m_cart->m_i2cmem) - { - if (BIT(data, 3)) - m_i2c_in_use = EEPROM_EXTERNAL; - m_subslot->m_cart->m_i2cmem->write_scl(BIT(data, 3)); - } -#endif - break; - case 0x08: - m_subslot->write_prg_bank(data & 0x0f); - break; - case 0x0d: -#if TEST_EEPROM - // bit7, select SDA direction LZ93D50P -> EEPROM or EEPROM -> LZ93D50P - m_i2c_dir = BIT(data, 7); - - // bit6 goes to SDA line, which is in common with the 2nd EEPROM, if present - m_i2cmem->write_sda(BIT(data, 6)); - if (m_subslot->m_cart && m_subslot->m_cart->m_i2cmem) - m_subslot->m_cart->m_i2cmem->write_sda(BIT(data, 6)); - - // bit5 goes to SCL of the internal EEPROM (and we use write=1 to enable reading from this EEPROM) - if (BIT(data, 5)) - m_i2c_in_use = EEPROM_INTERNAL; - m_i2cmem->write_scl(BIT(data, 5)); -#endif - break; - default: - fcg_write(space, offset & 0x0f, data, mem_mask); - break; - } -} - -//------------------------------------------------- -// BARCODE READER + CART SLOT + X24C02 -//------------------------------------------------- - -static SLOT_INTERFACE_START(datach_cart) - SLOT_INTERFACE_INTERNAL("datach_rom", NES_DATACH_ROM) - SLOT_INTERFACE_INTERNAL("datach_ep1", NES_DATACH_24C01) -SLOT_INTERFACE_END - - -MACHINE_CONFIG_FRAGMENT( bandai_datach ) - MCFG_BARCODE_READER_ADD("datach") - MCFG_DATACH_MINICART_ADD("datach_slot", datach_cart) - MCFG_24C02_ADD("i2cmem") -MACHINE_CONFIG_END - -machine_config_constructor nes_datach_device::device_mconfig_additions() const -{ - return MACHINE_CONFIG_NAME( bandai_datach ); -} - - -//------------------------------------------------- -// device_timer - handler timer events -//------------------------------------------------- - -void nes_datach_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) -{ - if (id == TIMER_IRQ) - { - if (m_irq_enable) - { - // 16bit counter, IRQ fired when the counter goes from 1 to 0 - // after firing, the counter is *not* reloaded, but next clock - // counter wraps around from 0 to 0xffff - if (!m_irq_count) - m_irq_count = 0xffff; - else - m_irq_count--; - - if (!m_irq_count) - { - m_maincpu->set_input_line(M6502_IRQ_LINE, ASSERT_LINE); - m_irq_enable = 0; - } - } - } - if (id == TIMER_SERIAL) - { - m_datach_latch = (m_reader->read_pixel() << 3); - } -} diff --git a/src/devices/bus/nes/datach.cpp b/src/devices/bus/nes/datach.cpp new file mode 100644 index 00000000000..1bf562976ed --- /dev/null +++ b/src/devices/bus/nes/datach.cpp @@ -0,0 +1,420 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for Bandai Datach PCBs + + + Here we emulate the Bandai Datach Joint ROM System [mapper 157]. + The base unit features: a Bandai LZ93D50 + 24C02 EEPROM PCB + + barcode reader + subslot for PRG cart + + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "datach.h" +#include "cpu/m6502/m6502.h" + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + +#define EEPROM_INTERNAL 0 +#define EEPROM_EXTERNAL 1 + + +#define TEST_EEPROM 0 + +//-------------------------------- +// +// Datach Cartslot implementation +// +//-------------------------------- + +//------------------------------------------------- +// sub-cart interface +//------------------------------------------------- + +datach_cart_interface::datach_cart_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig, device), + m_i2cmem(*this, "i2cmem"), + m_rom(NULL) +{ +} + +datach_cart_interface::~datach_cart_interface() +{ +} + +READ8_MEMBER(datach_cart_interface::read) +{ + if (offset < 0x4000) + return m_rom[(m_bank * 0x4000) + (offset & 0x3fff)]; + else + return m_rom[(0x0f * 0x4000) + (offset & 0x3fff)]; +} + +//------------------------------------------------- +// sub-cart slot device +//------------------------------------------------- + +const device_type NES_DATACH_SLOT = &device_creator; + +nes_datach_slot_device::nes_datach_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, NES_DATACH_SLOT, "NES Datach Cartridge Slot", tag, owner, clock, "nes_datach_slot", __FILE__), + device_image_interface(mconfig, *this), + device_slot_interface(mconfig, *this) +{ +} + +nes_datach_slot_device::~nes_datach_slot_device() +{ +} + + +void nes_datach_slot_device::device_start() +{ + m_cart = dynamic_cast(get_card_device()); +} + +READ8_MEMBER(nes_datach_slot_device::read) +{ + if (m_cart) + return m_cart->read(space, offset, mem_mask); + + return 0xff; +} + +bool nes_datach_slot_device::call_load() +{ + if (m_cart) + { + UINT8 *ROM = m_cart->get_cart_base(); + + if (!ROM) + return IMAGE_INIT_FAIL; + + // Existing Datach carts are all 256K, so we only load files of this size + if (software_entry() == NULL) + { + if (length() != 0x40000 && length() != 0x40010) + return IMAGE_INIT_FAIL; + + int shift = length() - 0x40000; + UINT8 temp[0x40010]; + fread(&temp, length()); + memcpy(ROM, temp + shift, 0x40000); + + // double check that iNES files are really mapper 157 + // (or 16, since some older .nes files marked Datach as mapper 16) + if (length() == 0x40010) + { + UINT8 mapper = (temp[6] & 0xf0) >> 4; + mapper |= temp[7] & 0xf0; + if (mapper != 157 && mapper != 16) + { + return IMAGE_INIT_FAIL; + } + } + } + else + { + if (get_software_region_length("rom") != 0x40000) + return IMAGE_INIT_FAIL; + + memcpy(ROM, get_software_region("rom"), 0x40000); + } + } + + return IMAGE_INIT_PASS; +} + + +bool nes_datach_slot_device::call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry) +{ + load_software_part_region(*this, swlist, swname, start_entry ); + return TRUE; +} + +void nes_datach_slot_device::get_default_card_software(std::string &result) +{ + // any way to detect the game with X24C01? + software_get_default_slot(result, "datach_rom"); +} + + +//-------------------------------- +// +// Datach Minicart implementation +// +// Two kinds of PCB exist +// * ROM only, used by most games +// * ROM + X24C01 EEPROM, used by +// Battle Rush +// +//-------------------------------- + +ROM_START( datach_rom ) + ROM_REGION(0x40000, "datachrom", ROMREGION_ERASEFF) +ROM_END + +const device_type NES_DATACH_ROM = &device_creator; +const device_type NES_DATACH_24C01 = &device_creator; + +nes_datach_rom_device::nes_datach_rom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + datach_cart_interface( mconfig, *this ) +{ +} + +nes_datach_rom_device::nes_datach_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, NES_DATACH_ROM, "NES Datach ROM", tag, owner, clock, "nes_datach_rom", __FILE__), + datach_cart_interface( mconfig, *this ) +{ +} + +nes_datach_24c01_device::nes_datach_24c01_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_datach_rom_device(mconfig, NES_DATACH_24C01, "NES Datach + 24C01 PCB", tag, owner, clock, "nes_datach_ep1", __FILE__) +{ +} + + +void nes_datach_rom_device::device_start() +{ + m_rom = (UINT8*)memregion("datachrom")->base(); + save_item(NAME(m_bank)); +} + +void nes_datach_rom_device::device_reset() +{ + m_bank = 0; +} + +const rom_entry *nes_datach_rom_device::device_rom_region() const +{ + return ROM_NAME( datach_rom ); +} + +UINT8 *nes_datach_rom_device::get_cart_base() +{ + return m_rom; +} + + +MACHINE_CONFIG_FRAGMENT( subcart_i2c_24c01 ) + MCFG_24C01_ADD("i2cmem") +MACHINE_CONFIG_END + +machine_config_constructor nes_datach_24c01_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( subcart_i2c_24c01 ); +} + + +//--------------------------------- +// +// Datach Base Unit implementation +// +//--------------------------------- + +const device_type NES_DATACH = &device_creator; + + +nes_datach_device::nes_datach_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_lz93d50_device(mconfig, NES_DATACH, "NES Cart Bandai Datach PCB", tag, owner, clock, "nes_datach", __FILE__), + m_i2cmem(*this, "i2cmem"), + m_reader(*this, "datach"), + m_subslot(*this, "datach_slot") +{ +} + + +void nes_datach_device::device_start() +{ + common_start(); + irq_timer = timer_alloc(TIMER_IRQ); + serial_timer = timer_alloc(TIMER_SERIAL); + irq_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1)); + serial_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1000)); + + save_item(NAME(m_irq_enable)); + save_item(NAME(m_irq_count)); + save_item(NAME(m_datach_latch)); +} + +void nes_datach_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + + m_irq_enable = 0; + m_irq_count = 0; + m_datach_latch = 0; + m_i2c_in_use = EEPROM_INTERNAL; +} + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + Bandai LZ93D50 + Datach barcode reader emulation + + Games: Datach Games + + iNES: mappers 157 + + In MESS: Supported + + TODO: Datach carts should actually be handled + separately! Original carts were minicarts to be + inserted in a smaller slot of the Barcode reader + FC cart. The Barcode reader acts as a passthrough + but it has no internal ROM (it does not work if + you don't have any minicart inserted) + + TODO2: This class should be derived from the + LZ93D50 + X24C02 class, since the main board + has this EEPROM. Moreover, Datach - Battle Rush + has a second X24C01 EEPROM that we don't emulate yet... + + -------------------------------------------------*/ + + +READ8_MEMBER(nes_datach_device::read_m) +{ + LOG_MMC(("Datach read_m, offset: %04x\n", offset)); + UINT8 i2c_val = 0; +#if TEST_EEPROM + if (m_i2c_dir) + { + if (m_i2c_in_use == EEPROM_INTERNAL) + i2c_val = (m_i2cmem->read_sda() & 1) << 4; + if (m_i2c_in_use == EEPROM_EXTERNAL && m_subslot->m_cart && m_subslot->m_cart->m_i2cmem) + i2c_val = (m_subslot->m_cart->m_i2cmem->read_sda() & 1) << 4; + } +#endif + return m_datach_latch | i2c_val; +} + + +READ8_MEMBER(nes_datach_device::read_h) +{ + LOG_MMC(("Datach read_h, offset: %04x\n", offset)); + // this shall be the proper code, but it's a bit slower, so we access directly the subcart below + //return m_subslot->read(space, offset, mem_mask); + + if (m_subslot->m_cart) + return m_subslot->m_cart->read(space, offset, mem_mask); + else // this is "fake" in the sense that we fill CPU space with 0xff if no Datach cart is loaded + return hi_access_rom(offset); +} + +WRITE8_MEMBER(nes_datach_device::write_h) +{ + LOG_MMC(("Datach write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x0f) + { + case 0: case 1: case 2: case 3: + case 4: case 5: case 6: case 7: + // these don't switch CHR bank (if you try this, both Battle Rush and SD Gundam Wars will have glitches!) + // bit3 goes to SCL of the external EEPROM (and we use write=1 to enable reading from this EEPROM) + // docs from naruko don't specify the bit, our choice comes from observation of writes performed by Battle Rush +#if TEST_EEPROM + if (m_subslot->m_cart && m_subslot->m_cart->m_i2cmem) + { + if (BIT(data, 3)) + m_i2c_in_use = EEPROM_EXTERNAL; + m_subslot->m_cart->m_i2cmem->write_scl(BIT(data, 3)); + } +#endif + break; + case 0x08: + m_subslot->write_prg_bank(data & 0x0f); + break; + case 0x0d: +#if TEST_EEPROM + // bit7, select SDA direction LZ93D50P -> EEPROM or EEPROM -> LZ93D50P + m_i2c_dir = BIT(data, 7); + + // bit6 goes to SDA line, which is in common with the 2nd EEPROM, if present + m_i2cmem->write_sda(BIT(data, 6)); + if (m_subslot->m_cart && m_subslot->m_cart->m_i2cmem) + m_subslot->m_cart->m_i2cmem->write_sda(BIT(data, 6)); + + // bit5 goes to SCL of the internal EEPROM (and we use write=1 to enable reading from this EEPROM) + if (BIT(data, 5)) + m_i2c_in_use = EEPROM_INTERNAL; + m_i2cmem->write_scl(BIT(data, 5)); +#endif + break; + default: + fcg_write(space, offset & 0x0f, data, mem_mask); + break; + } +} + +//------------------------------------------------- +// BARCODE READER + CART SLOT + X24C02 +//------------------------------------------------- + +static SLOT_INTERFACE_START(datach_cart) + SLOT_INTERFACE_INTERNAL("datach_rom", NES_DATACH_ROM) + SLOT_INTERFACE_INTERNAL("datach_ep1", NES_DATACH_24C01) +SLOT_INTERFACE_END + + +MACHINE_CONFIG_FRAGMENT( bandai_datach ) + MCFG_BARCODE_READER_ADD("datach") + MCFG_DATACH_MINICART_ADD("datach_slot", datach_cart) + MCFG_24C02_ADD("i2cmem") +MACHINE_CONFIG_END + +machine_config_constructor nes_datach_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( bandai_datach ); +} + + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +void nes_datach_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (id == TIMER_IRQ) + { + if (m_irq_enable) + { + // 16bit counter, IRQ fired when the counter goes from 1 to 0 + // after firing, the counter is *not* reloaded, but next clock + // counter wraps around from 0 to 0xffff + if (!m_irq_count) + m_irq_count = 0xffff; + else + m_irq_count--; + + if (!m_irq_count) + { + m_maincpu->set_input_line(M6502_IRQ_LINE, ASSERT_LINE); + m_irq_enable = 0; + } + } + } + if (id == TIMER_SERIAL) + { + m_datach_latch = (m_reader->read_pixel() << 3); + } +} diff --git a/src/devices/bus/nes/discrete.c b/src/devices/bus/nes/discrete.c deleted file mode 100644 index e0109a84d94..00000000000 --- a/src/devices/bus/nes/discrete.c +++ /dev/null @@ -1,209 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Fabio Priuli -/*********************************************************************************************************** - - - NES/Famicom cartridge emulation for PCBs mostly based on discrete components - - Here we emulate the following PCBs - - * PCB with IC 74x161x161x32 [mapper 70 & 152] - * PCB with IC 74x139x74 [mapper 87] - * PCB with IC 74x377 [mapper 11] - * PCB with IC 74x161x138 [mapper 38] - - TODO: - - Investigating missing inputs in Crime Busters - - ***********************************************************************************************************/ - - -#include "emu.h" -#include "discrete.h" - - -#ifdef NES_PCB_DEBUG -#define VERBOSE 1 -#else -#define VERBOSE 0 -#endif - -#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) - - -//------------------------------------------------- -// constructor -//------------------------------------------------- - -const device_type NES_74X161X161X32 = &device_creator; -const device_type NES_74X139X74 = &device_creator; -const device_type NES_74X377 = &device_creator; -const device_type NES_74X161X138 = &device_creator; - - -nes_74x161x161x32_device::nes_74x161x161x32_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_74X161X161X32, "NES Cart Discrete Logic (74*161/161/32) PCB", tag, owner, clock, "nes_74x161", __FILE__) -{ -} - -nes_74x139x74_device::nes_74x139x74_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_74X139X74, "NES Cart Discrete Logic (74*139/74) PCB", tag, owner, clock, "nes_74x139", __FILE__) -{ -} - -nes_74x377_device::nes_74x377_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_74X377, "NES Cart Discrete Logic (74*377) PCB", tag, owner, clock, "nes_74x377", __FILE__) -{ -} - -nes_74x161x138_device::nes_74x161x138_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_74X161X138, "NES Cart Discrete Logic (74*161/138) PCB", tag, owner, clock, "nes_bitcorp_dis", __FILE__) -{ -} - - - - -void nes_74x161x161x32_device::device_start() -{ - common_start(); -} - -void nes_74x161x161x32_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(0); - prg16_cdef(m_prg_chunks - 1); - chr8(0, m_chr_source); -} - -void nes_74x139x74_device::device_start() -{ - common_start(); -} - -void nes_74x139x74_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(0); - prg16_cdef(m_prg_chunks - 1); - chr8(0, m_chr_source); -} - -void nes_74x377_device::device_start() -{ - common_start(); -} - -void nes_74x377_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0); - chr8(0, m_chr_source); -} - -void nes_74x161x138_device::device_start() -{ - common_start(); -} - -void nes_74x161x138_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0); - chr8(0, m_chr_source); -} - - - - -/*------------------------------------------------- - mapper specific handlers - -------------------------------------------------*/ - -/*------------------------------------------------- - - Discrete Logic board IC 74x161x161x32 - - There are two variants (one with hardwired mirroring, the - other with a mirroring control), making necessary two distinct - mappers & pcb_id - - iNES: mappers 70 & 152 - - -------------------------------------------------*/ - -// there are two 'variants' depending on hardwired or mapper ctrl mirroring -WRITE8_MEMBER(nes_74x161x161x32_device::write_h) -{ - LOG_MMC(("74x161x161x32 write_h, offset: %04x, data: %02x\n", offset, data)); - - // this pcb is subject to bus conflict - data = account_bus_conflict(offset, data); - - if (m_pcb_ctrl_mirror) - set_nt_mirroring(BIT(data, 7) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW); - chr8(data, CHRROM); - prg16_89ab(data >> 4); -} - -/*------------------------------------------------- - - Discrete Logic board IC 74x139x74 by Konami & Jaleco - - iNES: mapper 87 - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_74x139x74_device::write_m) -{ - LOG_MMC(("74x139x74 write_m, offset: %04x, data: %02x\n", offset, data)); - - chr8(((data & 0x02) >> 1) | ((data & 0x01) << 1), CHRROM); -} - -/*------------------------------------------------- - - Discrete Logic board IC 74x377 by Color Dreams / Nina-007 emulation - - Games: many Color Dreams and Wisdom Tree titles - - iNES: mapper 11 - - In MESS: Supported - - Note: bit2 & bit3 are actually related to CIC lockout - defeating, and real Color Dreams titles use only - bit0 & bit1 for PRG switching. Our usage allows for support - of extended PRG games (e.g. homebrew) - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_74x377_device::write_h) -{ - LOG_MMC(("74x377 write_h, offset: %04x, data: %02x\n", offset, data)); - - // this pcb is subject to bus conflict, but not the prototype of Secret Scout, which actually breaks in case of conflict... - data = account_bus_conflict(offset, data); - - chr8(data >> 4, m_chr_source); - prg32(data & 0x0f); -} - -/*------------------------------------------------- - - Discrete Logic board IC 74x161x138 - - Games: Crime Busters - - iNES: mapper 38 - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_74x161x138_device::write_m) -{ - LOG_MMC(("74x161x138 write_m, offset: %04x, data: %02x\n", offset, data)); - - chr8(data >> 2, CHRROM); - prg32(data); -} diff --git a/src/devices/bus/nes/discrete.cpp b/src/devices/bus/nes/discrete.cpp new file mode 100644 index 00000000000..e0109a84d94 --- /dev/null +++ b/src/devices/bus/nes/discrete.cpp @@ -0,0 +1,209 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for PCBs mostly based on discrete components + + Here we emulate the following PCBs + + * PCB with IC 74x161x161x32 [mapper 70 & 152] + * PCB with IC 74x139x74 [mapper 87] + * PCB with IC 74x377 [mapper 11] + * PCB with IC 74x161x138 [mapper 38] + + TODO: + - Investigating missing inputs in Crime Busters + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "discrete.h" + + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_74X161X161X32 = &device_creator; +const device_type NES_74X139X74 = &device_creator; +const device_type NES_74X377 = &device_creator; +const device_type NES_74X161X138 = &device_creator; + + +nes_74x161x161x32_device::nes_74x161x161x32_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_74X161X161X32, "NES Cart Discrete Logic (74*161/161/32) PCB", tag, owner, clock, "nes_74x161", __FILE__) +{ +} + +nes_74x139x74_device::nes_74x139x74_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_74X139X74, "NES Cart Discrete Logic (74*139/74) PCB", tag, owner, clock, "nes_74x139", __FILE__) +{ +} + +nes_74x377_device::nes_74x377_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_74X377, "NES Cart Discrete Logic (74*377) PCB", tag, owner, clock, "nes_74x377", __FILE__) +{ +} + +nes_74x161x138_device::nes_74x161x138_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_74X161X138, "NES Cart Discrete Logic (74*161/138) PCB", tag, owner, clock, "nes_bitcorp_dis", __FILE__) +{ +} + + + + +void nes_74x161x161x32_device::device_start() +{ + common_start(); +} + +void nes_74x161x161x32_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); +} + +void nes_74x139x74_device::device_start() +{ + common_start(); +} + +void nes_74x139x74_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); +} + +void nes_74x377_device::device_start() +{ + common_start(); +} + +void nes_74x377_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + +void nes_74x161x138_device::device_start() +{ + common_start(); +} + +void nes_74x161x138_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + + + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + Discrete Logic board IC 74x161x161x32 + + There are two variants (one with hardwired mirroring, the + other with a mirroring control), making necessary two distinct + mappers & pcb_id + + iNES: mappers 70 & 152 + + -------------------------------------------------*/ + +// there are two 'variants' depending on hardwired or mapper ctrl mirroring +WRITE8_MEMBER(nes_74x161x161x32_device::write_h) +{ + LOG_MMC(("74x161x161x32 write_h, offset: %04x, data: %02x\n", offset, data)); + + // this pcb is subject to bus conflict + data = account_bus_conflict(offset, data); + + if (m_pcb_ctrl_mirror) + set_nt_mirroring(BIT(data, 7) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW); + chr8(data, CHRROM); + prg16_89ab(data >> 4); +} + +/*------------------------------------------------- + + Discrete Logic board IC 74x139x74 by Konami & Jaleco + + iNES: mapper 87 + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_74x139x74_device::write_m) +{ + LOG_MMC(("74x139x74 write_m, offset: %04x, data: %02x\n", offset, data)); + + chr8(((data & 0x02) >> 1) | ((data & 0x01) << 1), CHRROM); +} + +/*------------------------------------------------- + + Discrete Logic board IC 74x377 by Color Dreams / Nina-007 emulation + + Games: many Color Dreams and Wisdom Tree titles + + iNES: mapper 11 + + In MESS: Supported + + Note: bit2 & bit3 are actually related to CIC lockout + defeating, and real Color Dreams titles use only + bit0 & bit1 for PRG switching. Our usage allows for support + of extended PRG games (e.g. homebrew) + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_74x377_device::write_h) +{ + LOG_MMC(("74x377 write_h, offset: %04x, data: %02x\n", offset, data)); + + // this pcb is subject to bus conflict, but not the prototype of Secret Scout, which actually breaks in case of conflict... + data = account_bus_conflict(offset, data); + + chr8(data >> 4, m_chr_source); + prg32(data & 0x0f); +} + +/*------------------------------------------------- + + Discrete Logic board IC 74x161x138 + + Games: Crime Busters + + iNES: mapper 38 + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_74x161x138_device::write_m) +{ + LOG_MMC(("74x161x138 write_m, offset: %04x, data: %02x\n", offset, data)); + + chr8(data >> 2, CHRROM); + prg32(data); +} diff --git a/src/devices/bus/nes/disksys.c b/src/devices/bus/nes/disksys.c deleted file mode 100644 index 45cb275e9de..00000000000 --- a/src/devices/bus/nes/disksys.c +++ /dev/null @@ -1,431 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Fabio Priuli -/*********************************************************************************************************** - - - NES/Famicom cartridge emulation for Disk System expansion - - - Here we emulate the RAM expansion + Disk Drive which form the - Famicom Disk System. - - Based on info from NESDev wiki ( http://wiki.nesdev.com/w/index.php/Family_Computer_Disk_System ) - - TODO: - - convert floppy drive + fds format to modern code! - - add sound bits - - stop IRQ from using HOLD_LINE - - ***********************************************************************************************************/ - - -#include "emu.h" -#include "disksys.h" -#include "cpu/m6502/m6502.h" -#include "imagedev/flopdrv.h" -#include "formats/nes_dsk.h" - -#ifdef NES_PCB_DEBUG - #define VERBOSE 1 -#else - #define VERBOSE 0 -#endif - -#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) - - -//----------------------------------------------- -// -// Disk drive implementation -// -//----------------------------------------------- - -static const floppy_interface nes_floppy_interface = -{ - FLOPPY_STANDARD_5_25_DSHD, - LEGACY_FLOPPY_OPTIONS_NAME(nes_only), - "floppy_5_25" -}; - -static MACHINE_CONFIG_FRAGMENT( nes_disksys ) - MCFG_LEGACY_FLOPPY_DRIVE_ADD(FLOPPY_0, nes_floppy_interface) -MACHINE_CONFIG_END - -//------------------------------------------------- -// machine_config_additions - device-specific -// machine configurations -//------------------------------------------------- - -machine_config_constructor nes_disksys_device::device_mconfig_additions() const -{ - return MACHINE_CONFIG_NAME( nes_disksys ); -} - - - -ROM_START( disksys ) - ROM_REGION(0x2000, "drive", 0) - ROM_SYSTEM_BIOS( 0, "2c33a-01a", "Famicom Disk System Bios") - ROMX_LOAD( "rp2c33a-01a.bin", 0x0000, 0x2000, CRC(5e607dcf) SHA1(57fe1bdee955bb48d357e463ccbf129496930b62), ROM_BIOS(1)) // newer, Nintendo logo has no shadow - ROM_SYSTEM_BIOS( 1, "2c33-01", "Famicom Disk System Bios, older") - ROMX_LOAD( "rp2c33-01.bin", 0x0000, 0x2000, CRC(1c7ae5d5) SHA1(af5af53f66982e749643fdf8b2acbb7d4d3ed229), ROM_BIOS(2)) // older, Nintendo logo has shadow -ROM_END - -//------------------------------------------------- -// rom_region - device-specific ROM region -//------------------------------------------------- - -const rom_entry *nes_disksys_device::device_rom_region() const -{ - return ROM_NAME( disksys ); -} - - -void nes_disksys_device::load_proc(device_image_interface &image) -{ - nes_disksys_device *disk_sys = static_cast(image.device().owner()); - disk_sys->load_disk(image); -} - -void nes_disksys_device::unload_proc(device_image_interface &image) -{ - nes_disksys_device *disk_sys = static_cast(image.device().owner()); - disk_sys->unload_disk(image); -} - - -//------------------------------------------------ -// -// RAM expansion cart implementation -// -//------------------------------------------------ - -const device_type NES_DISKSYS = &device_creator; - - -nes_disksys_device::nes_disksys_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_DISKSYS, "FC RAM Expansion + Disk System PCB", tag, owner, clock, "fc_disksys", __FILE__), - m_fds_data(NULL), - m_disk(*this, FLOPPY_0), - m_fds_sides(0) -{ -} - - -void nes_disksys_device::device_start() -{ - common_start(); - - m_2c33_rom = (UINT8*)memregion("drive")->base(); - - m_disk->floppy_install_load_proc(nes_disksys_device::load_proc); - m_disk->floppy_install_unload_proc(nes_disksys_device::unload_proc); - - irq_timer = timer_alloc(TIMER_IRQ); - irq_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1)); - - save_item(NAME(m_fds_motor_on)); - save_item(NAME(m_fds_door_closed)); - save_item(NAME(m_fds_current_side)); - save_item(NAME(m_fds_head_position)); - save_item(NAME(m_fds_status0)); - save_item(NAME(m_read_mode)); - save_item(NAME(m_drive_ready)); - save_item(NAME(m_irq_enable)); - save_item(NAME(m_irq_transfer)); - save_item(NAME(m_irq_count)); - save_item(NAME(m_irq_count_latch)); - - save_item(NAME(m_fds_last_side)); - save_item(NAME(m_fds_count)); -} - -void nes_disksys_device::pcb_reset() -{ - // read accesses in 0x6000-0xffff are always handled by - // cutom code below, so no need to setup the prg... - chr8(0, CHRRAM); - set_nt_mirroring(PPU_MIRROR_VERT); - - m_fds_motor_on = 0; - m_fds_door_closed = 0; - m_fds_current_side = 1; - m_fds_head_position = 0; - m_fds_status0 = 0; - m_read_mode = 0; - m_drive_ready = 0; - m_irq_count = 0; - m_irq_count_latch = 0; - m_irq_enable = 0; - m_irq_transfer = 0; - - m_fds_count = 0; - m_fds_last_side = 0; -} - - -/*------------------------------------------------- - mapper specific handlers - -------------------------------------------------*/ - -/*------------------------------------------------- - - RAM is in 0x6000-0xdfff (32K) - ROM is in 0xe000-0xffff (8K) - - registers + disk drive are accessed in - 0x4020-0x403f (read_ex/write_ex below) - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_disksys_device::write_h) -{ - LOG_MMC(("Famicom Disk System write_h, offset %04x, data: %02x\n", offset, data)); - - if (offset < 0x6000) - m_prgram[offset + 0x2000] = data; -} - -READ8_MEMBER(nes_disksys_device::read_h) -{ - LOG_MMC(("Famicom Disk System read_h, offset: %04x\n", offset)); - - if (offset < 0x6000) - return m_prgram[offset + 0x2000]; - else - return m_2c33_rom[offset & 0x1fff]; -} - -WRITE8_MEMBER(nes_disksys_device::write_m) -{ - LOG_MMC(("Famicom Disk System write_m, offset: %04x, data: %02x\n", offset, data)); - m_prgram[offset] = data; -} - -READ8_MEMBER(nes_disksys_device::read_m) -{ - LOG_MMC(("Famicom Disk System read_m, offset: %04x\n", offset)); - return m_prgram[offset]; -} - -void nes_disksys_device::hblank_irq(int scanline, int vblank, int blanked) -{ - if (m_irq_transfer) - m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE); -} - -WRITE8_MEMBER(nes_disksys_device::write_ex) -{ - LOG_MMC(("Famicom Disk System write_ex, offset: %04x, data: %02x\n", offset, data)); - - if (offset >= 0x20 && offset < 0x60) - { - // wavetable - } - - switch (offset) - { - case 0x00: - m_irq_count_latch = (m_irq_count_latch & 0xff00) | data; - break; - case 0x01: - m_irq_count_latch = (m_irq_count_latch & 0x00ff) | (data << 8); - break; - case 0x02: - m_irq_count = m_irq_count_latch; - m_irq_enable = BIT(data, 1); - break; - case 0x03: - // bit0 - Enable disk I/O registers - // bit1 - Enable sound I/O registers - break; - case 0x04: - // write data out to disk - // TEST! - if (m_fds_data && m_fds_current_side && !m_read_mode) - m_fds_data[(m_fds_current_side - 1) * 65500 + m_fds_head_position++] = data; - break; - case 0x05: - // $4025 - FDS Control - // bit0 - Drive Motor Control (0: Stop motor; 1: Turn on motor) - // bit1 - Transfer Reset (Set 1 to reset transfer timing to the initial state) - // bit2 - Read / Write mode (0: write; 1: read) - // bit3 - Mirroring (0: horizontal; 1: vertical) - // bit4 - CRC control (set during CRC calculation of transfer) - // bit5 - Always set to '1' - // bit6 - Read/Write Start (Set to 1 when the drive becomes ready for read/write) - // bit7 - Interrupt Transfer (0: Transfer without using IRQ; 1: Enable IRQ when - // the drive becomes ready) - m_fds_motor_on = BIT(data, 0); - - if (BIT(data, 1)) - m_fds_head_position = 0; - - if (!(data & 0x40) && m_drive_ready && m_fds_head_position > 2) - m_fds_head_position -= 2; // ??? is this some sort of compensation?? - - m_read_mode = BIT(data, 2); - set_nt_mirroring(BIT(data, 3) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); - m_drive_ready = data & 0x40; - m_irq_transfer = BIT(data, 7); - break; - case 0x06: - // external connector - break; - case 0x60: // $4080 - Volume envelope - read through $4090 - case 0x62: // $4082 - Frequency low - case 0x63: // $4083 - Frequency high - case 0x64: // $4084 - Mod envelope - read through $4092 - case 0x65: // $4085 - Mod counter - case 0x66: // $4086 - Mod frequency low - case 0x67: // $4087 - Mod frequency high - case 0x68: // $4088 - Mod table write - case 0x69: // $4089 - Wave write / master volume - case 0x6a: // $408a - Envelope speed - break; - } -} - -READ8_MEMBER(nes_disksys_device::read_ex) -{ - LOG_MMC(("Famicom Disk System read_ex, offset: %04x\n", offset)); - UINT8 ret = 0x00; - - if (offset >= 0x20 && offset < 0x60) - { - // wavetable - } - - switch (offset) - { - case 0x10: - // $4030 - disk status 0 - // bit0 - Timer Interrupt (1: an IRQ occurred) - // bit1 - Byte transfer flag (Set to 1 every time 8 bits have been transfered between - // the RAM adaptor & disk drive through $4024/$4031; Reset to 0 when $4024, - // $4031, or $4030 has been serviced) - // bit4 - CRC control (0: CRC passed; 1: CRC error) - // bit6 - End of Head (1 when disk head is on the most inner track) - // bit7 - Disk Data Read/Write Enable (1 when disk is readable/writable) - ret = m_fds_status0 | 0x80; - // clear the disk IRQ detect flag - m_fds_status0 &= ~0x01; - break; - case 0x11: - // $4031 - data latch - // don't read data if disk is unloaded - if (!m_fds_data) - ret = 0; - else if (m_fds_current_side && m_read_mode) - { - ret = m_fds_data[(m_fds_current_side - 1) * 65500 + m_fds_head_position++]; - if (m_fds_head_position == 65500) - { - printf("end of disk reached!\n"); - m_fds_status0 |= 0x40; - m_fds_head_position -= 2; - } - } - else - ret = 0; - break; - case 0x12: - // $4032 - disk status 1: - // bit0 - Disk flag (0: Disk inserted; 1: Disk not inserted) - // bit1 - Ready flag (0: Disk ready; 1: Disk not ready) - // bit2 - Protect flag (0: Not write protected; 1: Write protected or disk ejected) - if (!m_fds_data) - ret = 1; - else if (m_fds_last_side != m_fds_current_side) - { - // If we've switched disks, report "no disk" for a few reads - ret = 1; - m_fds_count++; - if (m_fds_count == 50) - { - m_fds_last_side = m_fds_current_side; - m_fds_count = 0; - } - } - else - ret = (m_fds_current_side == 0) ? 1 : 0; // 0 if a disk is inserted - break; - case 0x13: - // $4033 - external connector (bits 0-6) + battery status (bit 7) - ret = 0x80; - break; - case 0x70: // $4090 - Volume gain - write through $4080 - case 0x72: // $4092 - Mod gain - read through $4084 - default: - ret = 0x00; - break; - } - - return ret; -} - -//------------------------------------------------- -// device_timer - handler timer events -//------------------------------------------------- - -void nes_disksys_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) -{ - if (id == TIMER_IRQ) - { - if (m_irq_enable && m_irq_count) - { - m_irq_count--; - if (!m_irq_count) - { - m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE); - m_irq_enable = 0; - m_fds_status0 |= 0x01; - m_irq_count_latch = 0; // used in Kaettekita Mario Bros - } - } - } -} - - -// Hacky helper to allow user to switch disk side with a simple key - -void nes_disksys_device::disk_flip_side() -{ - m_fds_current_side++; - if (m_fds_current_side > m_fds_sides) - m_fds_current_side = 0; - - if (m_fds_current_side == 0) - popmessage("No disk inserted."); - else - popmessage("Disk set to side %d", m_fds_current_side); -} - - - -// Disk Loading / Unloading - -void nes_disksys_device::load_disk(device_image_interface &image) -{ - int header = 0; - m_fds_sides = 0; - - if (image.length() % 65500) - header = 0x10; - - m_fds_sides = (image.length() - header) / 65500; - - if (!m_fds_data) - m_fds_data = auto_alloc_array(machine(), UINT8, m_fds_sides * 65500); - - // if there is an header, skip it - image.fseek(header, SEEK_SET); - image.fread(m_fds_data, 65500 * m_fds_sides); - return; -} - -void nes_disksys_device::unload_disk(device_image_interface &image) -{ - /* TODO: should write out changes here as well */ - m_fds_sides = 0; -} diff --git a/src/devices/bus/nes/disksys.cpp b/src/devices/bus/nes/disksys.cpp new file mode 100644 index 00000000000..45cb275e9de --- /dev/null +++ b/src/devices/bus/nes/disksys.cpp @@ -0,0 +1,431 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for Disk System expansion + + + Here we emulate the RAM expansion + Disk Drive which form the + Famicom Disk System. + + Based on info from NESDev wiki ( http://wiki.nesdev.com/w/index.php/Family_Computer_Disk_System ) + + TODO: + - convert floppy drive + fds format to modern code! + - add sound bits + - stop IRQ from using HOLD_LINE + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "disksys.h" +#include "cpu/m6502/m6502.h" +#include "imagedev/flopdrv.h" +#include "formats/nes_dsk.h" + +#ifdef NES_PCB_DEBUG + #define VERBOSE 1 +#else + #define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//----------------------------------------------- +// +// Disk drive implementation +// +//----------------------------------------------- + +static const floppy_interface nes_floppy_interface = +{ + FLOPPY_STANDARD_5_25_DSHD, + LEGACY_FLOPPY_OPTIONS_NAME(nes_only), + "floppy_5_25" +}; + +static MACHINE_CONFIG_FRAGMENT( nes_disksys ) + MCFG_LEGACY_FLOPPY_DRIVE_ADD(FLOPPY_0, nes_floppy_interface) +MACHINE_CONFIG_END + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor nes_disksys_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( nes_disksys ); +} + + + +ROM_START( disksys ) + ROM_REGION(0x2000, "drive", 0) + ROM_SYSTEM_BIOS( 0, "2c33a-01a", "Famicom Disk System Bios") + ROMX_LOAD( "rp2c33a-01a.bin", 0x0000, 0x2000, CRC(5e607dcf) SHA1(57fe1bdee955bb48d357e463ccbf129496930b62), ROM_BIOS(1)) // newer, Nintendo logo has no shadow + ROM_SYSTEM_BIOS( 1, "2c33-01", "Famicom Disk System Bios, older") + ROMX_LOAD( "rp2c33-01.bin", 0x0000, 0x2000, CRC(1c7ae5d5) SHA1(af5af53f66982e749643fdf8b2acbb7d4d3ed229), ROM_BIOS(2)) // older, Nintendo logo has shadow +ROM_END + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *nes_disksys_device::device_rom_region() const +{ + return ROM_NAME( disksys ); +} + + +void nes_disksys_device::load_proc(device_image_interface &image) +{ + nes_disksys_device *disk_sys = static_cast(image.device().owner()); + disk_sys->load_disk(image); +} + +void nes_disksys_device::unload_proc(device_image_interface &image) +{ + nes_disksys_device *disk_sys = static_cast(image.device().owner()); + disk_sys->unload_disk(image); +} + + +//------------------------------------------------ +// +// RAM expansion cart implementation +// +//------------------------------------------------ + +const device_type NES_DISKSYS = &device_creator; + + +nes_disksys_device::nes_disksys_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_DISKSYS, "FC RAM Expansion + Disk System PCB", tag, owner, clock, "fc_disksys", __FILE__), + m_fds_data(NULL), + m_disk(*this, FLOPPY_0), + m_fds_sides(0) +{ +} + + +void nes_disksys_device::device_start() +{ + common_start(); + + m_2c33_rom = (UINT8*)memregion("drive")->base(); + + m_disk->floppy_install_load_proc(nes_disksys_device::load_proc); + m_disk->floppy_install_unload_proc(nes_disksys_device::unload_proc); + + irq_timer = timer_alloc(TIMER_IRQ); + irq_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1)); + + save_item(NAME(m_fds_motor_on)); + save_item(NAME(m_fds_door_closed)); + save_item(NAME(m_fds_current_side)); + save_item(NAME(m_fds_head_position)); + save_item(NAME(m_fds_status0)); + save_item(NAME(m_read_mode)); + save_item(NAME(m_drive_ready)); + save_item(NAME(m_irq_enable)); + save_item(NAME(m_irq_transfer)); + save_item(NAME(m_irq_count)); + save_item(NAME(m_irq_count_latch)); + + save_item(NAME(m_fds_last_side)); + save_item(NAME(m_fds_count)); +} + +void nes_disksys_device::pcb_reset() +{ + // read accesses in 0x6000-0xffff are always handled by + // cutom code below, so no need to setup the prg... + chr8(0, CHRRAM); + set_nt_mirroring(PPU_MIRROR_VERT); + + m_fds_motor_on = 0; + m_fds_door_closed = 0; + m_fds_current_side = 1; + m_fds_head_position = 0; + m_fds_status0 = 0; + m_read_mode = 0; + m_drive_ready = 0; + m_irq_count = 0; + m_irq_count_latch = 0; + m_irq_enable = 0; + m_irq_transfer = 0; + + m_fds_count = 0; + m_fds_last_side = 0; +} + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + RAM is in 0x6000-0xdfff (32K) + ROM is in 0xe000-0xffff (8K) + + registers + disk drive are accessed in + 0x4020-0x403f (read_ex/write_ex below) + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_disksys_device::write_h) +{ + LOG_MMC(("Famicom Disk System write_h, offset %04x, data: %02x\n", offset, data)); + + if (offset < 0x6000) + m_prgram[offset + 0x2000] = data; +} + +READ8_MEMBER(nes_disksys_device::read_h) +{ + LOG_MMC(("Famicom Disk System read_h, offset: %04x\n", offset)); + + if (offset < 0x6000) + return m_prgram[offset + 0x2000]; + else + return m_2c33_rom[offset & 0x1fff]; +} + +WRITE8_MEMBER(nes_disksys_device::write_m) +{ + LOG_MMC(("Famicom Disk System write_m, offset: %04x, data: %02x\n", offset, data)); + m_prgram[offset] = data; +} + +READ8_MEMBER(nes_disksys_device::read_m) +{ + LOG_MMC(("Famicom Disk System read_m, offset: %04x\n", offset)); + return m_prgram[offset]; +} + +void nes_disksys_device::hblank_irq(int scanline, int vblank, int blanked) +{ + if (m_irq_transfer) + m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE); +} + +WRITE8_MEMBER(nes_disksys_device::write_ex) +{ + LOG_MMC(("Famicom Disk System write_ex, offset: %04x, data: %02x\n", offset, data)); + + if (offset >= 0x20 && offset < 0x60) + { + // wavetable + } + + switch (offset) + { + case 0x00: + m_irq_count_latch = (m_irq_count_latch & 0xff00) | data; + break; + case 0x01: + m_irq_count_latch = (m_irq_count_latch & 0x00ff) | (data << 8); + break; + case 0x02: + m_irq_count = m_irq_count_latch; + m_irq_enable = BIT(data, 1); + break; + case 0x03: + // bit0 - Enable disk I/O registers + // bit1 - Enable sound I/O registers + break; + case 0x04: + // write data out to disk + // TEST! + if (m_fds_data && m_fds_current_side && !m_read_mode) + m_fds_data[(m_fds_current_side - 1) * 65500 + m_fds_head_position++] = data; + break; + case 0x05: + // $4025 - FDS Control + // bit0 - Drive Motor Control (0: Stop motor; 1: Turn on motor) + // bit1 - Transfer Reset (Set 1 to reset transfer timing to the initial state) + // bit2 - Read / Write mode (0: write; 1: read) + // bit3 - Mirroring (0: horizontal; 1: vertical) + // bit4 - CRC control (set during CRC calculation of transfer) + // bit5 - Always set to '1' + // bit6 - Read/Write Start (Set to 1 when the drive becomes ready for read/write) + // bit7 - Interrupt Transfer (0: Transfer without using IRQ; 1: Enable IRQ when + // the drive becomes ready) + m_fds_motor_on = BIT(data, 0); + + if (BIT(data, 1)) + m_fds_head_position = 0; + + if (!(data & 0x40) && m_drive_ready && m_fds_head_position > 2) + m_fds_head_position -= 2; // ??? is this some sort of compensation?? + + m_read_mode = BIT(data, 2); + set_nt_mirroring(BIT(data, 3) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + m_drive_ready = data & 0x40; + m_irq_transfer = BIT(data, 7); + break; + case 0x06: + // external connector + break; + case 0x60: // $4080 - Volume envelope - read through $4090 + case 0x62: // $4082 - Frequency low + case 0x63: // $4083 - Frequency high + case 0x64: // $4084 - Mod envelope - read through $4092 + case 0x65: // $4085 - Mod counter + case 0x66: // $4086 - Mod frequency low + case 0x67: // $4087 - Mod frequency high + case 0x68: // $4088 - Mod table write + case 0x69: // $4089 - Wave write / master volume + case 0x6a: // $408a - Envelope speed + break; + } +} + +READ8_MEMBER(nes_disksys_device::read_ex) +{ + LOG_MMC(("Famicom Disk System read_ex, offset: %04x\n", offset)); + UINT8 ret = 0x00; + + if (offset >= 0x20 && offset < 0x60) + { + // wavetable + } + + switch (offset) + { + case 0x10: + // $4030 - disk status 0 + // bit0 - Timer Interrupt (1: an IRQ occurred) + // bit1 - Byte transfer flag (Set to 1 every time 8 bits have been transfered between + // the RAM adaptor & disk drive through $4024/$4031; Reset to 0 when $4024, + // $4031, or $4030 has been serviced) + // bit4 - CRC control (0: CRC passed; 1: CRC error) + // bit6 - End of Head (1 when disk head is on the most inner track) + // bit7 - Disk Data Read/Write Enable (1 when disk is readable/writable) + ret = m_fds_status0 | 0x80; + // clear the disk IRQ detect flag + m_fds_status0 &= ~0x01; + break; + case 0x11: + // $4031 - data latch + // don't read data if disk is unloaded + if (!m_fds_data) + ret = 0; + else if (m_fds_current_side && m_read_mode) + { + ret = m_fds_data[(m_fds_current_side - 1) * 65500 + m_fds_head_position++]; + if (m_fds_head_position == 65500) + { + printf("end of disk reached!\n"); + m_fds_status0 |= 0x40; + m_fds_head_position -= 2; + } + } + else + ret = 0; + break; + case 0x12: + // $4032 - disk status 1: + // bit0 - Disk flag (0: Disk inserted; 1: Disk not inserted) + // bit1 - Ready flag (0: Disk ready; 1: Disk not ready) + // bit2 - Protect flag (0: Not write protected; 1: Write protected or disk ejected) + if (!m_fds_data) + ret = 1; + else if (m_fds_last_side != m_fds_current_side) + { + // If we've switched disks, report "no disk" for a few reads + ret = 1; + m_fds_count++; + if (m_fds_count == 50) + { + m_fds_last_side = m_fds_current_side; + m_fds_count = 0; + } + } + else + ret = (m_fds_current_side == 0) ? 1 : 0; // 0 if a disk is inserted + break; + case 0x13: + // $4033 - external connector (bits 0-6) + battery status (bit 7) + ret = 0x80; + break; + case 0x70: // $4090 - Volume gain - write through $4080 + case 0x72: // $4092 - Mod gain - read through $4084 + default: + ret = 0x00; + break; + } + + return ret; +} + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +void nes_disksys_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (id == TIMER_IRQ) + { + if (m_irq_enable && m_irq_count) + { + m_irq_count--; + if (!m_irq_count) + { + m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE); + m_irq_enable = 0; + m_fds_status0 |= 0x01; + m_irq_count_latch = 0; // used in Kaettekita Mario Bros + } + } + } +} + + +// Hacky helper to allow user to switch disk side with a simple key + +void nes_disksys_device::disk_flip_side() +{ + m_fds_current_side++; + if (m_fds_current_side > m_fds_sides) + m_fds_current_side = 0; + + if (m_fds_current_side == 0) + popmessage("No disk inserted."); + else + popmessage("Disk set to side %d", m_fds_current_side); +} + + + +// Disk Loading / Unloading + +void nes_disksys_device::load_disk(device_image_interface &image) +{ + int header = 0; + m_fds_sides = 0; + + if (image.length() % 65500) + header = 0x10; + + m_fds_sides = (image.length() - header) / 65500; + + if (!m_fds_data) + m_fds_data = auto_alloc_array(machine(), UINT8, m_fds_sides * 65500); + + // if there is an header, skip it + image.fseek(header, SEEK_SET); + image.fread(m_fds_data, 65500 * m_fds_sides); + return; +} + +void nes_disksys_device::unload_disk(device_image_interface &image) +{ + /* TODO: should write out changes here as well */ + m_fds_sides = 0; +} diff --git a/src/devices/bus/nes/event.c b/src/devices/bus/nes/event.c deleted file mode 100644 index 4059b107a24..00000000000 --- a/src/devices/bus/nes/event.c +++ /dev/null @@ -1,239 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Fabio Priuli -/*********************************************************************************************************** - - - NES/Famicom cartridge emulation for Nintendo NES-EVENT PCB - - - Here we emulate the following PCBs - - * Nintendo NES-EVENT [mapper 105] - - ***********************************************************************************************************/ - - -#include "emu.h" -#include "event.h" - -#include "cpu/m6502/m6502.h" - - -#ifdef NES_PCB_DEBUG -#define VERBOSE 1 -#else -#define VERBOSE 0 -#endif - -#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) - - -//------------------------------------------------- -// constructor -//------------------------------------------------- - -const device_type NES_EVENT = &device_creator; - - -nes_event_device::nes_event_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_sxrom_device(mconfig, NES_EVENT, "NES Cart Event PCB", tag, owner, clock, "nes_event", __FILE__), - m_dsw(*this, "DIPSW") -{ -} - - -void nes_event_device::device_start() -{ - common_start(); - event_timer = timer_alloc(TIMER_EVENT); - event_timer->adjust(attotime::never); - timer_freq = machine().device("maincpu")->cycles_to_attotime(1); - - save_item(NAME(m_latch)); - save_item(NAME(m_count)); - save_item(NAME(m_reg)); - save_item(NAME(m_reg_write_enable)); - save_item(NAME(m_nwc_init)); - - save_item(NAME(m_timer_count)); - save_item(NAME(m_timer_on)); - save_item(NAME(m_timer_enabled)); -} - -void nes_event_device::pcb_reset() -{ - m_latch = 0; - m_count = 0; - m_reg[0] = 0x0f; - m_reg[1] = m_reg[2] = m_reg[3] = 0; - m_reg_write_enable = 1; - m_nwc_init = 2; - - set_nt_mirroring(PPU_MIRROR_HORZ); - chr8(0, CHRRAM); - prg32(0); - m_timer_count = 0; - m_timer_enabled = 0; - m_timer_on = 0; -} - - - -/*------------------------------------------------- - mapper specific handlers - -------------------------------------------------*/ - -/*------------------------------------------------- - - Event PCB - - Games: Nintento World Championships - - MMC-1 variant with repurposed register at $a000 and a - lot of discrete components - - iNES: mapper 105 - - In MESS: Supported. - - -------------------------------------------------*/ - -void nes_event_device::set_chr() -{ - // no CHR switching, there are only 8KB VRAM from the cart -} - -void nes_event_device::set_prg() -{ -// printf("enter with %d and reg1 0x%x - reg3 0x%x\n", m_nwc_init, m_reg[1], m_reg[3]); - // reg[1] is different from base MMC-1! - // bit 0 is ignored, bit1/bit3 are used for PRG switch, bit4 is used for the timer - UINT8 temp = (m_reg[1] >> 1) & 7; - - // initially PRG is fixed, until bit4 of reg1 is set to 1 and then to 0 - switch (m_nwc_init) - { - case 2: - if (m_reg[1] & 0x10) m_nwc_init--; - return; - case 1: - if (~m_reg[1] & 0x10) m_nwc_init--; - return; - } - - if (temp < 4) - prg32(temp); - else - { - // else PRG works similarly to base MMC-1, but only acts on the higher 128KB (2nd PRG ROM) - switch (m_reg[0] & 0x0c) - { - case 0x00: - case 0x04: - prg32(0x04 | ((m_reg[3] >> 1) & 0x03)); - break; - case 0x08: - prg16_89ab(0x08 | 0x00); - prg16_cdef(0x08 | (m_reg[3] & 0x07)); - break; - case 0x0c: - prg16_89ab(0x08 | (m_reg[3] & 0x07)); - prg16_cdef(0x08 | 0x07); - break; - } - } - - // after the init procedure above, bit4 of m_reg[1] is used to init IRQ, by setting and then clearing the bit - // however, there are (bankswitch related?) writes with bit4 cleared before the one 'enabling' the timer, so - // we need the additional m_timer_enabled variable, to avoid starting the timer before its time... - if (m_reg[1] & 0x10) - { - m_timer_enabled = 1; - m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); - } - else - { - if (!m_timer_on && m_timer_enabled) - { - m_timer_count = 0x20000000 | ((m_dsw->read() & 0x0f) << 25); - event_timer->adjust(attotime::zero, 0, timer_freq); - m_timer_on = 1; - } - } -} - -void nes_event_device::update_regs(int reg) -{ - switch (reg) - { - case 0: - switch (m_reg[0] & 0x03) - { - case 0: set_nt_mirroring(PPU_MIRROR_LOW); break; - case 1: set_nt_mirroring(PPU_MIRROR_HIGH); break; - case 2: set_nt_mirroring(PPU_MIRROR_VERT); break; - case 3: set_nt_mirroring(PPU_MIRROR_HORZ); break; - } - set_prg(); - break; - case 1: - set_prg(); - break; - case 2: - set_chr(); - break; - case 3: - set_prg(); - break; - } -} - -//------------------------------------------------- -// Dipswicth -//------------------------------------------------- - -static INPUT_PORTS_START( nwc_dsw ) - PORT_START("DIPSW") - PORT_DIPNAME( 0x0f, 0x04, "Timer" ) PORT_DIPLOCATION("SW:!1,!2,!3,!4") - PORT_DIPSETTING( 0x00, "5:00.4" ) - PORT_DIPSETTING( 0x01, "5:19.2" ) - PORT_DIPSETTING( 0x02, "5:38.0" ) - PORT_DIPSETTING( 0x03, "5:56.7" ) - PORT_DIPSETTING( 0x04, "6:15.5" ) - PORT_DIPSETTING( 0x05, "6:34.3" ) - PORT_DIPSETTING( 0x06, "6:53.1" ) - PORT_DIPSETTING( 0x07, "7:11.9" ) - PORT_DIPSETTING( 0x08, "7:30.6" ) - PORT_DIPSETTING( 0x09, "7:49.4" ) - PORT_DIPSETTING( 0x0a, "8:08.2" ) - PORT_DIPSETTING( 0x0b, "8:27.0" ) - PORT_DIPSETTING( 0x0c, "8:45.8" ) - PORT_DIPSETTING( 0x0d, "9:04.5" ) - PORT_DIPSETTING( 0x0e, "9:23.3" ) - PORT_DIPSETTING( 0x0f, "9:42.1" ) -INPUT_PORTS_END - - - -ioport_constructor nes_event_device::device_input_ports() const -{ - return INPUT_PORTS_NAME( nwc_dsw ); -} - - -//------------------------------------------------- -// device_timer - handler timer events -//------------------------------------------------- - -void nes_event_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) -{ - if (id == TIMER_EVENT) - { - m_timer_count--; - if (!m_timer_count) - { - m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE); - event_timer->reset(); - } - } -} diff --git a/src/devices/bus/nes/event.cpp b/src/devices/bus/nes/event.cpp new file mode 100644 index 00000000000..4059b107a24 --- /dev/null +++ b/src/devices/bus/nes/event.cpp @@ -0,0 +1,239 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for Nintendo NES-EVENT PCB + + + Here we emulate the following PCBs + + * Nintendo NES-EVENT [mapper 105] + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "event.h" + +#include "cpu/m6502/m6502.h" + + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_EVENT = &device_creator; + + +nes_event_device::nes_event_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_sxrom_device(mconfig, NES_EVENT, "NES Cart Event PCB", tag, owner, clock, "nes_event", __FILE__), + m_dsw(*this, "DIPSW") +{ +} + + +void nes_event_device::device_start() +{ + common_start(); + event_timer = timer_alloc(TIMER_EVENT); + event_timer->adjust(attotime::never); + timer_freq = machine().device("maincpu")->cycles_to_attotime(1); + + save_item(NAME(m_latch)); + save_item(NAME(m_count)); + save_item(NAME(m_reg)); + save_item(NAME(m_reg_write_enable)); + save_item(NAME(m_nwc_init)); + + save_item(NAME(m_timer_count)); + save_item(NAME(m_timer_on)); + save_item(NAME(m_timer_enabled)); +} + +void nes_event_device::pcb_reset() +{ + m_latch = 0; + m_count = 0; + m_reg[0] = 0x0f; + m_reg[1] = m_reg[2] = m_reg[3] = 0; + m_reg_write_enable = 1; + m_nwc_init = 2; + + set_nt_mirroring(PPU_MIRROR_HORZ); + chr8(0, CHRRAM); + prg32(0); + m_timer_count = 0; + m_timer_enabled = 0; + m_timer_on = 0; +} + + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + Event PCB + + Games: Nintento World Championships + + MMC-1 variant with repurposed register at $a000 and a + lot of discrete components + + iNES: mapper 105 + + In MESS: Supported. + + -------------------------------------------------*/ + +void nes_event_device::set_chr() +{ + // no CHR switching, there are only 8KB VRAM from the cart +} + +void nes_event_device::set_prg() +{ +// printf("enter with %d and reg1 0x%x - reg3 0x%x\n", m_nwc_init, m_reg[1], m_reg[3]); + // reg[1] is different from base MMC-1! + // bit 0 is ignored, bit1/bit3 are used for PRG switch, bit4 is used for the timer + UINT8 temp = (m_reg[1] >> 1) & 7; + + // initially PRG is fixed, until bit4 of reg1 is set to 1 and then to 0 + switch (m_nwc_init) + { + case 2: + if (m_reg[1] & 0x10) m_nwc_init--; + return; + case 1: + if (~m_reg[1] & 0x10) m_nwc_init--; + return; + } + + if (temp < 4) + prg32(temp); + else + { + // else PRG works similarly to base MMC-1, but only acts on the higher 128KB (2nd PRG ROM) + switch (m_reg[0] & 0x0c) + { + case 0x00: + case 0x04: + prg32(0x04 | ((m_reg[3] >> 1) & 0x03)); + break; + case 0x08: + prg16_89ab(0x08 | 0x00); + prg16_cdef(0x08 | (m_reg[3] & 0x07)); + break; + case 0x0c: + prg16_89ab(0x08 | (m_reg[3] & 0x07)); + prg16_cdef(0x08 | 0x07); + break; + } + } + + // after the init procedure above, bit4 of m_reg[1] is used to init IRQ, by setting and then clearing the bit + // however, there are (bankswitch related?) writes with bit4 cleared before the one 'enabling' the timer, so + // we need the additional m_timer_enabled variable, to avoid starting the timer before its time... + if (m_reg[1] & 0x10) + { + m_timer_enabled = 1; + m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); + } + else + { + if (!m_timer_on && m_timer_enabled) + { + m_timer_count = 0x20000000 | ((m_dsw->read() & 0x0f) << 25); + event_timer->adjust(attotime::zero, 0, timer_freq); + m_timer_on = 1; + } + } +} + +void nes_event_device::update_regs(int reg) +{ + switch (reg) + { + case 0: + switch (m_reg[0] & 0x03) + { + case 0: set_nt_mirroring(PPU_MIRROR_LOW); break; + case 1: set_nt_mirroring(PPU_MIRROR_HIGH); break; + case 2: set_nt_mirroring(PPU_MIRROR_VERT); break; + case 3: set_nt_mirroring(PPU_MIRROR_HORZ); break; + } + set_prg(); + break; + case 1: + set_prg(); + break; + case 2: + set_chr(); + break; + case 3: + set_prg(); + break; + } +} + +//------------------------------------------------- +// Dipswicth +//------------------------------------------------- + +static INPUT_PORTS_START( nwc_dsw ) + PORT_START("DIPSW") + PORT_DIPNAME( 0x0f, 0x04, "Timer" ) PORT_DIPLOCATION("SW:!1,!2,!3,!4") + PORT_DIPSETTING( 0x00, "5:00.4" ) + PORT_DIPSETTING( 0x01, "5:19.2" ) + PORT_DIPSETTING( 0x02, "5:38.0" ) + PORT_DIPSETTING( 0x03, "5:56.7" ) + PORT_DIPSETTING( 0x04, "6:15.5" ) + PORT_DIPSETTING( 0x05, "6:34.3" ) + PORT_DIPSETTING( 0x06, "6:53.1" ) + PORT_DIPSETTING( 0x07, "7:11.9" ) + PORT_DIPSETTING( 0x08, "7:30.6" ) + PORT_DIPSETTING( 0x09, "7:49.4" ) + PORT_DIPSETTING( 0x0a, "8:08.2" ) + PORT_DIPSETTING( 0x0b, "8:27.0" ) + PORT_DIPSETTING( 0x0c, "8:45.8" ) + PORT_DIPSETTING( 0x0d, "9:04.5" ) + PORT_DIPSETTING( 0x0e, "9:23.3" ) + PORT_DIPSETTING( 0x0f, "9:42.1" ) +INPUT_PORTS_END + + + +ioport_constructor nes_event_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( nwc_dsw ); +} + + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +void nes_event_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (id == TIMER_EVENT) + { + m_timer_count--; + if (!m_timer_count) + { + m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE); + event_timer->reset(); + } + } +} diff --git a/src/devices/bus/nes/ggenie.c b/src/devices/bus/nes/ggenie.c deleted file mode 100644 index f9320a5fbee..00000000000 --- a/src/devices/bus/nes/ggenie.c +++ /dev/null @@ -1,274 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Fabio Priuli -/*********************************************************************************************************** - - - NES/Famicom cartridge emulation for Galoob Game Genie PCBs - - - Here we emulate the following PCBs - - * Galoob Game Genie, passthrough hacking cart - - ***********************************************************************************************************/ - - -#include "emu.h" -#include "ggenie.h" -#include "includes/nes.h" - - -#ifdef NES_PCB_DEBUG -#define VERBOSE 1 -#else -#define VERBOSE 0 -#endif - -#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) - - -//------------------------------------------------- -// constructor -//------------------------------------------------- - -const device_type NES_GGENIE = &device_creator; - - -nes_ggenie_device::nes_ggenie_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_GGENIE, "NES Cart Game Genie PCB", tag, owner, clock, "nes_ggenie", __FILE__), - m_ggslot(*this, "gg_slot") -{ -} - - -void nes_ggenie_device::device_start() -{ - common_start(); - save_item(NAME(m_gg_bypass)); -} - -void nes_ggenie_device::pcb_start(running_machine &machine, UINT8 *ciram_ptr, bool cart_mounted) -{ - device_nes_cart_interface::pcb_start(machine, ciram_ptr, cart_mounted); - if (m_ggslot->m_cart) - m_ggslot->pcb_start(m_ciram); -} - -void nes_ggenie_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0); - chr8(0, m_chr_source); - - set_nt_mirroring(PPU_MIRROR_LOW); - m_gg_bypass = 0; - - if (m_ggslot->m_cart) - m_ggslot->m_cart->pcb_reset(); -} - - - - -/*------------------------------------------------- - mapper specific handlers - -------------------------------------------------*/ - -/*------------------------------------------------- - - Game Genie board emulation - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_ggenie_device::write_h) -{ -// LOG_MMC(("axrom write_h, offset: %04x, data: %02x\n", offset, data)); - if (!m_gg_bypass) - { - // From blargg: Codes are written to $8001-800C, starting at $800C and going down to $8001. - // Next, two values are written to $8000. The first specify the kind of codes which have - // been inserted, the second write to $8000 is always zero (all 8 bits). - // This probably disables the boot ROM (the code is executing from RAM at this point). - // Once done, the code jumps to ($FFFC) to begin the game. - // All 12 bytes from $8001-800C are written regardless of how many codes are inserted. - // The value written to $8000 is the only clue as to what codes are actually valid and which - // ones have compare values. - if (offset) - { - int code; - offset -= 1; - code = (offset & 0xc) >> 2; - if (code == 3) - return; // how did we end up here? the GG is not expected to write to $800d-800f! - - switch (offset & 3) - { - case 0: - m_gg_addr[code] |= (data & 0x7f) << 8; - break; - case 1: - m_gg_addr[code] = data; - break; - case 2: - m_gg_comp[code] = data; - break; - case 3: - m_gg_repl[code] = data; - break; - } - return; - } - - if (offset == 0 && data == 0) - { - m_gg_bypass = 1; - m_maincpu->set_pc(0xfffc); - } - else - { - // bit 0 is always set (GG enable?) - m_gg_is_comp[0] = BIT(data, 1); - m_gg_is_comp[1] = BIT(data, 2); - m_gg_is_comp[2] = BIT(data, 3); - m_gg_disable[0] = BIT(data, 4); - m_gg_disable[1] = BIT(data, 5); - m_gg_disable[2] = BIT(data, 6); - // bit 7 is always clear - logerror("Game Genie Summary:\n"); - for (int i = 0; i < 3; i++) - { - logerror("Code %d: %s\n", i, m_gg_disable[i] ? "No" : "Yes"); - if (!m_gg_disable[i]) - { - logerror("\tAddr: 0x%X\n", m_gg_addr[i]); - logerror("\tValue: 0x%X\n", m_gg_repl[i]); - if (m_gg_is_comp[i]) - logerror("\t if equals: 0x%X\n", m_gg_comp[i]); - - } - } - } - } - else - m_ggslot->write_h(space, offset, data, mem_mask); -} - -WRITE8_MEMBER(nes_ggenie_device::write_m) -{ - if (m_gg_bypass && m_ggslot) - m_ggslot->write_m(space, offset, data, mem_mask); -} - -WRITE8_MEMBER(nes_ggenie_device::write_l) -{ - if (m_gg_bypass && m_ggslot) - m_ggslot->write_l(space, offset, data, mem_mask); -} - -READ8_MEMBER(nes_ggenie_device::read_h) -{ - if (m_gg_bypass && m_ggslot->m_cart) - { - UINT8 rom_value = m_ggslot->m_cart->hi_access_rom(offset); - - // check if GG code has to act on this address - for (int i = 0; i < 3; i++) - { - if (!m_gg_disable[i] && offset == m_gg_addr[i]) - { - if (!m_gg_is_comp[i] || (m_gg_is_comp[i] && m_gg_comp[i] == rom_value)) - return m_gg_repl[i]; - } - } - - return rom_value; - } - return hi_access_rom(offset); -} - -READ8_MEMBER(nes_ggenie_device::read_m) -{ - if (m_gg_bypass && m_ggslot->m_cart) - return m_ggslot->m_cart->read_m(space, offset, mem_mask); - - return 0xff; -} - -READ8_MEMBER(nes_ggenie_device::read_l) -{ - if (m_gg_bypass && m_ggslot->m_cart) - return m_ggslot->m_cart->read_l(space, offset, mem_mask); - - return 0xff; -} - -WRITE8_MEMBER(nes_ggenie_device::chr_w) -{ - int bank = offset >> 10; - - if (m_gg_bypass && m_ggslot->m_cart) - { - m_ggslot->m_cart->chr_w(space, offset, data, mem_mask); - return; - } - - if (m_chr_src[bank] == CHRRAM) - m_chr_access[bank][offset & 0x3ff] = data; -} - -READ8_MEMBER(nes_ggenie_device::chr_r) -{ - int bank = offset >> 10; - - if (m_gg_bypass && m_ggslot->m_cart) - return m_ggslot->m_cart->chr_r(space, offset, mem_mask); - - return m_chr_access[bank][offset & 0x3ff]; -} - - -WRITE8_MEMBER(nes_ggenie_device::nt_w) -{ - int page = ((offset & 0xc00) >> 10); - - if (m_gg_bypass && m_ggslot->m_cart) - { - m_ggslot->m_cart->nt_w(space, offset, data, mem_mask); - return; - } - - if (!m_nt_writable[page]) - return; - - m_nt_access[page][offset & 0x3ff] = data; -} - -READ8_MEMBER(nes_ggenie_device::nt_r) -{ - int page = ((offset & 0xc00) >> 10); - - if (m_gg_bypass && m_ggslot->m_cart) - return m_ggslot->m_cart->nt_r(space, offset, mem_mask); - - return m_nt_access[page][offset & 0x3ff]; -} - -//------------------------------------------------- -// MACHINE_CONFIG_FRAGMENT( sub_slot ) -//------------------------------------------------- - -static MACHINE_CONFIG_FRAGMENT( sub_slot ) - MCFG_NES_CARTRIDGE_ADD("gg_slot", nes_cart, NULL) - MCFG_NES_CARTRIDGE_NOT_MANDATORY -MACHINE_CONFIG_END - - -//------------------------------------------------- -// machine_config_additions - device-specific -// machine configurations -//------------------------------------------------- - -machine_config_constructor nes_ggenie_device::device_mconfig_additions() const -{ - return MACHINE_CONFIG_NAME( sub_slot ); -} diff --git a/src/devices/bus/nes/ggenie.cpp b/src/devices/bus/nes/ggenie.cpp new file mode 100644 index 00000000000..f9320a5fbee --- /dev/null +++ b/src/devices/bus/nes/ggenie.cpp @@ -0,0 +1,274 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for Galoob Game Genie PCBs + + + Here we emulate the following PCBs + + * Galoob Game Genie, passthrough hacking cart + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "ggenie.h" +#include "includes/nes.h" + + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_GGENIE = &device_creator; + + +nes_ggenie_device::nes_ggenie_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_GGENIE, "NES Cart Game Genie PCB", tag, owner, clock, "nes_ggenie", __FILE__), + m_ggslot(*this, "gg_slot") +{ +} + + +void nes_ggenie_device::device_start() +{ + common_start(); + save_item(NAME(m_gg_bypass)); +} + +void nes_ggenie_device::pcb_start(running_machine &machine, UINT8 *ciram_ptr, bool cart_mounted) +{ + device_nes_cart_interface::pcb_start(machine, ciram_ptr, cart_mounted); + if (m_ggslot->m_cart) + m_ggslot->pcb_start(m_ciram); +} + +void nes_ggenie_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); + + set_nt_mirroring(PPU_MIRROR_LOW); + m_gg_bypass = 0; + + if (m_ggslot->m_cart) + m_ggslot->m_cart->pcb_reset(); +} + + + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + Game Genie board emulation + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_ggenie_device::write_h) +{ +// LOG_MMC(("axrom write_h, offset: %04x, data: %02x\n", offset, data)); + if (!m_gg_bypass) + { + // From blargg: Codes are written to $8001-800C, starting at $800C and going down to $8001. + // Next, two values are written to $8000. The first specify the kind of codes which have + // been inserted, the second write to $8000 is always zero (all 8 bits). + // This probably disables the boot ROM (the code is executing from RAM at this point). + // Once done, the code jumps to ($FFFC) to begin the game. + // All 12 bytes from $8001-800C are written regardless of how many codes are inserted. + // The value written to $8000 is the only clue as to what codes are actually valid and which + // ones have compare values. + if (offset) + { + int code; + offset -= 1; + code = (offset & 0xc) >> 2; + if (code == 3) + return; // how did we end up here? the GG is not expected to write to $800d-800f! + + switch (offset & 3) + { + case 0: + m_gg_addr[code] |= (data & 0x7f) << 8; + break; + case 1: + m_gg_addr[code] = data; + break; + case 2: + m_gg_comp[code] = data; + break; + case 3: + m_gg_repl[code] = data; + break; + } + return; + } + + if (offset == 0 && data == 0) + { + m_gg_bypass = 1; + m_maincpu->set_pc(0xfffc); + } + else + { + // bit 0 is always set (GG enable?) + m_gg_is_comp[0] = BIT(data, 1); + m_gg_is_comp[1] = BIT(data, 2); + m_gg_is_comp[2] = BIT(data, 3); + m_gg_disable[0] = BIT(data, 4); + m_gg_disable[1] = BIT(data, 5); + m_gg_disable[2] = BIT(data, 6); + // bit 7 is always clear + logerror("Game Genie Summary:\n"); + for (int i = 0; i < 3; i++) + { + logerror("Code %d: %s\n", i, m_gg_disable[i] ? "No" : "Yes"); + if (!m_gg_disable[i]) + { + logerror("\tAddr: 0x%X\n", m_gg_addr[i]); + logerror("\tValue: 0x%X\n", m_gg_repl[i]); + if (m_gg_is_comp[i]) + logerror("\t if equals: 0x%X\n", m_gg_comp[i]); + + } + } + } + } + else + m_ggslot->write_h(space, offset, data, mem_mask); +} + +WRITE8_MEMBER(nes_ggenie_device::write_m) +{ + if (m_gg_bypass && m_ggslot) + m_ggslot->write_m(space, offset, data, mem_mask); +} + +WRITE8_MEMBER(nes_ggenie_device::write_l) +{ + if (m_gg_bypass && m_ggslot) + m_ggslot->write_l(space, offset, data, mem_mask); +} + +READ8_MEMBER(nes_ggenie_device::read_h) +{ + if (m_gg_bypass && m_ggslot->m_cart) + { + UINT8 rom_value = m_ggslot->m_cart->hi_access_rom(offset); + + // check if GG code has to act on this address + for (int i = 0; i < 3; i++) + { + if (!m_gg_disable[i] && offset == m_gg_addr[i]) + { + if (!m_gg_is_comp[i] || (m_gg_is_comp[i] && m_gg_comp[i] == rom_value)) + return m_gg_repl[i]; + } + } + + return rom_value; + } + return hi_access_rom(offset); +} + +READ8_MEMBER(nes_ggenie_device::read_m) +{ + if (m_gg_bypass && m_ggslot->m_cart) + return m_ggslot->m_cart->read_m(space, offset, mem_mask); + + return 0xff; +} + +READ8_MEMBER(nes_ggenie_device::read_l) +{ + if (m_gg_bypass && m_ggslot->m_cart) + return m_ggslot->m_cart->read_l(space, offset, mem_mask); + + return 0xff; +} + +WRITE8_MEMBER(nes_ggenie_device::chr_w) +{ + int bank = offset >> 10; + + if (m_gg_bypass && m_ggslot->m_cart) + { + m_ggslot->m_cart->chr_w(space, offset, data, mem_mask); + return; + } + + if (m_chr_src[bank] == CHRRAM) + m_chr_access[bank][offset & 0x3ff] = data; +} + +READ8_MEMBER(nes_ggenie_device::chr_r) +{ + int bank = offset >> 10; + + if (m_gg_bypass && m_ggslot->m_cart) + return m_ggslot->m_cart->chr_r(space, offset, mem_mask); + + return m_chr_access[bank][offset & 0x3ff]; +} + + +WRITE8_MEMBER(nes_ggenie_device::nt_w) +{ + int page = ((offset & 0xc00) >> 10); + + if (m_gg_bypass && m_ggslot->m_cart) + { + m_ggslot->m_cart->nt_w(space, offset, data, mem_mask); + return; + } + + if (!m_nt_writable[page]) + return; + + m_nt_access[page][offset & 0x3ff] = data; +} + +READ8_MEMBER(nes_ggenie_device::nt_r) +{ + int page = ((offset & 0xc00) >> 10); + + if (m_gg_bypass && m_ggslot->m_cart) + return m_ggslot->m_cart->nt_r(space, offset, mem_mask); + + return m_nt_access[page][offset & 0x3ff]; +} + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( sub_slot ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( sub_slot ) + MCFG_NES_CARTRIDGE_ADD("gg_slot", nes_cart, NULL) + MCFG_NES_CARTRIDGE_NOT_MANDATORY +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor nes_ggenie_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( sub_slot ); +} diff --git a/src/devices/bus/nes/henggedianzi.c b/src/devices/bus/nes/henggedianzi.c deleted file mode 100644 index 5cda60e6938..00000000000 --- a/src/devices/bus/nes/henggedianzi.c +++ /dev/null @@ -1,278 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Fabio Priuli -/*********************************************************************************************************** - - - NES/Famicom cartridge emulation for Henggedianzi PCBs - - - Here we emulate the following PCBs - - * Henggedianzi Super Rich [mapper 177] - * Henggedianzi Xing He Zhan Shi [mapper 179] - * Henggedianzi Shen Hua Jian Yun III - - - TODO: - - investigate relation with some TXC & Waixing boards - - ***********************************************************************************************************/ - - -#include "emu.h" -#include "henggedianzi.h" - -#include "cpu/m6502/m6502.h" - - -#ifdef NES_PCB_DEBUG -#define VERBOSE 1 -#else -#define VERBOSE 0 -#endif - -#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) - - -//------------------------------------------------- -// constructor -//------------------------------------------------- - -const device_type NES_HENGG_SRICH = &device_creator; -const device_type NES_HENGG_XHZS = &device_creator; -const device_type NES_HENGG_SHJY3 = &device_creator; - - -nes_hengg_srich_device::nes_hengg_srich_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_HENGG_SRICH, "NES Cart Henggedianzi Super Rich PCB", tag, owner, clock, "nes_hengg_srich", __FILE__) -{ -} - -nes_hengg_xhzs_device::nes_hengg_xhzs_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_HENGG_XHZS, "NES Cart Henggedianzi Xing He Zhan Shi PCB", tag, owner, clock, "nes_hengg_xhzs", __FILE__) -{ -} - -nes_hengg_shjy3_device::nes_hengg_shjy3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_HENGG_SHJY3, "NES Cart Henggedianzi Shen Hua Jian Yun III PCB", tag, owner, clock, "nes_hengg_shjy3", __FILE__) -{ -} - - - - -void nes_hengg_srich_device::device_start() -{ - common_start(); -} - -void nes_hengg_srich_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0); - chr8(0, m_chr_source); -} - -void nes_hengg_xhzs_device::device_start() -{ - common_start(); -} - -void nes_hengg_xhzs_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0); - chr8(0, m_chr_source); -} - -void nes_hengg_shjy3_device::device_start() -{ - common_start(); - save_item(NAME(m_irq_count)); - save_item(NAME(m_irq_count_latch)); - save_item(NAME(m_irq_enable)); - save_item(NAME(m_chr_mode)); - save_item(NAME(m_mmc_prg_bank)); - save_item(NAME(m_mmc_vrom_bank)); - save_item(NAME(m_mmc_extra_bank)); -} - -void nes_hengg_shjy3_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(0); - prg16_cdef(m_prg_chunks - 1); - chr8(0, m_chr_source); - - m_irq_enable = 0; - m_irq_count = m_irq_count_latch = 0; - - m_chr_mode = 0; - memset(m_mmc_prg_bank, 0, sizeof(m_mmc_prg_bank)); - memset(m_mmc_vrom_bank, 0, sizeof(m_mmc_vrom_bank)); - memset(m_mmc_extra_bank, 0, sizeof(m_mmc_extra_bank)); -} - - - - - -/*------------------------------------------------- - mapper specific handlers - -------------------------------------------------*/ - -/*------------------------------------------------- - - Bootleg Board by Henggedianzi - - Games: Mei Guo Fu Hao, Shang Gu Shen Jian , Wang Zi Fu - Chou Ji - - Writes to 0x8000-0xffff set prg32. Moreover, data&0x20 sets - NT mirroring. - - iNES: mapper 177 - - In MESS: Supported. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_hengg_srich_device::write_h) -{ - LOG_MMC(("hengg_srich write_h, offset: %04x, data: %02x\n", offset, data)); - - prg32(data); - set_nt_mirroring(BIT(data, 5) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); -} - -/*------------------------------------------------- - - Bootleg Board by Henggedianzi - - Games: Xing He Zhan Shi - - Writes to 0x5000-0x5fff set prg32 banks, writes to 0x8000- - 0xffff set NT mirroring - - Note: NEStopia marks this as Xjzb, but Xing Ji Zheng Ba - (Phantasy Star?) runs on the other Henggedianzi board - Is there an alt dump of Xing Ji Zheng Ba using this? - - iNES: mapper 179 - - In MESS: Supported. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_hengg_xhzs_device::write_l) -{ - LOG_MMC(("hengg_xhzs write_l, offset: %04x, data: %02x\n", offset, data)); - offset += 0x4100; - - if (offset & 0x5000) - prg32(data >> 1); -} - -WRITE8_MEMBER(nes_hengg_xhzs_device::write_h) -{ - LOG_MMC(("hengg_xhzs write_h, offset: %04x, data: %02x\n", offset, data)); - - set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); -} - -/*------------------------------------------------- - - UNL-SHJY3 - - -------------------------------------------------*/ - -/* I think the IRQ should only get fired if enough CPU cycles have passed, but we don't implement (yet) this part */ -void nes_hengg_shjy3_device::hblank_irq(int scanline, int vblank, int blanked) -{ - if (m_irq_enable & 0x02) - { - if (m_irq_count == 0xff) - { - m_irq_count = m_irq_count_latch; - m_irq_enable = m_irq_enable | ((m_irq_enable & 0x01) << 1); - m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE); - } - else - m_irq_count++; - } -} - -void nes_hengg_shjy3_device::update_banks() -{ - prg8_89(m_mmc_prg_bank[0]); - prg8_ab(m_mmc_prg_bank[1]); - - for (int i = 0; i < 8; i++) - { - UINT8 chr_bank = m_mmc_vrom_bank[i] | (m_mmc_extra_bank[i] << 4); - if (m_mmc_vrom_bank[i] == 0xc8) - { - m_chr_mode = 0; - continue; - } - else if (m_mmc_vrom_bank[i] == 0x88) - { - m_chr_mode = 1; - continue; - } - if ((m_mmc_vrom_bank[i] == 4 || m_mmc_vrom_bank[i] == 5) && !m_chr_mode) - chr1_x(i, chr_bank & 1, CHRRAM); - else - chr1_x(i, chr_bank, CHRROM); - } -} - -WRITE8_MEMBER(nes_hengg_shjy3_device::write_h) -{ - LOG_MMC(("shjy3 write_h, offset: %04x, data: %02x\n", offset, data)); - - if (offset >= 0x3000 && offset <= 0x600c) - { - UINT8 shift = offset & 4; - UINT8 mmc_helper = ((offset & 8) | (offset >> 8)) >> 3; - mmc_helper += 2; - mmc_helper &= 7; - - m_mmc_vrom_bank[mmc_helper] = (m_mmc_vrom_bank[mmc_helper] & (0xf0 >> shift)) | ((data & 0x0f) << shift); - if (shift) - m_mmc_extra_bank[mmc_helper] = data >> 4; - } - else - { - switch (offset) - { - case 0x0010: - m_mmc_prg_bank[0] = data; - break; - case 0x2010: - m_mmc_prg_bank[1] = data; - break; - case 0x1400: - switch (data & 0x03) - { - case 0: set_nt_mirroring(PPU_MIRROR_VERT); break; - case 1: set_nt_mirroring(PPU_MIRROR_HORZ); break; - case 2: set_nt_mirroring(PPU_MIRROR_LOW); break; - case 3: set_nt_mirroring(PPU_MIRROR_HIGH); break; - } - break; - case 0x7000: - m_irq_count_latch = (m_irq_count_latch & 0xf0) | (data & 0x0f); - break; - case 0x7004: - m_irq_count_latch = (m_irq_count_latch & 0x0f) | ((data & 0x0f) << 4); - break; - case 0x7008: - m_irq_enable = data & 0x03; - if (m_irq_enable & 0x02) - m_irq_count = m_irq_count_latch; - break; - } - } - update_banks(); -} diff --git a/src/devices/bus/nes/henggedianzi.cpp b/src/devices/bus/nes/henggedianzi.cpp new file mode 100644 index 00000000000..5cda60e6938 --- /dev/null +++ b/src/devices/bus/nes/henggedianzi.cpp @@ -0,0 +1,278 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for Henggedianzi PCBs + + + Here we emulate the following PCBs + + * Henggedianzi Super Rich [mapper 177] + * Henggedianzi Xing He Zhan Shi [mapper 179] + * Henggedianzi Shen Hua Jian Yun III + + + TODO: + - investigate relation with some TXC & Waixing boards + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "henggedianzi.h" + +#include "cpu/m6502/m6502.h" + + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_HENGG_SRICH = &device_creator; +const device_type NES_HENGG_XHZS = &device_creator; +const device_type NES_HENGG_SHJY3 = &device_creator; + + +nes_hengg_srich_device::nes_hengg_srich_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_HENGG_SRICH, "NES Cart Henggedianzi Super Rich PCB", tag, owner, clock, "nes_hengg_srich", __FILE__) +{ +} + +nes_hengg_xhzs_device::nes_hengg_xhzs_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_HENGG_XHZS, "NES Cart Henggedianzi Xing He Zhan Shi PCB", tag, owner, clock, "nes_hengg_xhzs", __FILE__) +{ +} + +nes_hengg_shjy3_device::nes_hengg_shjy3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_HENGG_SHJY3, "NES Cart Henggedianzi Shen Hua Jian Yun III PCB", tag, owner, clock, "nes_hengg_shjy3", __FILE__) +{ +} + + + + +void nes_hengg_srich_device::device_start() +{ + common_start(); +} + +void nes_hengg_srich_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + +void nes_hengg_xhzs_device::device_start() +{ + common_start(); +} + +void nes_hengg_xhzs_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + +void nes_hengg_shjy3_device::device_start() +{ + common_start(); + save_item(NAME(m_irq_count)); + save_item(NAME(m_irq_count_latch)); + save_item(NAME(m_irq_enable)); + save_item(NAME(m_chr_mode)); + save_item(NAME(m_mmc_prg_bank)); + save_item(NAME(m_mmc_vrom_bank)); + save_item(NAME(m_mmc_extra_bank)); +} + +void nes_hengg_shjy3_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + + m_irq_enable = 0; + m_irq_count = m_irq_count_latch = 0; + + m_chr_mode = 0; + memset(m_mmc_prg_bank, 0, sizeof(m_mmc_prg_bank)); + memset(m_mmc_vrom_bank, 0, sizeof(m_mmc_vrom_bank)); + memset(m_mmc_extra_bank, 0, sizeof(m_mmc_extra_bank)); +} + + + + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + Bootleg Board by Henggedianzi + + Games: Mei Guo Fu Hao, Shang Gu Shen Jian , Wang Zi Fu + Chou Ji + + Writes to 0x8000-0xffff set prg32. Moreover, data&0x20 sets + NT mirroring. + + iNES: mapper 177 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_hengg_srich_device::write_h) +{ + LOG_MMC(("hengg_srich write_h, offset: %04x, data: %02x\n", offset, data)); + + prg32(data); + set_nt_mirroring(BIT(data, 5) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); +} + +/*------------------------------------------------- + + Bootleg Board by Henggedianzi + + Games: Xing He Zhan Shi + + Writes to 0x5000-0x5fff set prg32 banks, writes to 0x8000- + 0xffff set NT mirroring + + Note: NEStopia marks this as Xjzb, but Xing Ji Zheng Ba + (Phantasy Star?) runs on the other Henggedianzi board + Is there an alt dump of Xing Ji Zheng Ba using this? + + iNES: mapper 179 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_hengg_xhzs_device::write_l) +{ + LOG_MMC(("hengg_xhzs write_l, offset: %04x, data: %02x\n", offset, data)); + offset += 0x4100; + + if (offset & 0x5000) + prg32(data >> 1); +} + +WRITE8_MEMBER(nes_hengg_xhzs_device::write_h) +{ + LOG_MMC(("hengg_xhzs write_h, offset: %04x, data: %02x\n", offset, data)); + + set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); +} + +/*------------------------------------------------- + + UNL-SHJY3 + + -------------------------------------------------*/ + +/* I think the IRQ should only get fired if enough CPU cycles have passed, but we don't implement (yet) this part */ +void nes_hengg_shjy3_device::hblank_irq(int scanline, int vblank, int blanked) +{ + if (m_irq_enable & 0x02) + { + if (m_irq_count == 0xff) + { + m_irq_count = m_irq_count_latch; + m_irq_enable = m_irq_enable | ((m_irq_enable & 0x01) << 1); + m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE); + } + else + m_irq_count++; + } +} + +void nes_hengg_shjy3_device::update_banks() +{ + prg8_89(m_mmc_prg_bank[0]); + prg8_ab(m_mmc_prg_bank[1]); + + for (int i = 0; i < 8; i++) + { + UINT8 chr_bank = m_mmc_vrom_bank[i] | (m_mmc_extra_bank[i] << 4); + if (m_mmc_vrom_bank[i] == 0xc8) + { + m_chr_mode = 0; + continue; + } + else if (m_mmc_vrom_bank[i] == 0x88) + { + m_chr_mode = 1; + continue; + } + if ((m_mmc_vrom_bank[i] == 4 || m_mmc_vrom_bank[i] == 5) && !m_chr_mode) + chr1_x(i, chr_bank & 1, CHRRAM); + else + chr1_x(i, chr_bank, CHRROM); + } +} + +WRITE8_MEMBER(nes_hengg_shjy3_device::write_h) +{ + LOG_MMC(("shjy3 write_h, offset: %04x, data: %02x\n", offset, data)); + + if (offset >= 0x3000 && offset <= 0x600c) + { + UINT8 shift = offset & 4; + UINT8 mmc_helper = ((offset & 8) | (offset >> 8)) >> 3; + mmc_helper += 2; + mmc_helper &= 7; + + m_mmc_vrom_bank[mmc_helper] = (m_mmc_vrom_bank[mmc_helper] & (0xf0 >> shift)) | ((data & 0x0f) << shift); + if (shift) + m_mmc_extra_bank[mmc_helper] = data >> 4; + } + else + { + switch (offset) + { + case 0x0010: + m_mmc_prg_bank[0] = data; + break; + case 0x2010: + m_mmc_prg_bank[1] = data; + break; + case 0x1400: + switch (data & 0x03) + { + case 0: set_nt_mirroring(PPU_MIRROR_VERT); break; + case 1: set_nt_mirroring(PPU_MIRROR_HORZ); break; + case 2: set_nt_mirroring(PPU_MIRROR_LOW); break; + case 3: set_nt_mirroring(PPU_MIRROR_HIGH); break; + } + break; + case 0x7000: + m_irq_count_latch = (m_irq_count_latch & 0xf0) | (data & 0x0f); + break; + case 0x7004: + m_irq_count_latch = (m_irq_count_latch & 0x0f) | ((data & 0x0f) << 4); + break; + case 0x7008: + m_irq_enable = data & 0x03; + if (m_irq_enable & 0x02) + m_irq_count = m_irq_count_latch; + break; + } + } + update_banks(); +} diff --git a/src/devices/bus/nes/hes.c b/src/devices/bus/nes/hes.c deleted file mode 100644 index ddfda0590d8..00000000000 --- a/src/devices/bus/nes/hes.c +++ /dev/null @@ -1,87 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Fabio Priuli -/*********************************************************************************************************** - - - NES/Famicom cartridge emulation for HES PCBs - - - Here we emulate the HES PCBs (both the one with hardwired mirroring and the one with mapper-controlled - mirroring used by HES 6 in 1) [mapper 113] - - - ***********************************************************************************************************/ - - -#include "emu.h" -#include "hes.h" - - -#ifdef NES_PCB_DEBUG -#define VERBOSE 1 -#else -#define VERBOSE 0 -#endif - -#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) - - -//------------------------------------------------- -// constructor -//------------------------------------------------- - -const device_type NES_HES = &device_creator; - - -nes_hes_device::nes_hes_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_HES, "NES Cart HES PCB", tag, owner, clock, "nes_hes", __FILE__) -{ -} - - -void nes_hes_device::device_start() -{ - common_start(); -} - -void nes_hes_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0); - chr8(0, m_chr_source); -} - - - -/*------------------------------------------------- - mapper specific handlers - -------------------------------------------------*/ - -/*------------------------------------------------- - - Bootleg Board by HES (also used by others) - - Games: AV Hanafuda Club, AV Soccer, Papillon, Sidewinder, - Total Funpack - - Actually, two variant: one for HES 6-in-1 with mirroring control - and one for AV Soccer and others with hardwired mirroring - - iNES: mapper 113 - - In MESS: Supported. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_hes_device::write_l) -{ - LOG_MMC(("hes write_l, offset: %04x, data: %02x\n", offset, data)); - - if (!(offset & 0x100)) - { - prg32((data & 0x38) >> 3); - chr8((data & 0x07) | ((data & 0x40) >> 3), CHRROM); - if (m_pcb_ctrl_mirror) - set_nt_mirroring(BIT(data, 7) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ); - } -} diff --git a/src/devices/bus/nes/hes.cpp b/src/devices/bus/nes/hes.cpp new file mode 100644 index 00000000000..ddfda0590d8 --- /dev/null +++ b/src/devices/bus/nes/hes.cpp @@ -0,0 +1,87 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for HES PCBs + + + Here we emulate the HES PCBs (both the one with hardwired mirroring and the one with mapper-controlled + mirroring used by HES 6 in 1) [mapper 113] + + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "hes.h" + + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_HES = &device_creator; + + +nes_hes_device::nes_hes_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_HES, "NES Cart HES PCB", tag, owner, clock, "nes_hes", __FILE__) +{ +} + + +void nes_hes_device::device_start() +{ + common_start(); +} + +void nes_hes_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + Bootleg Board by HES (also used by others) + + Games: AV Hanafuda Club, AV Soccer, Papillon, Sidewinder, + Total Funpack + + Actually, two variant: one for HES 6-in-1 with mirroring control + and one for AV Soccer and others with hardwired mirroring + + iNES: mapper 113 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_hes_device::write_l) +{ + LOG_MMC(("hes write_l, offset: %04x, data: %02x\n", offset, data)); + + if (!(offset & 0x100)) + { + prg32((data & 0x38) >> 3); + chr8((data & 0x07) | ((data & 0x40) >> 3), CHRROM); + if (m_pcb_ctrl_mirror) + set_nt_mirroring(BIT(data, 7) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ); + } +} diff --git a/src/devices/bus/nes/hosenkan.c b/src/devices/bus/nes/hosenkan.c deleted file mode 100644 index fae439ac903..00000000000 --- a/src/devices/bus/nes/hosenkan.c +++ /dev/null @@ -1,155 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Fabio Priuli -/*********************************************************************************************************** - - - NES/Famicom cartridge emulation for Hosenkan PCBs - - - ***********************************************************************************************************/ - - -#include "emu.h" -#include "hosenkan.h" - -#include "cpu/m6502/m6502.h" -#include "video/ppu2c0x.h" // this has to be included so that IRQ functions can access PPU_BOTTOM_VISIBLE_SCANLINE - - -#ifdef NES_PCB_DEBUG -#define VERBOSE 1 -#else -#define VERBOSE 0 -#endif - -#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) - - -//------------------------------------------------- -// constructor -//------------------------------------------------- - -const device_type NES_HOSENKAN = &device_creator; - - -nes_hosenkan_device::nes_hosenkan_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_HOSENKAN, "NES Cart HOSENKAN PCB", tag, owner, clock, "nes_hosenkan", __FILE__) -{ -} - - - - -void nes_hosenkan_device::device_start() -{ - common_start(); - save_item(NAME(m_irq_enable)); - save_item(NAME(m_irq_count)); - save_item(NAME(m_irq_count_latch)); - save_item(NAME(m_irq_clear)); - save_item(NAME(m_latch)); -} - -void nes_hosenkan_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32((m_prg_chunks - 1) >> 1); - chr8(0, m_chr_source); - - m_latch = 0; - m_irq_enable = 0; - m_irq_count = m_irq_count_latch = 0; - m_irq_clear = 0; -} - - - -/*------------------------------------------------- - mapper specific handlers - -------------------------------------------------*/ - -/*------------------------------------------------- - - Bootleg Board by Hosenkan - - Games: Pocahontas, Super Donkey Kong - - iNES: mapper 182 - - In MESS: Supported. - - -------------------------------------------------*/ - -// same as MMC3! -void nes_hosenkan_device::hblank_irq( int scanline, int vblank, int blanked ) -{ - if (scanline < PPU_BOTTOM_VISIBLE_SCANLINE) - { - int prior_count = m_irq_count; - if ((m_irq_count == 0) || m_irq_clear) - m_irq_count = m_irq_count_latch; - else - m_irq_count--; - - if (m_irq_enable && !blanked && (m_irq_count == 0) && (prior_count || m_irq_clear)) - { - LOG_MMC(("irq fired, scanline: %d (MAME %d, beam pos: %d)\n", scanline, - machine().first_screen()->vpos(), machine().first_screen()->hpos())); - m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE); - } - } - m_irq_clear = 0; -} - -WRITE8_MEMBER(nes_hosenkan_device::write_h) -{ - LOG_MMC(("hosenkan write_h, offset: %04x, data: %02x\n", offset, data)); - - switch (offset & 0x7003) - { - case 0x0001: - set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); - break; - case 0x2000: - m_latch = data; - break; - case 0x4000: - switch (m_latch) - { - case 0: - chr2_0(data >> 1, CHRROM); - break; - case 1: - chr1_5(data, CHRROM); - break; - case 2: - chr2_2(data >> 1, CHRROM); - break; - case 3: - chr1_7(data, CHRROM); - break; - case 4: - prg8_89(data); - break; - case 5: - prg8_ab(data); - break; - case 6: - chr1_4(data, CHRROM); - break; - case 7: - chr1_6(data, CHRROM); - break; - } - break; - case 0x6003: - if (data) - { - m_irq_count = data; - m_irq_enable = 1; - } - else - m_irq_enable = 0; - break; - } -} diff --git a/src/devices/bus/nes/hosenkan.cpp b/src/devices/bus/nes/hosenkan.cpp new file mode 100644 index 00000000000..fae439ac903 --- /dev/null +++ b/src/devices/bus/nes/hosenkan.cpp @@ -0,0 +1,155 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for Hosenkan PCBs + + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "hosenkan.h" + +#include "cpu/m6502/m6502.h" +#include "video/ppu2c0x.h" // this has to be included so that IRQ functions can access PPU_BOTTOM_VISIBLE_SCANLINE + + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_HOSENKAN = &device_creator; + + +nes_hosenkan_device::nes_hosenkan_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_HOSENKAN, "NES Cart HOSENKAN PCB", tag, owner, clock, "nes_hosenkan", __FILE__) +{ +} + + + + +void nes_hosenkan_device::device_start() +{ + common_start(); + save_item(NAME(m_irq_enable)); + save_item(NAME(m_irq_count)); + save_item(NAME(m_irq_count_latch)); + save_item(NAME(m_irq_clear)); + save_item(NAME(m_latch)); +} + +void nes_hosenkan_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32((m_prg_chunks - 1) >> 1); + chr8(0, m_chr_source); + + m_latch = 0; + m_irq_enable = 0; + m_irq_count = m_irq_count_latch = 0; + m_irq_clear = 0; +} + + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + Bootleg Board by Hosenkan + + Games: Pocahontas, Super Donkey Kong + + iNES: mapper 182 + + In MESS: Supported. + + -------------------------------------------------*/ + +// same as MMC3! +void nes_hosenkan_device::hblank_irq( int scanline, int vblank, int blanked ) +{ + if (scanline < PPU_BOTTOM_VISIBLE_SCANLINE) + { + int prior_count = m_irq_count; + if ((m_irq_count == 0) || m_irq_clear) + m_irq_count = m_irq_count_latch; + else + m_irq_count--; + + if (m_irq_enable && !blanked && (m_irq_count == 0) && (prior_count || m_irq_clear)) + { + LOG_MMC(("irq fired, scanline: %d (MAME %d, beam pos: %d)\n", scanline, + machine().first_screen()->vpos(), machine().first_screen()->hpos())); + m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE); + } + } + m_irq_clear = 0; +} + +WRITE8_MEMBER(nes_hosenkan_device::write_h) +{ + LOG_MMC(("hosenkan write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x7003) + { + case 0x0001: + set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + break; + case 0x2000: + m_latch = data; + break; + case 0x4000: + switch (m_latch) + { + case 0: + chr2_0(data >> 1, CHRROM); + break; + case 1: + chr1_5(data, CHRROM); + break; + case 2: + chr2_2(data >> 1, CHRROM); + break; + case 3: + chr1_7(data, CHRROM); + break; + case 4: + prg8_89(data); + break; + case 5: + prg8_ab(data); + break; + case 6: + chr1_4(data, CHRROM); + break; + case 7: + chr1_6(data, CHRROM); + break; + } + break; + case 0x6003: + if (data) + { + m_irq_count = data; + m_irq_enable = 1; + } + else + m_irq_enable = 0; + break; + } +} diff --git a/src/devices/bus/nes/irem.c b/src/devices/bus/nes/irem.c deleted file mode 100644 index 43f5bab1d7d..00000000000 --- a/src/devices/bus/nes/irem.c +++ /dev/null @@ -1,352 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Fabio Priuli -/*********************************************************************************************************** - - - NES/Famicom cartridge emulation for IREM PCBs - - - Here we emulate the following PCBs - - * IREM LROG017 [mapper 77] - * IREM Holy Diver [mapper 78] - * IREM TAM-S1 [mapper 97] - * IREM G101 [mapper 32] - * IREM H3001 [mapper 65] - - ***********************************************************************************************************/ - - -#include "emu.h" -#include "irem.h" - -#include "cpu/m6502/m6502.h" - -#ifdef NES_PCB_DEBUG -#define VERBOSE 1 -#else -#define VERBOSE 0 -#endif - -#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) - - -//------------------------------------------------- -// constructor -//------------------------------------------------- - -const device_type NES_LROG017 = &device_creator; -const device_type NES_HOLYDIVR = &device_creator; -const device_type NES_TAM_S1 = &device_creator; -const device_type NES_G101 = &device_creator; -const device_type NES_H3001 = &device_creator; - - -nes_lrog017_device::nes_lrog017_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_LROG017, "NES Cart Irem Discrete 74*161/161/21/138 PCB", tag, owner, clock, "nes_lrog017", __FILE__) -{ -} - -nes_holydivr_device::nes_holydivr_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_HOLYDIVR, "NES Cart Irem Holy Diver PCB", tag, owner, clock, "nes_holydivr", __FILE__) -{ -} - -nes_tam_s1_device::nes_tam_s1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_TAM_S1, "NES Cart Irem TAM-S1 PCB", tag, owner, clock, "nes_tam_s1", __FILE__) -{ -} - -nes_g101_device::nes_g101_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_G101, "NES Cart Irem G-101 PCB", tag, owner, clock, "nes_g101", __FILE__) -{ -} - -nes_h3001_device::nes_h3001_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_H3001, "NES Cart Irem H-3001 PCB", tag, owner, clock, "nes_h3001", __FILE__) -{ -} - - - - -void nes_lrog017_device::device_start() -{ - common_start(); -} - -void nes_lrog017_device::pcb_reset() -{ - prg32(0); - chr2_0(0, CHRROM); - chr2_2(0, CHRRAM); - chr2_4(1, CHRRAM); - chr2_6(2, CHRRAM); -} - -void nes_holydivr_device::device_start() -{ - common_start(); -} - -void nes_holydivr_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(0); - prg16_cdef(m_prg_chunks - 1); - chr8(0, m_chr_source); -} - -void nes_tam_s1_device::device_start() -{ - common_start(); -} - -void nes_tam_s1_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(m_prg_chunks - 1); - prg16_cdef(0); - chr8(0, m_chr_source); -} - -void nes_g101_device::device_start() -{ - common_start(); - save_item(NAME(m_latch)); -} - -void nes_g101_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(0); - prg16_cdef(m_prg_chunks - 1); - chr8(0, m_chr_source); - - m_latch = 0; -} - -void nes_h3001_device::device_start() -{ - common_start(); - irq_timer = timer_alloc(TIMER_IRQ); - irq_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1)); - - save_item(NAME(m_irq_enable)); - save_item(NAME(m_irq_count)); - save_item(NAME(m_irq_count_latch)); -} - -void nes_h3001_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(0); - prg16_cdef(m_prg_chunks - 1); - chr8(0, m_chr_source); - - m_irq_enable = 0; - m_irq_count = 0; - m_irq_count_latch = 0; -} - - -/*------------------------------------------------- - mapper specific handlers - -------------------------------------------------*/ - -/*------------------------------------------------- - - Irem LROG017 - Discrete board emulation (74*161/161/21/138) - - Games: Napoleon Senki - - iNES: mapper 77 - - This board should use 2KB of CHRRAM as NTRAM, instead - of using directly 4-screen mirroring, but for the - moment we cheat in this way... - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_lrog017_device::write_h) -{ - LOG_MMC(("lrog017 write_h, offset: %04x, data: %02x\n", offset, data)); - - // this pcb is subject to bus conflict - data = account_bus_conflict(offset, data); - - prg32(data); - chr2_0((data >> 4), CHRROM); -} - -/*------------------------------------------------- - - Irem Holy Diver board emulation - - iNES: mapper 78 (shared with JF-16) - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_holydivr_device::write_h) -{ - LOG_MMC(("holy diver write_h, offset: %04x, data: %02x\n", offset, data)); - - // this pcb is subject to bus conflict - data = account_bus_conflict(offset, data); - - set_nt_mirroring(BIT(data, 3) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ); - chr8(data >> 4, CHRROM); - prg16_89ab(data); -} - -/*------------------------------------------------- - - Irem TAM-S1 board emulation - - Games: Kaiketsu Yanchamaru - - iNES: mapper 97 - - In MESS: Supported. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_tam_s1_device::write_h) -{ - LOG_MMC(("tam s1 write_h, offset: %04x, data: %02x\n", offset, data)); - - if (offset < 0x4000) - { - // this pcb is subject to bus conflict - data = account_bus_conflict(offset, data); - - set_nt_mirroring(BIT(data, 7) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ); - prg16_cdef(data); - } -} - -/*------------------------------------------------- - - Irem G-101 board emulation - - Major League uses hardwired mirroring - - iNES: mapper 32 - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_g101_device::write_h) -{ - LOG_MMC(("g101 write_h, offset: %04x, data: %02x\n", offset, data)); - - switch (offset & 0x7000) - { - case 0x0000: - if (m_latch) - { - prg8_89(0xfe); - prg8_cd(data & 0x1f); - } - else - { - prg8_89(data & 0x1f); - prg8_cd(0xfe); - } - break; - case 0x1000: - m_latch = BIT(data, 1); - if (m_pcb_ctrl_mirror) - set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); - break; - case 0x2000: - prg8_ab(data & 0x1f); - break; - case 0x3000: - chr1_x(offset & 0x07, data & 0x7f, CHRROM); - break; - } -} - -/*------------------------------------------------- - - Irem H-3001 board emulation - - Games: Daiku no Gen San 2 - Akage no Dan no Gyakushuu, - Kaiketsu Yanchamaru 3, Spartan X 2 - - iNES: mapper 65 - - In MESS: Supported. - - -------------------------------------------------*/ - - -void nes_h3001_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) -{ - if (id == TIMER_IRQ) - { - if (m_irq_enable) - { - // 16bit counter, IRQ fired when the counter reaches 0 - // after firing, the counter is *not* reloaded and does not wrap - if (m_irq_count > 0) - m_irq_count--; - - if (!m_irq_count) - { - m_maincpu->set_input_line(M6502_IRQ_LINE, ASSERT_LINE); - m_irq_enable = 0; - } - } - } -} - -WRITE8_MEMBER(nes_h3001_device::write_h) -{ - LOG_MMC(("h3001 write_h, offset %04x, data: %02x\n", offset, data)); - - switch (offset & 0x7fff) - { - case 0x0000: - prg8_89(data); - break; - - case 0x1001: - set_nt_mirroring(BIT(data, 7) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); - break; - - case 0x1003: - m_irq_enable = data & 0x80; - m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); - break; - - case 0x1004: - m_irq_count = m_irq_count_latch; - m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); - break; - - case 0x1005: - m_irq_count_latch = (m_irq_count_latch & 0x00ff) | (data << 8); - break; - - case 0x1006: - m_irq_count_latch = (m_irq_count_latch & 0xff00) | data; - break; - - case 0x2000: - prg8_ab(data); - break; - - case 0x3000: case 0x3001: case 0x3002: case 0x3003: - case 0x3004: case 0x3005: case 0x3006: case 0x3007: - chr1_x(offset & 0x07, data, CHRROM); - break; - - case 0x4000: - prg8_cd(data); - break; - - default: - break; - } -} diff --git a/src/devices/bus/nes/irem.cpp b/src/devices/bus/nes/irem.cpp new file mode 100644 index 00000000000..43f5bab1d7d --- /dev/null +++ b/src/devices/bus/nes/irem.cpp @@ -0,0 +1,352 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for IREM PCBs + + + Here we emulate the following PCBs + + * IREM LROG017 [mapper 77] + * IREM Holy Diver [mapper 78] + * IREM TAM-S1 [mapper 97] + * IREM G101 [mapper 32] + * IREM H3001 [mapper 65] + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "irem.h" + +#include "cpu/m6502/m6502.h" + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_LROG017 = &device_creator; +const device_type NES_HOLYDIVR = &device_creator; +const device_type NES_TAM_S1 = &device_creator; +const device_type NES_G101 = &device_creator; +const device_type NES_H3001 = &device_creator; + + +nes_lrog017_device::nes_lrog017_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_LROG017, "NES Cart Irem Discrete 74*161/161/21/138 PCB", tag, owner, clock, "nes_lrog017", __FILE__) +{ +} + +nes_holydivr_device::nes_holydivr_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_HOLYDIVR, "NES Cart Irem Holy Diver PCB", tag, owner, clock, "nes_holydivr", __FILE__) +{ +} + +nes_tam_s1_device::nes_tam_s1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_TAM_S1, "NES Cart Irem TAM-S1 PCB", tag, owner, clock, "nes_tam_s1", __FILE__) +{ +} + +nes_g101_device::nes_g101_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_G101, "NES Cart Irem G-101 PCB", tag, owner, clock, "nes_g101", __FILE__) +{ +} + +nes_h3001_device::nes_h3001_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_H3001, "NES Cart Irem H-3001 PCB", tag, owner, clock, "nes_h3001", __FILE__) +{ +} + + + + +void nes_lrog017_device::device_start() +{ + common_start(); +} + +void nes_lrog017_device::pcb_reset() +{ + prg32(0); + chr2_0(0, CHRROM); + chr2_2(0, CHRRAM); + chr2_4(1, CHRRAM); + chr2_6(2, CHRRAM); +} + +void nes_holydivr_device::device_start() +{ + common_start(); +} + +void nes_holydivr_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); +} + +void nes_tam_s1_device::device_start() +{ + common_start(); +} + +void nes_tam_s1_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(m_prg_chunks - 1); + prg16_cdef(0); + chr8(0, m_chr_source); +} + +void nes_g101_device::device_start() +{ + common_start(); + save_item(NAME(m_latch)); +} + +void nes_g101_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + + m_latch = 0; +} + +void nes_h3001_device::device_start() +{ + common_start(); + irq_timer = timer_alloc(TIMER_IRQ); + irq_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1)); + + save_item(NAME(m_irq_enable)); + save_item(NAME(m_irq_count)); + save_item(NAME(m_irq_count_latch)); +} + +void nes_h3001_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + + m_irq_enable = 0; + m_irq_count = 0; + m_irq_count_latch = 0; +} + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + Irem LROG017 - Discrete board emulation (74*161/161/21/138) + + Games: Napoleon Senki + + iNES: mapper 77 + + This board should use 2KB of CHRRAM as NTRAM, instead + of using directly 4-screen mirroring, but for the + moment we cheat in this way... + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_lrog017_device::write_h) +{ + LOG_MMC(("lrog017 write_h, offset: %04x, data: %02x\n", offset, data)); + + // this pcb is subject to bus conflict + data = account_bus_conflict(offset, data); + + prg32(data); + chr2_0((data >> 4), CHRROM); +} + +/*------------------------------------------------- + + Irem Holy Diver board emulation + + iNES: mapper 78 (shared with JF-16) + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_holydivr_device::write_h) +{ + LOG_MMC(("holy diver write_h, offset: %04x, data: %02x\n", offset, data)); + + // this pcb is subject to bus conflict + data = account_bus_conflict(offset, data); + + set_nt_mirroring(BIT(data, 3) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ); + chr8(data >> 4, CHRROM); + prg16_89ab(data); +} + +/*------------------------------------------------- + + Irem TAM-S1 board emulation + + Games: Kaiketsu Yanchamaru + + iNES: mapper 97 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_tam_s1_device::write_h) +{ + LOG_MMC(("tam s1 write_h, offset: %04x, data: %02x\n", offset, data)); + + if (offset < 0x4000) + { + // this pcb is subject to bus conflict + data = account_bus_conflict(offset, data); + + set_nt_mirroring(BIT(data, 7) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ); + prg16_cdef(data); + } +} + +/*------------------------------------------------- + + Irem G-101 board emulation + + Major League uses hardwired mirroring + + iNES: mapper 32 + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_g101_device::write_h) +{ + LOG_MMC(("g101 write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x7000) + { + case 0x0000: + if (m_latch) + { + prg8_89(0xfe); + prg8_cd(data & 0x1f); + } + else + { + prg8_89(data & 0x1f); + prg8_cd(0xfe); + } + break; + case 0x1000: + m_latch = BIT(data, 1); + if (m_pcb_ctrl_mirror) + set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + break; + case 0x2000: + prg8_ab(data & 0x1f); + break; + case 0x3000: + chr1_x(offset & 0x07, data & 0x7f, CHRROM); + break; + } +} + +/*------------------------------------------------- + + Irem H-3001 board emulation + + Games: Daiku no Gen San 2 - Akage no Dan no Gyakushuu, + Kaiketsu Yanchamaru 3, Spartan X 2 + + iNES: mapper 65 + + In MESS: Supported. + + -------------------------------------------------*/ + + +void nes_h3001_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (id == TIMER_IRQ) + { + if (m_irq_enable) + { + // 16bit counter, IRQ fired when the counter reaches 0 + // after firing, the counter is *not* reloaded and does not wrap + if (m_irq_count > 0) + m_irq_count--; + + if (!m_irq_count) + { + m_maincpu->set_input_line(M6502_IRQ_LINE, ASSERT_LINE); + m_irq_enable = 0; + } + } + } +} + +WRITE8_MEMBER(nes_h3001_device::write_h) +{ + LOG_MMC(("h3001 write_h, offset %04x, data: %02x\n", offset, data)); + + switch (offset & 0x7fff) + { + case 0x0000: + prg8_89(data); + break; + + case 0x1001: + set_nt_mirroring(BIT(data, 7) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + break; + + case 0x1003: + m_irq_enable = data & 0x80; + m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); + break; + + case 0x1004: + m_irq_count = m_irq_count_latch; + m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); + break; + + case 0x1005: + m_irq_count_latch = (m_irq_count_latch & 0x00ff) | (data << 8); + break; + + case 0x1006: + m_irq_count_latch = (m_irq_count_latch & 0xff00) | data; + break; + + case 0x2000: + prg8_ab(data); + break; + + case 0x3000: case 0x3001: case 0x3002: case 0x3003: + case 0x3004: case 0x3005: case 0x3006: case 0x3007: + chr1_x(offset & 0x07, data, CHRROM); + break; + + case 0x4000: + prg8_cd(data); + break; + + default: + break; + } +} diff --git a/src/devices/bus/nes/jaleco.c b/src/devices/bus/nes/jaleco.c deleted file mode 100644 index 28df5250118..00000000000 --- a/src/devices/bus/nes/jaleco.c +++ /dev/null @@ -1,886 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Fabio Priuli -/*********************************************************************************************************** - - - NES/Famicom cartridge emulation for Jaleco PCBs - - - Here we emulate the following PCBs - - * Jaleco JF-11 [mapper 140] - * Jaleco JF-13 [mapper 86] - * Jaleco JF-16 [mapper 78] - * Jaleco JF-17 [mapper 72] + its variant with samples - * Jaleco JF-19 [mapper 92] + its variant with samples - * Jaleco SS88006 [mapper 18] + its variant(s) with samples - - ***********************************************************************************************************/ - - -#include "emu.h" -#include "jaleco.h" - -#include "cpu/m6502/m6502.h" -#include "sound/samples.h" - -#ifdef NES_PCB_DEBUG -#define VERBOSE 1 -#else -#define VERBOSE 0 -#endif - -#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) - - -//------------------------------------------------- -// constructor -//------------------------------------------------- - -const device_type NES_JF11 = &device_creator; -const device_type NES_JF16 = &device_creator; -const device_type NES_JF17 = &device_creator; -const device_type NES_JF19 = &device_creator; -const device_type NES_SS88006 = &device_creator; -const device_type NES_JF13 = &device_creator; -const device_type NES_JF17_ADPCM = &device_creator; -const device_type NES_JF19_ADPCM = &device_creator; -const device_type NES_JF23 = &device_creator; -const device_type NES_JF24 = &device_creator; -const device_type NES_JF29 = &device_creator; -const device_type NES_JF33 = &device_creator; - - -nes_jf11_device::nes_jf11_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_JF11, "NES Cart Jaleco JF-11 PCB", tag, owner, clock, "nes_jf11", __FILE__) -{ -} - -nes_jf13_device::nes_jf13_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_JF13, "NES Cart Jaleco JF-13 PCB", tag, owner, clock, "nes_jf13", __FILE__), - m_samples(*this, "samples") -{ -} - -nes_jf16_device::nes_jf16_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_JF16, "NES Cart Jaleco JF-16 PCB", tag, owner, clock, "nes_jf16", __FILE__) -{ -} - -nes_jf17_device::nes_jf17_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) - : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source) -{ -} - -nes_jf17_device::nes_jf17_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_JF17, "NES Cart Jaleco JF-17 PCB", tag, owner, clock, "nes_jf17", __FILE__) -{ -} - -nes_jf17_adpcm_device::nes_jf17_adpcm_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_jf17_device(mconfig, NES_JF17_ADPCM, "NES Cart Jaleco JF-17 + ADPCM (Moero!! Pro Tennis) PCB", tag, owner, clock, "nes_jf17_pcm", __FILE__), - m_samples(*this, "samples") -{ -} - -nes_jf19_device::nes_jf19_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) - : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source) -{ -} - -nes_jf19_device::nes_jf19_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_JF19, "NES Cart Jaleco JF-19 (Moero!! Pro Soccer) PCB", tag, owner, clock, "nes_jf19", __FILE__) -{ -} - -nes_jf19_adpcm_device::nes_jf19_adpcm_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_jf19_device(mconfig, NES_JF19_ADPCM, "NES Cart Jaleco JF-19 + ADPCM (Moero!! Pro Yakyuu 88) PCB", tag, owner, clock, "nes_jf19_pcm", __FILE__), - m_samples(*this, "samples") -{ -} - -nes_ss88006_device::nes_ss88006_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) - : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source) -{ -} - -nes_ss88006_device::nes_ss88006_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_SS88006, "NES Cart Jaleco SS88006 PCB", tag, owner, clock, "nes_ss88006", __FILE__) -{ -} - -nes_ss88006_adpcm_device::nes_ss88006_adpcm_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) - : nes_ss88006_device(mconfig, type, name, tag, owner, clock, shortname, source) -{ -} - -nes_jf23_device::nes_jf23_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_ss88006_adpcm_device(mconfig, NES_JF23, "NES Cart Jaleco Shin Moero Pro Yakyuu PCB", tag, owner, clock, "nes_jf23", __FILE__), - m_samples(*this, "samples") -{ -} - -nes_jf24_device::nes_jf24_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_ss88006_adpcm_device(mconfig, NES_JF24, "NES Cart Jaleco Terao no Dosukoi Oozumou PCB", tag, owner, clock, "nes_jf24", __FILE__), - m_samples(*this, "samples") -{ -} - -nes_jf29_device::nes_jf29_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_ss88006_adpcm_device(mconfig, NES_JF29, "NES Cart Jaleco Moe Pro! '90 PCB", tag, owner, clock, "nes_jf29", __FILE__), - m_samples(*this, "samples") -{ -} - -nes_jf33_device::nes_jf33_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_ss88006_adpcm_device(mconfig, NES_JF33, "NES Cart Jaleco Moe Pro! Saikyou-hen PCB", tag, owner, clock, "nes_jf33", __FILE__), - m_samples(*this, "samples") -{ -} - - - -void nes_jf11_device::device_start() -{ - common_start(); -} - -void nes_jf11_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0); - chr8(0, m_chr_source); -} - -void nes_jf13_device::device_start() -{ - common_start(); -} - -void nes_jf13_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0); - chr8(0, m_chr_source); -} - -void nes_jf16_device::device_start() -{ - common_start(); -} - -void nes_jf16_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(0); - prg16_cdef(m_prg_chunks - 1); - chr8(0, m_chr_source); -} - -void nes_jf17_device::device_start() -{ - common_start(); - save_item(NAME(m_latch)); -} - -void nes_jf17_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(0); - prg16_cdef(m_prg_chunks - 1); - chr8(0, m_chr_source); - m_latch = 0; -} - -void nes_jf19_device::device_start() -{ - common_start(); -} - -void nes_jf19_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0); - chr8(0, m_chr_source); -} - -void nes_ss88006_device::device_start() -{ - common_start(); - irq_timer = timer_alloc(TIMER_IRQ); - irq_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1)); - - save_item(NAME(m_mmc_prg_bank)); - save_item(NAME(m_mmc_vrom_bank)); - save_item(NAME(m_irq_enable)); - save_item(NAME(m_irq_count)); - save_item(NAME(m_irq_count_latch)); - save_item(NAME(m_irq_mode)); - save_item(NAME(m_latch)); -} - -void nes_ss88006_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(0); - prg16_cdef(m_prg_chunks - 1); - chr8(0, m_chr_source); - - memset(m_mmc_prg_bank, 0, sizeof(m_mmc_prg_bank)); - memset(m_mmc_vrom_bank, 0, sizeof(m_mmc_vrom_bank)); - m_irq_enable = 0; - m_irq_mode = 0; - m_irq_count = 0; - m_irq_count_latch = 0; - m_latch = 0; -} - - -/*------------------------------------------------- - mapper specific handlers - -------------------------------------------------*/ - -/*------------------------------------------------- - - Jaleco JF-11, JF-12 & JF-14 boards emulation - - Games: Bio Senshi Dan, Mississippi Satsujin Jiken - - iNES: mapper 140 - - In MESS: Supported. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_jf11_device::write_m) -{ - LOG_MMC(("jf11 write_m, offset: %04x, data: %02x\n", offset, data)); - chr8(data, CHRROM); - prg32(data >> 4); -} - -/*------------------------------------------------- - - Jaleco JF-13 board emulation - - Games: Moero Pro Yakyuu - - Note: we don't emulate the additional sound hardware. - - iNES: mapper 86 - - In MESS: Supported. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_jf13_device::write_m) -{ - LOG_MMC(("jf13 write_m, offset: %04x, data: %02x\n", offset, data)); - - if (offset < 0x1000) - { - prg32((data >> 4) & 0x03); - chr8(((data >> 4) & 0x04) | (data & 0x03), CHRROM); - } - else - { -// printf("sample write: offset: %04x, data: %02x\n", offset, data); - if (data & 0x20) - m_samples->start(data & 0x0f, data & 0x0f); - else - m_samples->stop_all(); - } -} - -/*------------------------------------------------- - - Jaleco JF-16 board emulation - - iNES: mapper 78 (shared with a diff Irem board) - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_jf16_device::write_h) -{ - LOG_MMC(("jf16 write_h, offset: %04x, data: %02x\n", offset, data)); - - // this pcb is subject to bus conflict - data = account_bus_conflict(offset, data); - - set_nt_mirroring(BIT(data, 3) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW); - chr8(data >> 4, CHRROM); - prg16_89ab(data); -} - - -/*------------------------------------------------- - - Jaleco JF-17 boards emulation - - Note: we don't emulate the additional sound hardware - for Moero!! Pro Tennis - - Games: Moero!! Juudou Warriors, Moero!! Pro Tennis, Pinball - Quest Jpn - - iNES: mapper 72 - - In MESS: Supported, see below for the Moero Pro Tennis - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_jf17_device::write_h) -{ - LOG_MMC(("jf17 write_h, offset: %04x, data: %02x\n", offset, data)); - - // this pcb is subject to bus conflict - data = account_bus_conflict(offset, data); - - if (BIT(m_latch, 7) && !BIT(data, 7)) - prg16_89ab(m_latch & 0x07); - if (BIT(m_latch, 6) && !BIT(data, 6)) - chr8(m_latch & 0x0f, CHRROM); - - m_latch = data; -} - -WRITE8_MEMBER(nes_jf17_adpcm_device::write_h) -{ - LOG_MMC(("jf17 + ADPCM write_h, offset: %04x, data: %02x\n", offset, data)); - - // this pcb is subject to bus conflict - data = account_bus_conflict(offset, data); - - if (BIT(m_latch, 7) && !BIT(data, 7)) - prg16_89ab(m_latch & 0x07); - if (BIT(m_latch, 6) && !BIT(data, 6)) - chr8(m_latch & 0x0f, CHRROM); - if (BIT(data, 5) && !BIT(data,4)) - { -// printf("sample write: offset: %04x, data: %02x\n", offset, data); - m_samples->start(offset & 0x1f, offset & 0x1f); - } - - m_latch = data; -} - -/*------------------------------------------------- - - Jaleco JF-19 boards emulation - - Note: we don't emulate the additional sound hardware. - - Games: Moero Pro Soccer, Moero Pro Yakyuu '88 - - iNES: mapper 92 - - In MESS: Supported, see below for the Moero Pro Yakyuu '88 - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_jf19_device::write_h) -{ - LOG_MMC(("jf19 write_h, offset: %04x, data: %02x\n", offset, data)); - - // this pcb is subject to bus conflict - data = account_bus_conflict(offset, data); - - if (BIT(data, 7)) - prg16_cdef(data & 0x0f); - if (BIT(data, 6)) - chr8(data & 0x0f, CHRROM); -} - -WRITE8_MEMBER(nes_jf19_adpcm_device::write_h) -{ - LOG_MMC(("jf19 + ADPCM write_h, offset: %04x, data: %02x\n", offset, data)); - - // this pcb is subject to bus conflict - data = account_bus_conflict(offset, data); - - if (BIT(data, 7)) - prg16_cdef(data & 0x0f); - if (BIT(data, 6)) - chr8(data & 0x0f, CHRROM); - if (BIT(data, 5) && !BIT(data,4)) - { -// printf("sample write: offset: %04x, data: %02x\n", offset, data); - m_samples->start(offset & 0x1f, offset & 0x1f); - } -} - -/*------------------------------------------------- - - Jaleco SS88006 board emulation, aka JF-27, JF-29, JF-30, ..., - JF-38, JF-40, JF-41 - - Games: Lord of King, Magic John, Moe Pro '90, Ninja Jajamaru, - Pizza Pop, Plasma Ball - - iNES: mapper 18 - - In MESS: Supported, see below for the games with samples - - -------------------------------------------------*/ - -void nes_ss88006_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) -{ - if (id == TIMER_IRQ) - { - if (m_irq_enable) - { - if (m_irq_mode & 0x08) // 4bits counter - { - if (!(m_irq_count & 0x000f)) - { - m_maincpu->set_input_line(M6502_IRQ_LINE, ASSERT_LINE); - m_irq_count = (m_irq_count & 0xfff0) | 0x000f; - } - else - m_irq_count = (m_irq_count & 0xfff0) | ((m_irq_count & 0x000f) - 1); - } - else if (m_irq_mode & 0x04) // 8bits counter - { - if (!(m_irq_count & 0x00ff)) - { - m_maincpu->set_input_line(M6502_IRQ_LINE, ASSERT_LINE); - m_irq_count = (m_irq_count & 0xff00) | 0x00ff; - } - else - m_irq_count = (m_irq_count & 0xff00) | ((m_irq_count & 0x00ff) - 1); - } - else if (m_irq_mode & 0x02) // 12bits counter - { - if (!(m_irq_count & 0x0fff)) - { - m_maincpu->set_input_line(M6502_IRQ_LINE, ASSERT_LINE); - m_irq_count = (m_irq_count & 0xf000) | 0x0fff; - } - else - m_irq_count = (m_irq_count & 0xf000) | ((m_irq_count & 0x0fff) - 1); - } - else // 16bits counter - { - if (!m_irq_count) - { - m_maincpu->set_input_line(M6502_IRQ_LINE, ASSERT_LINE); - m_irq_count = 0xffff; - } - else - m_irq_count = m_irq_count - 1; - } - } - } -} - -WRITE8_MEMBER(nes_ss88006_device::ss88006_write) -{ - UINT8 bank; - LOG_MMC(("ss88006 write_h, offset: %04x, data: %02x\n", offset, data)); - - switch (offset & 0x7003) - { - case 0x0000: - m_mmc_prg_bank[0] = (m_mmc_prg_bank[0] & 0xf0) | (data & 0x0f); - prg8_89(m_mmc_prg_bank[0]); - break; - case 0x0001: - m_mmc_prg_bank[0] = (m_mmc_prg_bank[0] & 0x0f) | (data << 4); - prg8_89(m_mmc_prg_bank[0]); - break; - case 0x0002: - m_mmc_prg_bank[1] = (m_mmc_prg_bank[1] & 0xf0) | (data & 0x0f); - prg8_ab(m_mmc_prg_bank[1]); - break; - case 0x0003: - m_mmc_prg_bank[1] = (m_mmc_prg_bank[1] & 0x0f) | (data << 4); - prg8_ab(m_mmc_prg_bank[1]); - break; - case 0x1000: - m_mmc_prg_bank[2] = (m_mmc_prg_bank[2] & 0xf0) | (data & 0x0f); - prg8_cd(m_mmc_prg_bank[2]); - break; - case 0x1001: - m_mmc_prg_bank[2] = (m_mmc_prg_bank[2] & 0x0f) | (data << 4); - prg8_cd(m_mmc_prg_bank[2]); - break; - - /* $9002, 3 (1002, 3) uncaught = Jaleco Baseball writes 0 */ - /* believe it's related to battery-backed ram enable/disable */ - - case 0x2000: case 0x2001: case 0x2002: case 0x2003: - case 0x3000: case 0x3001: case 0x3002: case 0x3003: - case 0x4000: case 0x4001: case 0x4002: case 0x4003: - case 0x5000: case 0x5001: case 0x5002: case 0x5003: - bank = ((offset & 0x7000) - 0x2000) / 0x0800 + ((offset & 0x0002) >> 1); - if (offset & 0x0001) - m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0x0f) | ((data & 0x0f)<< 4); - else - m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0xf0) | (data & 0x0f); - - chr1_x(bank, m_mmc_vrom_bank[bank], CHRROM); - break; - - case 0x6000: - m_irq_count_latch = (m_irq_count_latch & 0xfff0) | (data & 0x0f); - break; - case 0x6001: - m_irq_count_latch = (m_irq_count_latch & 0xff0f) | ((data & 0x0f) << 4); - break; - case 0x6002: - m_irq_count_latch = (m_irq_count_latch & 0xf0ff) | ((data & 0x0f) << 8); - break; - case 0x6003: - m_irq_count_latch = (m_irq_count_latch & 0x0fff) | ((data & 0x0f) << 12); - break; - case 0x7000: - m_irq_count = m_irq_count_latch; - m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); - break; - case 0x7001: - m_irq_enable = data & 0x01; - m_irq_mode = data & 0x0e; - m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); - break; - - case 0x7002: - switch (data & 0x03) - { - case 0: set_nt_mirroring(PPU_MIRROR_HORZ); break; - case 1: set_nt_mirroring(PPU_MIRROR_VERT); break; - case 2: set_nt_mirroring(PPU_MIRROR_LOW); break; - case 3: set_nt_mirroring(PPU_MIRROR_HIGH); break; - } - break; - - default: - logerror("Jaleco SS88006 uncaught write, addr: %04x, value: %02x\n", offset + 0x8000, data); - break; - } -} - - -// bits2-bits6 are sample number, bit1 is setup/enable/disable -// program first write sample # + bit1 set to 'init' the sample -// then it writes sample # + bit1 clear to 'start' the sample -void nes_ss88006_adpcm_device::ss88006_adpcm_write(address_space &space, offs_t offset, UINT8 data, samples_device *dev) -{ - LOG_MMC(("ss88006 write_h, offset: %04x, data: %02x\n", offset, data)); - - switch (offset & 0x7003) - { - case 0x7003: - if ((m_latch & 0x7c) == (data & 0x7c)) - { -// printf("sample write: data: %02x\n", data); - if ((m_latch & 2) && !(data & 2)) - dev->start((data >> 2) & 0x1f, (data >> 2) & 0x1f); - } - m_latch = data; - break; - - default: - ss88006_write(space, offset, data); - break; - } -} - -/********************************************************** - - Boards with external samples - (due to undumpable UPD7755C/UPD7756C) - - JF-13 (Moero!! Pro Yakyuu) / iNES mapper 86 - JF-17 (Moero!! Pro Tennis) / iNES mapper 72 + ADPCM - JF-19 (Moero!! Pro Yakyuu '88 - Kettei Ban) / iNES mapper 92 + ADPCM - JF-23 (Shin Moero Pro Yakyuu) / iNES mapper 18 + ADPCM - JF-24 (Terao no Dosukoi Oozumou) / iNES mapper 18 + ADPCM - JF-29 (Moe Pro 90) / iNES mapper 18 + ADPCM - JF-33 (Moe Pro Saikyou-hen) / iNES mapper 18 + ADPCM - - -***********************************************************/ - -static const char *const jf13_sample_names[] = -{ - "*moepro", - "00", // strike - "01", // ball - "02", // time - "03", // out - "04", // safe - "05", // foul - "06", // (catcher obtains the ball) - "07", // you're out - "08", // play ball - "09", // ball four - "10", // home run - "11", // new pitcher - "12", // ouch (pitcher hits batter) - "13", // ?? - "14", // (bat hits the ball) - "15", // (crowd) - 0 -}; - -static const char *const jf17_sample_names[] = -{ - "*mptennis", - "00", // NOT EXISTING? - "01", // NOT EXISTING? - "02", // "love" (points) - "03", // 15 (points) - "04", // 30 (points) - "05", // 40 (points) - "06", // advantage - "07", // (advantage) server - "08", // (advantage) receiver - "09", // all (equal points) - "10", // deuce - "11", // game - "12", // (racket hits ball) - "13", // (crowd?) - "14", // fault - "15", // net - "16", // out - "17", // ?? - "18", // (ball hits player) - "19", // NOT EXISTING? - 0 -}; - -static const char *const jf19_sample_names[] = -{ - "*moepro88", - "00", // out - "01", // safe - "02", // foul - "03", // fair - "04", // strike - "05", // ball - "06", // time - "07", // batter out - "08", // ball four - "09", // home run - "10", // play ball - "11", // new pitcher - "12", // pinch-hit - "13", // (hit by pitch) - "14", // (bat hits the ball) - "15", // (bunt) - "16", // NOT EXISTING? - "17", // (catcher obtains the ball) - "18", // (pitcher obtains the ball) - "19", // (crowd) - 0 -}; - -static const char *const jf23_sample_names[] = -{ - "*smoepro", - "00", // out - "01", // safe - "02", // foul - "03", // NOT EXISTING? - "04", // strike - "05", // ball - "06", // time - "07", // batter out - "08", // ball four - "09", // home run - "10", // play ball - "11", // new pitcher - "12", // pinch-hit - "13", // (hit by pitch) - "14", // (bat hits the ball) - "15", // (bunt) - "16", // (catcher obtains the ball) - "17", // fair - "18", // (catcher obtains the ball, alt) - "19", // (crowd) - 0 -}; - -static const char *const jf24_sample_names[] = -{ - "*terao", - "00", // (tree beating sound) - "01", // Hakkyoyoi - "02", // Nokotta - "03", // Matta Nashi - "04", // Nokotta Nokotta - "05", // Matta Arimasen - 0 -}; - -static const char *const jf29_sample_names[] = -{ - "*moepro90", - "00", // out - "01", // safe - "02", // foul - "03", // Not existing? - "04", // strike - "05", // ball - "06", // time - "07", // batter out - "08", // ball four - "09", // home run - "10", // play ball - "11", // new pitcher - "12", // pinch-hit - "13", // (hit by pitch) - "14", // (bat hits the ball) - "15", // (bunt) - "16", // (catcher obtains the ball, alt) - "17", // (catcher obtains the ball) - "18", // (catcher obtains the ball, alt 2) - "19", // (crowd) - 0 -}; - -static const char *const jf33_sample_names[] = -{ - "*mpsaikyo", - "00", // out - "01", // safe - "02", // foul - "03", // ??? - "04", // strike - "05", // ball - "06", // time - "07", // batter out - "08", // ball four - "09", // home run - "10", // play ball - "11", // new pitcher - "12", // pinch-hit - "13", // (hit by pitch) - "14", // (bat hits the ball) - "15", // (bunt) - "16", // (catcher obtains the ball) - "17", // (catcher obtains the ball, alt) - "18", // ?? - "19", // (crowd) - 0 -}; - -//------------------------------------------------- -// MACHINE_DRIVER -//------------------------------------------------- - -static MACHINE_CONFIG_FRAGMENT( jf13 ) - - // additional sound hardware - MCFG_SPEAKER_STANDARD_MONO("addon") - - MCFG_SOUND_ADD("samples", SAMPLES, 0) - MCFG_SAMPLES_CHANNELS(16) - MCFG_SAMPLES_NAMES(jf13_sample_names) - MCFG_SOUND_ROUTE(ALL_OUTPUTS, "addon", 0.50) -MACHINE_CONFIG_END - -static MACHINE_CONFIG_FRAGMENT( jf17 ) - - // additional sound hardware - MCFG_SPEAKER_STANDARD_MONO("addon") - - MCFG_SOUND_ADD("samples", SAMPLES, 0) - MCFG_SAMPLES_CHANNELS(20) - MCFG_SAMPLES_NAMES(jf17_sample_names) - MCFG_SOUND_ROUTE(ALL_OUTPUTS, "addon", 0.50) -MACHINE_CONFIG_END - -static MACHINE_CONFIG_FRAGMENT( jf19 ) - - // additional sound hardware - MCFG_SPEAKER_STANDARD_MONO("addon") - - MCFG_SOUND_ADD("samples", SAMPLES, 0) - MCFG_SAMPLES_CHANNELS(20) - MCFG_SAMPLES_NAMES(jf19_sample_names) - MCFG_SOUND_ROUTE(ALL_OUTPUTS, "addon", 0.50) -MACHINE_CONFIG_END - -static MACHINE_CONFIG_FRAGMENT( jf23 ) - - // additional sound hardware - MCFG_SPEAKER_STANDARD_MONO("addon") - - MCFG_SOUND_ADD("samples", SAMPLES, 0) - MCFG_SAMPLES_CHANNELS(20) - MCFG_SAMPLES_NAMES(jf23_sample_names) - MCFG_SOUND_ROUTE(ALL_OUTPUTS, "addon", 0.50) -MACHINE_CONFIG_END - -static MACHINE_CONFIG_FRAGMENT( jf24 ) - - // additional sound hardware - MCFG_SPEAKER_STANDARD_MONO("addon") - - MCFG_SOUND_ADD("samples", SAMPLES, 0) - MCFG_SAMPLES_CHANNELS(6) - MCFG_SAMPLES_NAMES(jf24_sample_names) - MCFG_SOUND_ROUTE(ALL_OUTPUTS, "addon", 0.50) -MACHINE_CONFIG_END - -static MACHINE_CONFIG_FRAGMENT( jf29 ) - - // additional sound hardware - MCFG_SPEAKER_STANDARD_MONO("addon") - - MCFG_SOUND_ADD("samples", SAMPLES, 0) - MCFG_SAMPLES_CHANNELS(20) - MCFG_SAMPLES_NAMES(jf29_sample_names) - MCFG_SOUND_ROUTE(ALL_OUTPUTS, "addon", 0.50) -MACHINE_CONFIG_END - -static MACHINE_CONFIG_FRAGMENT( jf33 ) - - // additional sound hardware - MCFG_SPEAKER_STANDARD_MONO("addon") - - MCFG_SOUND_ADD("samples", SAMPLES, 0) - MCFG_SAMPLES_CHANNELS(20) - MCFG_SAMPLES_NAMES(jf33_sample_names) - MCFG_SOUND_ROUTE(ALL_OUTPUTS, "addon", 0.50) -MACHINE_CONFIG_END - -//------------------------------------------------- -// machine_config_additions -//------------------------------------------------- - -machine_config_constructor nes_jf13_device::device_mconfig_additions() const -{ - return MACHINE_CONFIG_NAME( jf13 ); -} - -machine_config_constructor nes_jf17_adpcm_device::device_mconfig_additions() const -{ - return MACHINE_CONFIG_NAME( jf17 ); -} - -machine_config_constructor nes_jf19_adpcm_device::device_mconfig_additions() const -{ - return MACHINE_CONFIG_NAME( jf19 ); -} - -machine_config_constructor nes_jf23_device::device_mconfig_additions() const -{ - return MACHINE_CONFIG_NAME( jf23 ); -} - -machine_config_constructor nes_jf24_device::device_mconfig_additions() const -{ - return MACHINE_CONFIG_NAME( jf24 ); -} - -machine_config_constructor nes_jf29_device::device_mconfig_additions() const -{ - return MACHINE_CONFIG_NAME( jf29 ); -} - -machine_config_constructor nes_jf33_device::device_mconfig_additions() const -{ - return MACHINE_CONFIG_NAME( jf33 ); -} diff --git a/src/devices/bus/nes/jaleco.cpp b/src/devices/bus/nes/jaleco.cpp new file mode 100644 index 00000000000..28df5250118 --- /dev/null +++ b/src/devices/bus/nes/jaleco.cpp @@ -0,0 +1,886 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for Jaleco PCBs + + + Here we emulate the following PCBs + + * Jaleco JF-11 [mapper 140] + * Jaleco JF-13 [mapper 86] + * Jaleco JF-16 [mapper 78] + * Jaleco JF-17 [mapper 72] + its variant with samples + * Jaleco JF-19 [mapper 92] + its variant with samples + * Jaleco SS88006 [mapper 18] + its variant(s) with samples + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "jaleco.h" + +#include "cpu/m6502/m6502.h" +#include "sound/samples.h" + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_JF11 = &device_creator; +const device_type NES_JF16 = &device_creator; +const device_type NES_JF17 = &device_creator; +const device_type NES_JF19 = &device_creator; +const device_type NES_SS88006 = &device_creator; +const device_type NES_JF13 = &device_creator; +const device_type NES_JF17_ADPCM = &device_creator; +const device_type NES_JF19_ADPCM = &device_creator; +const device_type NES_JF23 = &device_creator; +const device_type NES_JF24 = &device_creator; +const device_type NES_JF29 = &device_creator; +const device_type NES_JF33 = &device_creator; + + +nes_jf11_device::nes_jf11_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_JF11, "NES Cart Jaleco JF-11 PCB", tag, owner, clock, "nes_jf11", __FILE__) +{ +} + +nes_jf13_device::nes_jf13_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_JF13, "NES Cart Jaleco JF-13 PCB", tag, owner, clock, "nes_jf13", __FILE__), + m_samples(*this, "samples") +{ +} + +nes_jf16_device::nes_jf16_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_JF16, "NES Cart Jaleco JF-16 PCB", tag, owner, clock, "nes_jf16", __FILE__) +{ +} + +nes_jf17_device::nes_jf17_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +nes_jf17_device::nes_jf17_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_JF17, "NES Cart Jaleco JF-17 PCB", tag, owner, clock, "nes_jf17", __FILE__) +{ +} + +nes_jf17_adpcm_device::nes_jf17_adpcm_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_jf17_device(mconfig, NES_JF17_ADPCM, "NES Cart Jaleco JF-17 + ADPCM (Moero!! Pro Tennis) PCB", tag, owner, clock, "nes_jf17_pcm", __FILE__), + m_samples(*this, "samples") +{ +} + +nes_jf19_device::nes_jf19_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +nes_jf19_device::nes_jf19_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_JF19, "NES Cart Jaleco JF-19 (Moero!! Pro Soccer) PCB", tag, owner, clock, "nes_jf19", __FILE__) +{ +} + +nes_jf19_adpcm_device::nes_jf19_adpcm_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_jf19_device(mconfig, NES_JF19_ADPCM, "NES Cart Jaleco JF-19 + ADPCM (Moero!! Pro Yakyuu 88) PCB", tag, owner, clock, "nes_jf19_pcm", __FILE__), + m_samples(*this, "samples") +{ +} + +nes_ss88006_device::nes_ss88006_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +nes_ss88006_device::nes_ss88006_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_SS88006, "NES Cart Jaleco SS88006 PCB", tag, owner, clock, "nes_ss88006", __FILE__) +{ +} + +nes_ss88006_adpcm_device::nes_ss88006_adpcm_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : nes_ss88006_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +nes_jf23_device::nes_jf23_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_ss88006_adpcm_device(mconfig, NES_JF23, "NES Cart Jaleco Shin Moero Pro Yakyuu PCB", tag, owner, clock, "nes_jf23", __FILE__), + m_samples(*this, "samples") +{ +} + +nes_jf24_device::nes_jf24_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_ss88006_adpcm_device(mconfig, NES_JF24, "NES Cart Jaleco Terao no Dosukoi Oozumou PCB", tag, owner, clock, "nes_jf24", __FILE__), + m_samples(*this, "samples") +{ +} + +nes_jf29_device::nes_jf29_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_ss88006_adpcm_device(mconfig, NES_JF29, "NES Cart Jaleco Moe Pro! '90 PCB", tag, owner, clock, "nes_jf29", __FILE__), + m_samples(*this, "samples") +{ +} + +nes_jf33_device::nes_jf33_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_ss88006_adpcm_device(mconfig, NES_JF33, "NES Cart Jaleco Moe Pro! Saikyou-hen PCB", tag, owner, clock, "nes_jf33", __FILE__), + m_samples(*this, "samples") +{ +} + + + +void nes_jf11_device::device_start() +{ + common_start(); +} + +void nes_jf11_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + +void nes_jf13_device::device_start() +{ + common_start(); +} + +void nes_jf13_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + +void nes_jf16_device::device_start() +{ + common_start(); +} + +void nes_jf16_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); +} + +void nes_jf17_device::device_start() +{ + common_start(); + save_item(NAME(m_latch)); +} + +void nes_jf17_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + m_latch = 0; +} + +void nes_jf19_device::device_start() +{ + common_start(); +} + +void nes_jf19_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + +void nes_ss88006_device::device_start() +{ + common_start(); + irq_timer = timer_alloc(TIMER_IRQ); + irq_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1)); + + save_item(NAME(m_mmc_prg_bank)); + save_item(NAME(m_mmc_vrom_bank)); + save_item(NAME(m_irq_enable)); + save_item(NAME(m_irq_count)); + save_item(NAME(m_irq_count_latch)); + save_item(NAME(m_irq_mode)); + save_item(NAME(m_latch)); +} + +void nes_ss88006_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + + memset(m_mmc_prg_bank, 0, sizeof(m_mmc_prg_bank)); + memset(m_mmc_vrom_bank, 0, sizeof(m_mmc_vrom_bank)); + m_irq_enable = 0; + m_irq_mode = 0; + m_irq_count = 0; + m_irq_count_latch = 0; + m_latch = 0; +} + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + Jaleco JF-11, JF-12 & JF-14 boards emulation + + Games: Bio Senshi Dan, Mississippi Satsujin Jiken + + iNES: mapper 140 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_jf11_device::write_m) +{ + LOG_MMC(("jf11 write_m, offset: %04x, data: %02x\n", offset, data)); + chr8(data, CHRROM); + prg32(data >> 4); +} + +/*------------------------------------------------- + + Jaleco JF-13 board emulation + + Games: Moero Pro Yakyuu + + Note: we don't emulate the additional sound hardware. + + iNES: mapper 86 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_jf13_device::write_m) +{ + LOG_MMC(("jf13 write_m, offset: %04x, data: %02x\n", offset, data)); + + if (offset < 0x1000) + { + prg32((data >> 4) & 0x03); + chr8(((data >> 4) & 0x04) | (data & 0x03), CHRROM); + } + else + { +// printf("sample write: offset: %04x, data: %02x\n", offset, data); + if (data & 0x20) + m_samples->start(data & 0x0f, data & 0x0f); + else + m_samples->stop_all(); + } +} + +/*------------------------------------------------- + + Jaleco JF-16 board emulation + + iNES: mapper 78 (shared with a diff Irem board) + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_jf16_device::write_h) +{ + LOG_MMC(("jf16 write_h, offset: %04x, data: %02x\n", offset, data)); + + // this pcb is subject to bus conflict + data = account_bus_conflict(offset, data); + + set_nt_mirroring(BIT(data, 3) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW); + chr8(data >> 4, CHRROM); + prg16_89ab(data); +} + + +/*------------------------------------------------- + + Jaleco JF-17 boards emulation + + Note: we don't emulate the additional sound hardware + for Moero!! Pro Tennis + + Games: Moero!! Juudou Warriors, Moero!! Pro Tennis, Pinball + Quest Jpn + + iNES: mapper 72 + + In MESS: Supported, see below for the Moero Pro Tennis + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_jf17_device::write_h) +{ + LOG_MMC(("jf17 write_h, offset: %04x, data: %02x\n", offset, data)); + + // this pcb is subject to bus conflict + data = account_bus_conflict(offset, data); + + if (BIT(m_latch, 7) && !BIT(data, 7)) + prg16_89ab(m_latch & 0x07); + if (BIT(m_latch, 6) && !BIT(data, 6)) + chr8(m_latch & 0x0f, CHRROM); + + m_latch = data; +} + +WRITE8_MEMBER(nes_jf17_adpcm_device::write_h) +{ + LOG_MMC(("jf17 + ADPCM write_h, offset: %04x, data: %02x\n", offset, data)); + + // this pcb is subject to bus conflict + data = account_bus_conflict(offset, data); + + if (BIT(m_latch, 7) && !BIT(data, 7)) + prg16_89ab(m_latch & 0x07); + if (BIT(m_latch, 6) && !BIT(data, 6)) + chr8(m_latch & 0x0f, CHRROM); + if (BIT(data, 5) && !BIT(data,4)) + { +// printf("sample write: offset: %04x, data: %02x\n", offset, data); + m_samples->start(offset & 0x1f, offset & 0x1f); + } + + m_latch = data; +} + +/*------------------------------------------------- + + Jaleco JF-19 boards emulation + + Note: we don't emulate the additional sound hardware. + + Games: Moero Pro Soccer, Moero Pro Yakyuu '88 + + iNES: mapper 92 + + In MESS: Supported, see below for the Moero Pro Yakyuu '88 + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_jf19_device::write_h) +{ + LOG_MMC(("jf19 write_h, offset: %04x, data: %02x\n", offset, data)); + + // this pcb is subject to bus conflict + data = account_bus_conflict(offset, data); + + if (BIT(data, 7)) + prg16_cdef(data & 0x0f); + if (BIT(data, 6)) + chr8(data & 0x0f, CHRROM); +} + +WRITE8_MEMBER(nes_jf19_adpcm_device::write_h) +{ + LOG_MMC(("jf19 + ADPCM write_h, offset: %04x, data: %02x\n", offset, data)); + + // this pcb is subject to bus conflict + data = account_bus_conflict(offset, data); + + if (BIT(data, 7)) + prg16_cdef(data & 0x0f); + if (BIT(data, 6)) + chr8(data & 0x0f, CHRROM); + if (BIT(data, 5) && !BIT(data,4)) + { +// printf("sample write: offset: %04x, data: %02x\n", offset, data); + m_samples->start(offset & 0x1f, offset & 0x1f); + } +} + +/*------------------------------------------------- + + Jaleco SS88006 board emulation, aka JF-27, JF-29, JF-30, ..., + JF-38, JF-40, JF-41 + + Games: Lord of King, Magic John, Moe Pro '90, Ninja Jajamaru, + Pizza Pop, Plasma Ball + + iNES: mapper 18 + + In MESS: Supported, see below for the games with samples + + -------------------------------------------------*/ + +void nes_ss88006_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (id == TIMER_IRQ) + { + if (m_irq_enable) + { + if (m_irq_mode & 0x08) // 4bits counter + { + if (!(m_irq_count & 0x000f)) + { + m_maincpu->set_input_line(M6502_IRQ_LINE, ASSERT_LINE); + m_irq_count = (m_irq_count & 0xfff0) | 0x000f; + } + else + m_irq_count = (m_irq_count & 0xfff0) | ((m_irq_count & 0x000f) - 1); + } + else if (m_irq_mode & 0x04) // 8bits counter + { + if (!(m_irq_count & 0x00ff)) + { + m_maincpu->set_input_line(M6502_IRQ_LINE, ASSERT_LINE); + m_irq_count = (m_irq_count & 0xff00) | 0x00ff; + } + else + m_irq_count = (m_irq_count & 0xff00) | ((m_irq_count & 0x00ff) - 1); + } + else if (m_irq_mode & 0x02) // 12bits counter + { + if (!(m_irq_count & 0x0fff)) + { + m_maincpu->set_input_line(M6502_IRQ_LINE, ASSERT_LINE); + m_irq_count = (m_irq_count & 0xf000) | 0x0fff; + } + else + m_irq_count = (m_irq_count & 0xf000) | ((m_irq_count & 0x0fff) - 1); + } + else // 16bits counter + { + if (!m_irq_count) + { + m_maincpu->set_input_line(M6502_IRQ_LINE, ASSERT_LINE); + m_irq_count = 0xffff; + } + else + m_irq_count = m_irq_count - 1; + } + } + } +} + +WRITE8_MEMBER(nes_ss88006_device::ss88006_write) +{ + UINT8 bank; + LOG_MMC(("ss88006 write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x7003) + { + case 0x0000: + m_mmc_prg_bank[0] = (m_mmc_prg_bank[0] & 0xf0) | (data & 0x0f); + prg8_89(m_mmc_prg_bank[0]); + break; + case 0x0001: + m_mmc_prg_bank[0] = (m_mmc_prg_bank[0] & 0x0f) | (data << 4); + prg8_89(m_mmc_prg_bank[0]); + break; + case 0x0002: + m_mmc_prg_bank[1] = (m_mmc_prg_bank[1] & 0xf0) | (data & 0x0f); + prg8_ab(m_mmc_prg_bank[1]); + break; + case 0x0003: + m_mmc_prg_bank[1] = (m_mmc_prg_bank[1] & 0x0f) | (data << 4); + prg8_ab(m_mmc_prg_bank[1]); + break; + case 0x1000: + m_mmc_prg_bank[2] = (m_mmc_prg_bank[2] & 0xf0) | (data & 0x0f); + prg8_cd(m_mmc_prg_bank[2]); + break; + case 0x1001: + m_mmc_prg_bank[2] = (m_mmc_prg_bank[2] & 0x0f) | (data << 4); + prg8_cd(m_mmc_prg_bank[2]); + break; + + /* $9002, 3 (1002, 3) uncaught = Jaleco Baseball writes 0 */ + /* believe it's related to battery-backed ram enable/disable */ + + case 0x2000: case 0x2001: case 0x2002: case 0x2003: + case 0x3000: case 0x3001: case 0x3002: case 0x3003: + case 0x4000: case 0x4001: case 0x4002: case 0x4003: + case 0x5000: case 0x5001: case 0x5002: case 0x5003: + bank = ((offset & 0x7000) - 0x2000) / 0x0800 + ((offset & 0x0002) >> 1); + if (offset & 0x0001) + m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0x0f) | ((data & 0x0f)<< 4); + else + m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0xf0) | (data & 0x0f); + + chr1_x(bank, m_mmc_vrom_bank[bank], CHRROM); + break; + + case 0x6000: + m_irq_count_latch = (m_irq_count_latch & 0xfff0) | (data & 0x0f); + break; + case 0x6001: + m_irq_count_latch = (m_irq_count_latch & 0xff0f) | ((data & 0x0f) << 4); + break; + case 0x6002: + m_irq_count_latch = (m_irq_count_latch & 0xf0ff) | ((data & 0x0f) << 8); + break; + case 0x6003: + m_irq_count_latch = (m_irq_count_latch & 0x0fff) | ((data & 0x0f) << 12); + break; + case 0x7000: + m_irq_count = m_irq_count_latch; + m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); + break; + case 0x7001: + m_irq_enable = data & 0x01; + m_irq_mode = data & 0x0e; + m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); + break; + + case 0x7002: + switch (data & 0x03) + { + case 0: set_nt_mirroring(PPU_MIRROR_HORZ); break; + case 1: set_nt_mirroring(PPU_MIRROR_VERT); break; + case 2: set_nt_mirroring(PPU_MIRROR_LOW); break; + case 3: set_nt_mirroring(PPU_MIRROR_HIGH); break; + } + break; + + default: + logerror("Jaleco SS88006 uncaught write, addr: %04x, value: %02x\n", offset + 0x8000, data); + break; + } +} + + +// bits2-bits6 are sample number, bit1 is setup/enable/disable +// program first write sample # + bit1 set to 'init' the sample +// then it writes sample # + bit1 clear to 'start' the sample +void nes_ss88006_adpcm_device::ss88006_adpcm_write(address_space &space, offs_t offset, UINT8 data, samples_device *dev) +{ + LOG_MMC(("ss88006 write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x7003) + { + case 0x7003: + if ((m_latch & 0x7c) == (data & 0x7c)) + { +// printf("sample write: data: %02x\n", data); + if ((m_latch & 2) && !(data & 2)) + dev->start((data >> 2) & 0x1f, (data >> 2) & 0x1f); + } + m_latch = data; + break; + + default: + ss88006_write(space, offset, data); + break; + } +} + +/********************************************************** + + Boards with external samples + (due to undumpable UPD7755C/UPD7756C) + + JF-13 (Moero!! Pro Yakyuu) / iNES mapper 86 + JF-17 (Moero!! Pro Tennis) / iNES mapper 72 + ADPCM + JF-19 (Moero!! Pro Yakyuu '88 - Kettei Ban) / iNES mapper 92 + ADPCM + JF-23 (Shin Moero Pro Yakyuu) / iNES mapper 18 + ADPCM + JF-24 (Terao no Dosukoi Oozumou) / iNES mapper 18 + ADPCM + JF-29 (Moe Pro 90) / iNES mapper 18 + ADPCM + JF-33 (Moe Pro Saikyou-hen) / iNES mapper 18 + ADPCM + + +***********************************************************/ + +static const char *const jf13_sample_names[] = +{ + "*moepro", + "00", // strike + "01", // ball + "02", // time + "03", // out + "04", // safe + "05", // foul + "06", // (catcher obtains the ball) + "07", // you're out + "08", // play ball + "09", // ball four + "10", // home run + "11", // new pitcher + "12", // ouch (pitcher hits batter) + "13", // ?? + "14", // (bat hits the ball) + "15", // (crowd) + 0 +}; + +static const char *const jf17_sample_names[] = +{ + "*mptennis", + "00", // NOT EXISTING? + "01", // NOT EXISTING? + "02", // "love" (points) + "03", // 15 (points) + "04", // 30 (points) + "05", // 40 (points) + "06", // advantage + "07", // (advantage) server + "08", // (advantage) receiver + "09", // all (equal points) + "10", // deuce + "11", // game + "12", // (racket hits ball) + "13", // (crowd?) + "14", // fault + "15", // net + "16", // out + "17", // ?? + "18", // (ball hits player) + "19", // NOT EXISTING? + 0 +}; + +static const char *const jf19_sample_names[] = +{ + "*moepro88", + "00", // out + "01", // safe + "02", // foul + "03", // fair + "04", // strike + "05", // ball + "06", // time + "07", // batter out + "08", // ball four + "09", // home run + "10", // play ball + "11", // new pitcher + "12", // pinch-hit + "13", // (hit by pitch) + "14", // (bat hits the ball) + "15", // (bunt) + "16", // NOT EXISTING? + "17", // (catcher obtains the ball) + "18", // (pitcher obtains the ball) + "19", // (crowd) + 0 +}; + +static const char *const jf23_sample_names[] = +{ + "*smoepro", + "00", // out + "01", // safe + "02", // foul + "03", // NOT EXISTING? + "04", // strike + "05", // ball + "06", // time + "07", // batter out + "08", // ball four + "09", // home run + "10", // play ball + "11", // new pitcher + "12", // pinch-hit + "13", // (hit by pitch) + "14", // (bat hits the ball) + "15", // (bunt) + "16", // (catcher obtains the ball) + "17", // fair + "18", // (catcher obtains the ball, alt) + "19", // (crowd) + 0 +}; + +static const char *const jf24_sample_names[] = +{ + "*terao", + "00", // (tree beating sound) + "01", // Hakkyoyoi + "02", // Nokotta + "03", // Matta Nashi + "04", // Nokotta Nokotta + "05", // Matta Arimasen + 0 +}; + +static const char *const jf29_sample_names[] = +{ + "*moepro90", + "00", // out + "01", // safe + "02", // foul + "03", // Not existing? + "04", // strike + "05", // ball + "06", // time + "07", // batter out + "08", // ball four + "09", // home run + "10", // play ball + "11", // new pitcher + "12", // pinch-hit + "13", // (hit by pitch) + "14", // (bat hits the ball) + "15", // (bunt) + "16", // (catcher obtains the ball, alt) + "17", // (catcher obtains the ball) + "18", // (catcher obtains the ball, alt 2) + "19", // (crowd) + 0 +}; + +static const char *const jf33_sample_names[] = +{ + "*mpsaikyo", + "00", // out + "01", // safe + "02", // foul + "03", // ??? + "04", // strike + "05", // ball + "06", // time + "07", // batter out + "08", // ball four + "09", // home run + "10", // play ball + "11", // new pitcher + "12", // pinch-hit + "13", // (hit by pitch) + "14", // (bat hits the ball) + "15", // (bunt) + "16", // (catcher obtains the ball) + "17", // (catcher obtains the ball, alt) + "18", // ?? + "19", // (crowd) + 0 +}; + +//------------------------------------------------- +// MACHINE_DRIVER +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( jf13 ) + + // additional sound hardware + MCFG_SPEAKER_STANDARD_MONO("addon") + + MCFG_SOUND_ADD("samples", SAMPLES, 0) + MCFG_SAMPLES_CHANNELS(16) + MCFG_SAMPLES_NAMES(jf13_sample_names) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "addon", 0.50) +MACHINE_CONFIG_END + +static MACHINE_CONFIG_FRAGMENT( jf17 ) + + // additional sound hardware + MCFG_SPEAKER_STANDARD_MONO("addon") + + MCFG_SOUND_ADD("samples", SAMPLES, 0) + MCFG_SAMPLES_CHANNELS(20) + MCFG_SAMPLES_NAMES(jf17_sample_names) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "addon", 0.50) +MACHINE_CONFIG_END + +static MACHINE_CONFIG_FRAGMENT( jf19 ) + + // additional sound hardware + MCFG_SPEAKER_STANDARD_MONO("addon") + + MCFG_SOUND_ADD("samples", SAMPLES, 0) + MCFG_SAMPLES_CHANNELS(20) + MCFG_SAMPLES_NAMES(jf19_sample_names) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "addon", 0.50) +MACHINE_CONFIG_END + +static MACHINE_CONFIG_FRAGMENT( jf23 ) + + // additional sound hardware + MCFG_SPEAKER_STANDARD_MONO("addon") + + MCFG_SOUND_ADD("samples", SAMPLES, 0) + MCFG_SAMPLES_CHANNELS(20) + MCFG_SAMPLES_NAMES(jf23_sample_names) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "addon", 0.50) +MACHINE_CONFIG_END + +static MACHINE_CONFIG_FRAGMENT( jf24 ) + + // additional sound hardware + MCFG_SPEAKER_STANDARD_MONO("addon") + + MCFG_SOUND_ADD("samples", SAMPLES, 0) + MCFG_SAMPLES_CHANNELS(6) + MCFG_SAMPLES_NAMES(jf24_sample_names) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "addon", 0.50) +MACHINE_CONFIG_END + +static MACHINE_CONFIG_FRAGMENT( jf29 ) + + // additional sound hardware + MCFG_SPEAKER_STANDARD_MONO("addon") + + MCFG_SOUND_ADD("samples", SAMPLES, 0) + MCFG_SAMPLES_CHANNELS(20) + MCFG_SAMPLES_NAMES(jf29_sample_names) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "addon", 0.50) +MACHINE_CONFIG_END + +static MACHINE_CONFIG_FRAGMENT( jf33 ) + + // additional sound hardware + MCFG_SPEAKER_STANDARD_MONO("addon") + + MCFG_SOUND_ADD("samples", SAMPLES, 0) + MCFG_SAMPLES_CHANNELS(20) + MCFG_SAMPLES_NAMES(jf33_sample_names) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "addon", 0.50) +MACHINE_CONFIG_END + +//------------------------------------------------- +// machine_config_additions +//------------------------------------------------- + +machine_config_constructor nes_jf13_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( jf13 ); +} + +machine_config_constructor nes_jf17_adpcm_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( jf17 ); +} + +machine_config_constructor nes_jf19_adpcm_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( jf19 ); +} + +machine_config_constructor nes_jf23_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( jf23 ); +} + +machine_config_constructor nes_jf24_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( jf24 ); +} + +machine_config_constructor nes_jf29_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( jf29 ); +} + +machine_config_constructor nes_jf33_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( jf33 ); +} diff --git a/src/devices/bus/nes/jy.c b/src/devices/bus/nes/jy.c deleted file mode 100644 index 31358e2ab16..00000000000 --- a/src/devices/bus/nes/jy.c +++ /dev/null @@ -1,589 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Fabio Priuli -/*********************************************************************************************************** - - - NES/Famicom cartridge emulation for JY Company - - - Here we emulate multiple PCBs by JY Company with weird IRQ mechanisms [mappers 90, 209, 211] - - TODO: long list... - - add dipswitches - - revamp IRQ system - * scanline/hblank irq should fire 8 times per line (currently not possible) - * implement CPU write IRQ (used by any games?) - * possibly implementing 'funky' IRQ mode (unused?) - - ***********************************************************************************************************/ - - -#include "emu.h" -#include "jy.h" - -#include "cpu/m6502/m6502.h" -#include "video/ppu2c0x.h" // this has to be included so that IRQ functions can access PPU_BOTTOM_VISIBLE_SCANLINE - -#ifdef NES_PCB_DEBUG -#define VERBOSE 1 -#else -#define VERBOSE 0 -#endif - -#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) - - -//------------------------------------------------- -// constructor -//------------------------------------------------- - -const device_type NES_JY_TYPEA = &device_creator; -const device_type NES_JY_TYPEB = &device_creator; -const device_type NES_JY_TYPEC = &device_creator; - - -nes_jy_typea_device::nes_jy_typea_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) - : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source) -{ -} - -nes_jy_typea_device::nes_jy_typea_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_JY_TYPEA, "NES Cart JY Company Type A PCB", tag, owner, clock, "nes_jya", __FILE__) -{ -} - -nes_jy_typeb_device::nes_jy_typeb_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) - : nes_jy_typea_device(mconfig, type, name, tag, owner, clock, shortname, source) -{ -} - -nes_jy_typeb_device::nes_jy_typeb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_jy_typea_device(mconfig, NES_JY_TYPEB, "NES Cart JY Company Type B PCB", tag, owner, clock, "nes_jyb", __FILE__) -{ -} - -nes_jy_typec_device::nes_jy_typec_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_jy_typeb_device(mconfig, NES_JY_TYPEC, "NES Cart JY Company Type C PCB", tag, owner, clock, "nes_jyc", __FILE__) -{ -} - - - - -void nes_jy_typea_device::device_start() -{ - common_start(); - irq_timer = timer_alloc(TIMER_IRQ); - irq_timer->reset(); - timer_freq = machine().device("maincpu")->cycles_to_attotime(1); - - save_item(NAME(m_mul)); - save_item(NAME(m_latch)); - save_item(NAME(m_mmc_prg_bank)); - save_item(NAME(m_mmc_nt_bank)); - save_item(NAME(m_mmc_vrom_bank)); - save_item(NAME(m_reg)); - save_item(NAME(m_chr_latch)); - save_item(NAME(m_bank_6000)); - - save_item(NAME(m_irq_prescale)); - save_item(NAME(m_irq_prescale_mask)); - save_item(NAME(m_irq_mode)); - save_item(NAME(m_irq_count)); - save_item(NAME(m_irq_flip)); - save_item(NAME(m_irq_enable)); - save_item(NAME(m_irq_up)); - save_item(NAME(m_irq_down)); -} - -void nes_jy_typea_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0); - chr8(0, m_chr_source); - - // 0x5000-0x5fff - m_mul[0] = 0; - m_mul[1] = 0; - m_latch = 0; - - // 0x8000-0xffff - memset(m_mmc_prg_bank, 0xff, sizeof(m_mmc_prg_bank)); - memset(m_mmc_nt_bank, 0, sizeof(m_mmc_nt_bank)); - memset(m_mmc_vrom_bank, 0xffff, sizeof(m_mmc_vrom_bank)); - memset(m_reg, 0, sizeof(m_reg)); - m_chr_latch[0] = 0; - m_chr_latch[1] = 4; - m_bank_6000 = 0; - - update_prg(); - update_chr(); - update_mirror(); - - m_irq_mode = 0; - m_irq_count = 0; - m_irq_prescale = 0; - m_irq_prescale_mask = 0xff; - m_irq_flip = 0; - m_irq_enable = 0; - m_irq_up = 0; - m_irq_down = 0; -} - - -/*------------------------------------------------- - mapper specific handlers - -------------------------------------------------*/ - -/*------------------------------------------------- - - JY Company Type A board emulation - - iNES: mapper 90 - - -------------------------------------------------*/ - - -READ8_MEMBER(nes_jy_typea_device::nt_r) -{ - int page = ((offset & 0xc00) >> 10); - irq_clock(0, 2); - return m_nt_access[page][offset & 0x3ff]; -} - -READ8_MEMBER(nes_jy_typea_device::chr_r) -{ - int bank = offset >> 10; - irq_clock(0, 2); - return m_chr_access[bank][offset & 0x3ff]; -} - -void nes_jy_typea_device::irq_clock(int mode, int blanked) -{ - bool clock = FALSE, fire = FALSE; - - if (m_irq_mode != mode) - return; - - // no counter changes if both Up/Down are set or clear - if ((m_irq_down && m_irq_up) || (!m_irq_down && !m_irq_up)) - return; - - // update prescaler - if (m_irq_down) - { - if ((m_irq_prescale & m_irq_prescale_mask) == 0) - { - clock = TRUE; - m_irq_prescale = (m_irq_prescale_mask == 7) ? ((m_irq_prescale & 0xf8) | 7) : 0xff; - } - else - m_irq_prescale = (m_irq_prescale_mask == 7) ? ((m_irq_prescale & 0xf8) | ((m_irq_prescale - 1) & m_irq_prescale_mask)) : (m_irq_prescale - 1); - } - - if (m_irq_up) - { - if ((m_irq_prescale & m_irq_prescale_mask) == m_irq_prescale_mask) - { - clock = TRUE; - m_irq_prescale = (m_irq_prescale_mask == 7) ? (m_irq_prescale & 0xf8) : 0; - } - else - m_irq_prescale = (m_irq_prescale_mask == 7) ? ((m_irq_prescale & 0xf8) | ((m_irq_prescale + 1) & m_irq_prescale_mask)) : (m_irq_prescale + 1); - } - - // if prescaler wraps, update count - if (clock) - { - if (m_irq_down) - { - if (m_irq_count == 0) - { - fire = TRUE; - m_irq_count = 0xff; - } - else - m_irq_count--; - } - - if (m_irq_up) - { - if (m_irq_count == 0xff) - { - fire = TRUE; - m_irq_count = 0; - } - else - m_irq_count++; - } - - - // if count wraps, check if IRQ is enabled - if (fire && m_irq_enable && !blanked) - m_maincpu->set_input_line(M6502_IRQ_LINE, ASSERT_LINE); - - } -} - -void nes_jy_typea_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) -{ - if (id == TIMER_IRQ) - { - irq_clock(0, 0); - } -} - -void nes_jy_typea_device::scanline_irq(int scanline, int vblank, int blanked) -{ - if (scanline < PPU_BOTTOM_VISIBLE_SCANLINE) - irq_clock(blanked, 1); -} - - -// 0x5000-0x5fff : sort of protection? -READ8_MEMBER(nes_jy_typea_device::read_l) -{ - LOG_MMC(("JY Company write_m, offset: %04x\n", offset)); - offset += 0x100; - - if (offset >= 0x1000 && offset < 0x1800) - { - // bit6/bit7 DSW read - return m_open_bus & 0x3f; - } - - if (offset >= 0x1800) - { - if ((offset & 7) == 0) - return (m_mul[0] * m_mul[1]) & 0xff; - if ((offset & 7) == 1) - return ((m_mul[0] * m_mul[1]) >> 8) & 0xff; - if ((offset & 7) == 3) - return m_latch; - } - - return m_open_bus; // open bus -} - -WRITE8_MEMBER(nes_jy_typea_device::write_l) -{ - LOG_MMC(("JY Company write_m, offset: %04x, data: %02x\n", offset, data)); - offset += 0x100; - - if (offset >= 0x1800) - { - if ((offset & 7) == 0) - m_mul[0] = data; - if ((offset & 7) == 1) - m_mul[1] = data; - if ((offset & 7) == 3) - m_latch = data; - } -} - -// 0x6000-0x7fff : WRAM or open bus -READ8_MEMBER(nes_jy_typea_device::read_m) -{ - LOG_MMC(("JY Company write_m, offset: %04x\n", offset)); - - if (m_reg[0] & 0x80) - return m_prg[(m_bank_6000 & m_prg_mask) * 0x2000 + (offset & 0x1fff)]; - - return m_open_bus; // open bus -} - - -inline UINT8 nes_jy_typea_device::unscramble(UINT8 bank) -{ - return BITSWAP8(bank & 0x7f,7,0,1,2,3,4,5,6); -} - -void nes_jy_typea_device::update_prg() -{ - UINT8 exPrg = (m_reg[3] & 0x06) << 5; - UINT8 last = (m_reg[0] & 0x04) ? m_mmc_prg_bank[3] : 0x3f; - - switch (m_reg[0] & 0x03) - { - case 0: // 32KB - prg32((last & 0x0f) | (exPrg >> 2)); - m_bank_6000 = (((m_mmc_prg_bank[3] * 4) + 3) & 0x3f) | (exPrg >> 2); - break; - - case 1: // 16KB - prg16_89ab((m_mmc_prg_bank[1] & 0x1f) | (exPrg >> 1)); - prg16_cdef((last & 0x1f) | (exPrg >> 1)); - m_bank_6000 = (((m_mmc_prg_bank[3] * 2) + 1) & 0x1f) | (exPrg >> 1); - break; - - case 2: // 8KB - prg8_89(m_mmc_prg_bank[0] | exPrg); - prg8_ab(m_mmc_prg_bank[1] | exPrg); - prg8_cd(m_mmc_prg_bank[2] | exPrg); - prg8_ef(last | exPrg); - m_bank_6000 = m_mmc_prg_bank[3] | exPrg; - break; - - case 3: // 8KB Alt - prg8_89((unscramble(m_mmc_prg_bank[0]) & 0x3f) | exPrg); - prg8_ab((unscramble(m_mmc_prg_bank[1]) & 0x3f) | exPrg); - prg8_cd((unscramble(m_mmc_prg_bank[2]) & 0x3f) | exPrg); - if (m_reg[0] & 0x04) - prg8_ef((unscramble(m_mmc_prg_bank[3]) & 0x3f) | exPrg); - else - prg8_ef((unscramble(last) & 0x3f) | exPrg); - m_bank_6000 = (unscramble(m_mmc_prg_bank[3]) & 0x3f) | exPrg; - break; - } -} - -void nes_jy_typea_device::update_chr() -{ - // in 1KB & 2KB mode, PPU 0x800-0xfff always mirrors 0x000-0x7ff (0x1800-0x1fff not affected) - int chr_mirror_mode = BIT(m_reg[3], 7) << 1; - - // Case (m_reg[3] & 0x20 == 0) - // Block mode enabled: in this case lower bits select a 256KB page inside CHRROM - // and the low bytes of m_mmc_vrom_bank select the banks inside such a page - - // docs suggest m_reg[3] & 0x1f for chr_page below, - // but 45 in 1 (JY-120A) menu requires to use this (from NEStopia) - UINT8 chr_page = (m_reg[3] & 1) | ((m_reg[3] & 0x18) >> 2); - UINT32 extra_chr_base = BIT(m_reg[3], 5) ? 0 : (chr_page * 0x100); - UINT32 extra_chr_mask = BIT(m_reg[3], 5) ? 0xffffff : 0xff; - - switch (m_reg[0] & 0x18) - { - case 0x00: // 8KB - extra_chr_base >>= 3; - extra_chr_mask >>= 3; - chr8(extra_chr_base | (m_mmc_vrom_bank[0] & extra_chr_mask), m_chr_source); - break; - - case 0x08: // 4KB - extra_chr_base >>= 2; - extra_chr_mask >>= 2; - // Type A & B games have fixed m_chr_latch[0] = 0 and m_chr_latch[1] = 4 - // Type C games can change them at each CHR access! - chr4_0(extra_chr_base | (m_mmc_vrom_bank[m_chr_latch[0]] & extra_chr_mask), m_chr_source); - chr4_4(extra_chr_base | (m_mmc_vrom_bank[m_chr_latch[1]] & extra_chr_mask), m_chr_source); - break; - - case 0x10: // 2KB - extra_chr_base >>= 1; - extra_chr_mask >>= 1; - chr2_0(extra_chr_base | (m_mmc_vrom_bank[0] & extra_chr_mask), m_chr_source); - chr2_2(extra_chr_base | (m_mmc_vrom_bank[2 ^ chr_mirror_mode] & extra_chr_mask), m_chr_source); - chr2_4(extra_chr_base | (m_mmc_vrom_bank[4] & extra_chr_mask), m_chr_source); - chr2_6(extra_chr_base | (m_mmc_vrom_bank[6] & extra_chr_mask), m_chr_source); - break; - - case 0x18: // 1KB - chr1_0(extra_chr_base | (m_mmc_vrom_bank[0] & extra_chr_mask), m_chr_source); - chr1_1(extra_chr_base | (m_mmc_vrom_bank[1] & extra_chr_mask), m_chr_source); - chr1_2(extra_chr_base | (m_mmc_vrom_bank[2 ^ chr_mirror_mode] & extra_chr_mask), m_chr_source); - chr1_3(extra_chr_base | (m_mmc_vrom_bank[3 ^ chr_mirror_mode] & extra_chr_mask), m_chr_source); - chr1_4(extra_chr_base | (m_mmc_vrom_bank[4] & extra_chr_mask), m_chr_source); - chr1_5(extra_chr_base | (m_mmc_vrom_bank[5] & extra_chr_mask), m_chr_source); - chr1_6(extra_chr_base | (m_mmc_vrom_bank[6] & extra_chr_mask), m_chr_source); - chr1_7(extra_chr_base | (m_mmc_vrom_bank[7] & extra_chr_mask), m_chr_source); - break; - } -} - -void nes_jy_typea_device::update_mirror_typea() -{ - switch (m_reg[1] & 3) - { - case 0: set_nt_mirroring(PPU_MIRROR_VERT); break; - case 1: set_nt_mirroring(PPU_MIRROR_HORZ); break; - case 2: set_nt_mirroring(PPU_MIRROR_LOW); break; - case 3: set_nt_mirroring(PPU_MIRROR_HIGH); break; - } -} - -void nes_jy_typea_device::update_banks(int reg) -{ - switch (reg & 3) - { - case 0: - update_prg(); - update_chr(); - update_mirror(); - break; - case 1: - update_mirror(); - break; - case 2: - update_mirror(); - break; - case 3: - update_prg(); - update_chr(); - break; - } -} - - -WRITE8_MEMBER(nes_jy_typea_device::write_h) -{ - LOG_MMC(("JY Company write_m, offset: %04x, data: %02x\n", offset, data)); - - switch (offset & 0x7000) - { - case 0x0000: - offset &= 3; - data &= 0x3f; - if (m_mmc_prg_bank[offset] != data) - { - m_mmc_prg_bank[offset] = data; - update_prg(); - } - break; - case 0x1000: - offset &= 7; - if ((m_mmc_vrom_bank[offset] & 0xff) != data) - { - m_mmc_vrom_bank[offset] = (m_mmc_vrom_bank[offset] & 0xff00) | data; - update_chr(); - } - break; - case 0x2000: - offset &= 7; - if ((m_mmc_vrom_bank[offset] & 0xff00) != (data << 8)) - { - m_mmc_vrom_bank[offset] = (m_mmc_vrom_bank[offset] & 0x00ff) | (data << 8); - update_chr(); - } - break; - case 0x3000: - if (!(offset & 4)) - { - offset &= 3; - m_mmc_nt_bank[offset] = (m_mmc_nt_bank[offset] & 0xff00) | data; - } - else - { - offset &= 3; - m_mmc_nt_bank[offset] = (m_mmc_nt_bank[offset] & 0x00ff) | data << 8; - } - update_mirror(); - break; - case 0x4000: - switch (offset & 7) - { - case 0: - if (BIT(data, 0)) - m_irq_enable = 1; - else - { - m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); - m_irq_enable = 0; - } - break; - case 1: - m_irq_mode = data & 3; - m_irq_prescale_mask = (data & 4) ? 0x07 : 0xff; - m_irq_down = data & 0x80; - m_irq_up = data & 0x40; - if (m_irq_mode == 0) - irq_timer->adjust(attotime::zero, 0, timer_freq); - else - irq_timer->adjust(attotime::never); - break; - case 2: - m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); - m_irq_enable = 0; - break; - case 3: - m_irq_enable = 1; - break; - case 4: - m_irq_prescale = data ^ m_irq_flip; - break; - case 5: - m_irq_count = data ^ m_irq_flip; - break; - case 6: - m_irq_flip = data; - break; - case 7: - // this is used for the 'funky' IRQ mode, not implemented yet - break; - } - break; - case 0x5000: - if (m_reg[offset & 3] != data) - { - m_reg[offset & 3] = data; - update_banks(offset & 3); - } - break; - } -} - -/*------------------------------------------------- - - JY Company Type B board emulation - - iNES: mapper 211 - - The mirroring system is a lot more complex in this - board - - -------------------------------------------------*/ - -void nes_jy_typeb_device::update_mirror_typeb() -{ - for (int i = 0; i < 4; i++) - { - if (BIT(m_reg[0], 6)) // CHRROM - set_nt_page(i, VROM, m_mmc_nt_bank[i], 0); - else // might be either CHRROM or CIRAM - { - // CHRROM is only used if bit 7 of the NT Reg does not match bit7 of reg[2]. - if ((m_mmc_nt_bank[i] ^ m_reg[2]) & 0x80) - set_nt_page(i, VROM, m_mmc_nt_bank[i], 0); - else - set_nt_page(i, CIRAM, m_mmc_nt_bank[i] & 1, 1); - } - } -} - -/*------------------------------------------------- - - JY Company Type C board emulation - - iNES: mapper 209 - - These board can switch between the Type A and the - Type B mirroring - - -------------------------------------------------*/ - -void nes_jy_typec_device::update_mirror_typec() -{ - if (BIT(m_reg[0], 5)) - update_mirror_typeb(); - else - update_mirror_typea(); -} - -READ8_MEMBER(nes_jy_typec_device::chr_r) -{ - int bank = offset >> 10; - - irq_clock(0, 2); - switch (offset & 0xff0) - { - case 0xfd0: - m_chr_latch[BIT(offset, 12)] = (bank & 0x4); - update_chr(); - break; - case 0xfe0: - m_chr_latch[BIT(offset, 12)] = (bank & 0x4) | 0x2; - update_chr(); - break; - } - return m_chr_access[bank][offset & 0x3ff]; -} diff --git a/src/devices/bus/nes/jy.cpp b/src/devices/bus/nes/jy.cpp new file mode 100644 index 00000000000..31358e2ab16 --- /dev/null +++ b/src/devices/bus/nes/jy.cpp @@ -0,0 +1,589 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for JY Company + + + Here we emulate multiple PCBs by JY Company with weird IRQ mechanisms [mappers 90, 209, 211] + + TODO: long list... + - add dipswitches + - revamp IRQ system + * scanline/hblank irq should fire 8 times per line (currently not possible) + * implement CPU write IRQ (used by any games?) + * possibly implementing 'funky' IRQ mode (unused?) + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "jy.h" + +#include "cpu/m6502/m6502.h" +#include "video/ppu2c0x.h" // this has to be included so that IRQ functions can access PPU_BOTTOM_VISIBLE_SCANLINE + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_JY_TYPEA = &device_creator; +const device_type NES_JY_TYPEB = &device_creator; +const device_type NES_JY_TYPEC = &device_creator; + + +nes_jy_typea_device::nes_jy_typea_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +nes_jy_typea_device::nes_jy_typea_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_JY_TYPEA, "NES Cart JY Company Type A PCB", tag, owner, clock, "nes_jya", __FILE__) +{ +} + +nes_jy_typeb_device::nes_jy_typeb_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : nes_jy_typea_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +nes_jy_typeb_device::nes_jy_typeb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_jy_typea_device(mconfig, NES_JY_TYPEB, "NES Cart JY Company Type B PCB", tag, owner, clock, "nes_jyb", __FILE__) +{ +} + +nes_jy_typec_device::nes_jy_typec_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_jy_typeb_device(mconfig, NES_JY_TYPEC, "NES Cart JY Company Type C PCB", tag, owner, clock, "nes_jyc", __FILE__) +{ +} + + + + +void nes_jy_typea_device::device_start() +{ + common_start(); + irq_timer = timer_alloc(TIMER_IRQ); + irq_timer->reset(); + timer_freq = machine().device("maincpu")->cycles_to_attotime(1); + + save_item(NAME(m_mul)); + save_item(NAME(m_latch)); + save_item(NAME(m_mmc_prg_bank)); + save_item(NAME(m_mmc_nt_bank)); + save_item(NAME(m_mmc_vrom_bank)); + save_item(NAME(m_reg)); + save_item(NAME(m_chr_latch)); + save_item(NAME(m_bank_6000)); + + save_item(NAME(m_irq_prescale)); + save_item(NAME(m_irq_prescale_mask)); + save_item(NAME(m_irq_mode)); + save_item(NAME(m_irq_count)); + save_item(NAME(m_irq_flip)); + save_item(NAME(m_irq_enable)); + save_item(NAME(m_irq_up)); + save_item(NAME(m_irq_down)); +} + +void nes_jy_typea_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); + + // 0x5000-0x5fff + m_mul[0] = 0; + m_mul[1] = 0; + m_latch = 0; + + // 0x8000-0xffff + memset(m_mmc_prg_bank, 0xff, sizeof(m_mmc_prg_bank)); + memset(m_mmc_nt_bank, 0, sizeof(m_mmc_nt_bank)); + memset(m_mmc_vrom_bank, 0xffff, sizeof(m_mmc_vrom_bank)); + memset(m_reg, 0, sizeof(m_reg)); + m_chr_latch[0] = 0; + m_chr_latch[1] = 4; + m_bank_6000 = 0; + + update_prg(); + update_chr(); + update_mirror(); + + m_irq_mode = 0; + m_irq_count = 0; + m_irq_prescale = 0; + m_irq_prescale_mask = 0xff; + m_irq_flip = 0; + m_irq_enable = 0; + m_irq_up = 0; + m_irq_down = 0; +} + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + JY Company Type A board emulation + + iNES: mapper 90 + + -------------------------------------------------*/ + + +READ8_MEMBER(nes_jy_typea_device::nt_r) +{ + int page = ((offset & 0xc00) >> 10); + irq_clock(0, 2); + return m_nt_access[page][offset & 0x3ff]; +} + +READ8_MEMBER(nes_jy_typea_device::chr_r) +{ + int bank = offset >> 10; + irq_clock(0, 2); + return m_chr_access[bank][offset & 0x3ff]; +} + +void nes_jy_typea_device::irq_clock(int mode, int blanked) +{ + bool clock = FALSE, fire = FALSE; + + if (m_irq_mode != mode) + return; + + // no counter changes if both Up/Down are set or clear + if ((m_irq_down && m_irq_up) || (!m_irq_down && !m_irq_up)) + return; + + // update prescaler + if (m_irq_down) + { + if ((m_irq_prescale & m_irq_prescale_mask) == 0) + { + clock = TRUE; + m_irq_prescale = (m_irq_prescale_mask == 7) ? ((m_irq_prescale & 0xf8) | 7) : 0xff; + } + else + m_irq_prescale = (m_irq_prescale_mask == 7) ? ((m_irq_prescale & 0xf8) | ((m_irq_prescale - 1) & m_irq_prescale_mask)) : (m_irq_prescale - 1); + } + + if (m_irq_up) + { + if ((m_irq_prescale & m_irq_prescale_mask) == m_irq_prescale_mask) + { + clock = TRUE; + m_irq_prescale = (m_irq_prescale_mask == 7) ? (m_irq_prescale & 0xf8) : 0; + } + else + m_irq_prescale = (m_irq_prescale_mask == 7) ? ((m_irq_prescale & 0xf8) | ((m_irq_prescale + 1) & m_irq_prescale_mask)) : (m_irq_prescale + 1); + } + + // if prescaler wraps, update count + if (clock) + { + if (m_irq_down) + { + if (m_irq_count == 0) + { + fire = TRUE; + m_irq_count = 0xff; + } + else + m_irq_count--; + } + + if (m_irq_up) + { + if (m_irq_count == 0xff) + { + fire = TRUE; + m_irq_count = 0; + } + else + m_irq_count++; + } + + + // if count wraps, check if IRQ is enabled + if (fire && m_irq_enable && !blanked) + m_maincpu->set_input_line(M6502_IRQ_LINE, ASSERT_LINE); + + } +} + +void nes_jy_typea_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (id == TIMER_IRQ) + { + irq_clock(0, 0); + } +} + +void nes_jy_typea_device::scanline_irq(int scanline, int vblank, int blanked) +{ + if (scanline < PPU_BOTTOM_VISIBLE_SCANLINE) + irq_clock(blanked, 1); +} + + +// 0x5000-0x5fff : sort of protection? +READ8_MEMBER(nes_jy_typea_device::read_l) +{ + LOG_MMC(("JY Company write_m, offset: %04x\n", offset)); + offset += 0x100; + + if (offset >= 0x1000 && offset < 0x1800) + { + // bit6/bit7 DSW read + return m_open_bus & 0x3f; + } + + if (offset >= 0x1800) + { + if ((offset & 7) == 0) + return (m_mul[0] * m_mul[1]) & 0xff; + if ((offset & 7) == 1) + return ((m_mul[0] * m_mul[1]) >> 8) & 0xff; + if ((offset & 7) == 3) + return m_latch; + } + + return m_open_bus; // open bus +} + +WRITE8_MEMBER(nes_jy_typea_device::write_l) +{ + LOG_MMC(("JY Company write_m, offset: %04x, data: %02x\n", offset, data)); + offset += 0x100; + + if (offset >= 0x1800) + { + if ((offset & 7) == 0) + m_mul[0] = data; + if ((offset & 7) == 1) + m_mul[1] = data; + if ((offset & 7) == 3) + m_latch = data; + } +} + +// 0x6000-0x7fff : WRAM or open bus +READ8_MEMBER(nes_jy_typea_device::read_m) +{ + LOG_MMC(("JY Company write_m, offset: %04x\n", offset)); + + if (m_reg[0] & 0x80) + return m_prg[(m_bank_6000 & m_prg_mask) * 0x2000 + (offset & 0x1fff)]; + + return m_open_bus; // open bus +} + + +inline UINT8 nes_jy_typea_device::unscramble(UINT8 bank) +{ + return BITSWAP8(bank & 0x7f,7,0,1,2,3,4,5,6); +} + +void nes_jy_typea_device::update_prg() +{ + UINT8 exPrg = (m_reg[3] & 0x06) << 5; + UINT8 last = (m_reg[0] & 0x04) ? m_mmc_prg_bank[3] : 0x3f; + + switch (m_reg[0] & 0x03) + { + case 0: // 32KB + prg32((last & 0x0f) | (exPrg >> 2)); + m_bank_6000 = (((m_mmc_prg_bank[3] * 4) + 3) & 0x3f) | (exPrg >> 2); + break; + + case 1: // 16KB + prg16_89ab((m_mmc_prg_bank[1] & 0x1f) | (exPrg >> 1)); + prg16_cdef((last & 0x1f) | (exPrg >> 1)); + m_bank_6000 = (((m_mmc_prg_bank[3] * 2) + 1) & 0x1f) | (exPrg >> 1); + break; + + case 2: // 8KB + prg8_89(m_mmc_prg_bank[0] | exPrg); + prg8_ab(m_mmc_prg_bank[1] | exPrg); + prg8_cd(m_mmc_prg_bank[2] | exPrg); + prg8_ef(last | exPrg); + m_bank_6000 = m_mmc_prg_bank[3] | exPrg; + break; + + case 3: // 8KB Alt + prg8_89((unscramble(m_mmc_prg_bank[0]) & 0x3f) | exPrg); + prg8_ab((unscramble(m_mmc_prg_bank[1]) & 0x3f) | exPrg); + prg8_cd((unscramble(m_mmc_prg_bank[2]) & 0x3f) | exPrg); + if (m_reg[0] & 0x04) + prg8_ef((unscramble(m_mmc_prg_bank[3]) & 0x3f) | exPrg); + else + prg8_ef((unscramble(last) & 0x3f) | exPrg); + m_bank_6000 = (unscramble(m_mmc_prg_bank[3]) & 0x3f) | exPrg; + break; + } +} + +void nes_jy_typea_device::update_chr() +{ + // in 1KB & 2KB mode, PPU 0x800-0xfff always mirrors 0x000-0x7ff (0x1800-0x1fff not affected) + int chr_mirror_mode = BIT(m_reg[3], 7) << 1; + + // Case (m_reg[3] & 0x20 == 0) + // Block mode enabled: in this case lower bits select a 256KB page inside CHRROM + // and the low bytes of m_mmc_vrom_bank select the banks inside such a page + + // docs suggest m_reg[3] & 0x1f for chr_page below, + // but 45 in 1 (JY-120A) menu requires to use this (from NEStopia) + UINT8 chr_page = (m_reg[3] & 1) | ((m_reg[3] & 0x18) >> 2); + UINT32 extra_chr_base = BIT(m_reg[3], 5) ? 0 : (chr_page * 0x100); + UINT32 extra_chr_mask = BIT(m_reg[3], 5) ? 0xffffff : 0xff; + + switch (m_reg[0] & 0x18) + { + case 0x00: // 8KB + extra_chr_base >>= 3; + extra_chr_mask >>= 3; + chr8(extra_chr_base | (m_mmc_vrom_bank[0] & extra_chr_mask), m_chr_source); + break; + + case 0x08: // 4KB + extra_chr_base >>= 2; + extra_chr_mask >>= 2; + // Type A & B games have fixed m_chr_latch[0] = 0 and m_chr_latch[1] = 4 + // Type C games can change them at each CHR access! + chr4_0(extra_chr_base | (m_mmc_vrom_bank[m_chr_latch[0]] & extra_chr_mask), m_chr_source); + chr4_4(extra_chr_base | (m_mmc_vrom_bank[m_chr_latch[1]] & extra_chr_mask), m_chr_source); + break; + + case 0x10: // 2KB + extra_chr_base >>= 1; + extra_chr_mask >>= 1; + chr2_0(extra_chr_base | (m_mmc_vrom_bank[0] & extra_chr_mask), m_chr_source); + chr2_2(extra_chr_base | (m_mmc_vrom_bank[2 ^ chr_mirror_mode] & extra_chr_mask), m_chr_source); + chr2_4(extra_chr_base | (m_mmc_vrom_bank[4] & extra_chr_mask), m_chr_source); + chr2_6(extra_chr_base | (m_mmc_vrom_bank[6] & extra_chr_mask), m_chr_source); + break; + + case 0x18: // 1KB + chr1_0(extra_chr_base | (m_mmc_vrom_bank[0] & extra_chr_mask), m_chr_source); + chr1_1(extra_chr_base | (m_mmc_vrom_bank[1] & extra_chr_mask), m_chr_source); + chr1_2(extra_chr_base | (m_mmc_vrom_bank[2 ^ chr_mirror_mode] & extra_chr_mask), m_chr_source); + chr1_3(extra_chr_base | (m_mmc_vrom_bank[3 ^ chr_mirror_mode] & extra_chr_mask), m_chr_source); + chr1_4(extra_chr_base | (m_mmc_vrom_bank[4] & extra_chr_mask), m_chr_source); + chr1_5(extra_chr_base | (m_mmc_vrom_bank[5] & extra_chr_mask), m_chr_source); + chr1_6(extra_chr_base | (m_mmc_vrom_bank[6] & extra_chr_mask), m_chr_source); + chr1_7(extra_chr_base | (m_mmc_vrom_bank[7] & extra_chr_mask), m_chr_source); + break; + } +} + +void nes_jy_typea_device::update_mirror_typea() +{ + switch (m_reg[1] & 3) + { + case 0: set_nt_mirroring(PPU_MIRROR_VERT); break; + case 1: set_nt_mirroring(PPU_MIRROR_HORZ); break; + case 2: set_nt_mirroring(PPU_MIRROR_LOW); break; + case 3: set_nt_mirroring(PPU_MIRROR_HIGH); break; + } +} + +void nes_jy_typea_device::update_banks(int reg) +{ + switch (reg & 3) + { + case 0: + update_prg(); + update_chr(); + update_mirror(); + break; + case 1: + update_mirror(); + break; + case 2: + update_mirror(); + break; + case 3: + update_prg(); + update_chr(); + break; + } +} + + +WRITE8_MEMBER(nes_jy_typea_device::write_h) +{ + LOG_MMC(("JY Company write_m, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x7000) + { + case 0x0000: + offset &= 3; + data &= 0x3f; + if (m_mmc_prg_bank[offset] != data) + { + m_mmc_prg_bank[offset] = data; + update_prg(); + } + break; + case 0x1000: + offset &= 7; + if ((m_mmc_vrom_bank[offset] & 0xff) != data) + { + m_mmc_vrom_bank[offset] = (m_mmc_vrom_bank[offset] & 0xff00) | data; + update_chr(); + } + break; + case 0x2000: + offset &= 7; + if ((m_mmc_vrom_bank[offset] & 0xff00) != (data << 8)) + { + m_mmc_vrom_bank[offset] = (m_mmc_vrom_bank[offset] & 0x00ff) | (data << 8); + update_chr(); + } + break; + case 0x3000: + if (!(offset & 4)) + { + offset &= 3; + m_mmc_nt_bank[offset] = (m_mmc_nt_bank[offset] & 0xff00) | data; + } + else + { + offset &= 3; + m_mmc_nt_bank[offset] = (m_mmc_nt_bank[offset] & 0x00ff) | data << 8; + } + update_mirror(); + break; + case 0x4000: + switch (offset & 7) + { + case 0: + if (BIT(data, 0)) + m_irq_enable = 1; + else + { + m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); + m_irq_enable = 0; + } + break; + case 1: + m_irq_mode = data & 3; + m_irq_prescale_mask = (data & 4) ? 0x07 : 0xff; + m_irq_down = data & 0x80; + m_irq_up = data & 0x40; + if (m_irq_mode == 0) + irq_timer->adjust(attotime::zero, 0, timer_freq); + else + irq_timer->adjust(attotime::never); + break; + case 2: + m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); + m_irq_enable = 0; + break; + case 3: + m_irq_enable = 1; + break; + case 4: + m_irq_prescale = data ^ m_irq_flip; + break; + case 5: + m_irq_count = data ^ m_irq_flip; + break; + case 6: + m_irq_flip = data; + break; + case 7: + // this is used for the 'funky' IRQ mode, not implemented yet + break; + } + break; + case 0x5000: + if (m_reg[offset & 3] != data) + { + m_reg[offset & 3] = data; + update_banks(offset & 3); + } + break; + } +} + +/*------------------------------------------------- + + JY Company Type B board emulation + + iNES: mapper 211 + + The mirroring system is a lot more complex in this + board + + -------------------------------------------------*/ + +void nes_jy_typeb_device::update_mirror_typeb() +{ + for (int i = 0; i < 4; i++) + { + if (BIT(m_reg[0], 6)) // CHRROM + set_nt_page(i, VROM, m_mmc_nt_bank[i], 0); + else // might be either CHRROM or CIRAM + { + // CHRROM is only used if bit 7 of the NT Reg does not match bit7 of reg[2]. + if ((m_mmc_nt_bank[i] ^ m_reg[2]) & 0x80) + set_nt_page(i, VROM, m_mmc_nt_bank[i], 0); + else + set_nt_page(i, CIRAM, m_mmc_nt_bank[i] & 1, 1); + } + } +} + +/*------------------------------------------------- + + JY Company Type C board emulation + + iNES: mapper 209 + + These board can switch between the Type A and the + Type B mirroring + + -------------------------------------------------*/ + +void nes_jy_typec_device::update_mirror_typec() +{ + if (BIT(m_reg[0], 5)) + update_mirror_typeb(); + else + update_mirror_typea(); +} + +READ8_MEMBER(nes_jy_typec_device::chr_r) +{ + int bank = offset >> 10; + + irq_clock(0, 2); + switch (offset & 0xff0) + { + case 0xfd0: + m_chr_latch[BIT(offset, 12)] = (bank & 0x4); + update_chr(); + break; + case 0xfe0: + m_chr_latch[BIT(offset, 12)] = (bank & 0x4) | 0x2; + update_chr(); + break; + } + return m_chr_access[bank][offset & 0x3ff]; +} diff --git a/src/devices/bus/nes/kaiser.c b/src/devices/bus/nes/kaiser.c deleted file mode 100644 index 1c7d7bced0a..00000000000 --- a/src/devices/bus/nes/kaiser.c +++ /dev/null @@ -1,588 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Fabio Priuli -/*********************************************************************************************************** - - - NES/Famicom cartridge emulation for Kaiser PCBs - - - Here we emulate the following Kaiser bootleg PCBs - - * Kaiser KS202 - * Kaiser KS7012 - * Kaiser KS7013B - * Kaiser KS7017 - * Kaiser KS7022 - * Kaiser KS7032 - * Kaiser KS7058 - - The Kaiser KS7057 bootleg board is emulated in nes_mmc3_clones.c - - - TODO: - - FCEUmm lists more Kaiser PCBs: - * KS7030 (for Yume Koujou Doki Doki Panic by Kaiser?) - * KS7037 - but there seem to be no available dumps... - - ***********************************************************************************************************/ - - -#include "emu.h" -#include "kaiser.h" - -#include "cpu/m6502/m6502.h" - - -#ifdef NES_PCB_DEBUG -#define VERBOSE 1 -#else -#define VERBOSE 0 -#endif - -#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) - - -//------------------------------------------------- -// constructor -//------------------------------------------------- - -const device_type NES_KS7058 = &device_creator; -const device_type NES_KS7022 = &device_creator; -const device_type NES_KS7032 = &device_creator; -const device_type NES_KS202 = &device_creator; -const device_type NES_KS7017 = &device_creator; -const device_type NES_KS7012 = &device_creator; -const device_type NES_KS7013B = &device_creator; -const device_type NES_KS7031 = &device_creator; - - -nes_ks7058_device::nes_ks7058_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_KS7058, "NES Cart Kaiser KS-7058 PCB", tag, owner, clock, "nes_ks7058", __FILE__) -{ -} - -nes_ks7022_device::nes_ks7022_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_KS7022, "NES Cart Kaiser KS-7022 PCB", tag, owner, clock, "nes_ks7022", __FILE__) -{ -} - -nes_ks7032_device::nes_ks7032_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) - : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source) -{ -} - -nes_ks7032_device::nes_ks7032_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_KS7032, "NES Cart Kaiser KS-7032 PCB", tag, owner, clock, "nes_ks7032", __FILE__) -{ -} - -nes_ks202_device::nes_ks202_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_ks7032_device(mconfig, NES_KS202, "NES Cart Kaiser KS-202 PCB", tag, owner, clock, "nes_ks202", __FILE__) -{ -} - -nes_ks7017_device::nes_ks7017_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_KS7017, "NES Cart Kaiser KS-7017 PCB", tag, owner, clock, "nes_ks7017", __FILE__) -{ -} - -nes_ks7012_device::nes_ks7012_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_KS7012, "NES Cart Kaiser KS-7012 PCB", tag, owner, clock, "nes_ks7012", __FILE__) -{ -} - -nes_ks7013b_device::nes_ks7013b_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_KS7013B, "NES Cart Kaiser KS-7013B PCB", tag, owner, clock, "nes_ks7013b", __FILE__) -{ -} - -nes_ks7031_device::nes_ks7031_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_KS7031, "NES Cart Kaiser KS-7031 PCB", tag, owner, clock, "nes_ks7031", __FILE__) -{ -} - - - - -void nes_ks7058_device::device_start() -{ - common_start(); -} - -void nes_ks7058_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0); - chr8(0, m_chr_source); -} - -void nes_ks7022_device::device_start() -{ - common_start(); - save_item(NAME(m_latch)); -} - -void nes_ks7022_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(0); - prg16_cdef(m_prg_chunks - 1); - chr8(0, m_chr_source); - - m_latch = 0; -} - -void nes_ks7032_device::device_start() -{ - common_start(); - irq_timer = timer_alloc(TIMER_IRQ); - irq_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1)); - - save_item(NAME(m_latch)); - save_item(NAME(m_irq_enable)); - save_item(NAME(m_irq_count)); - save_item(NAME(m_reg)); -} - -void nes_ks7032_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(0); - prg16_cdef(m_prg_chunks - 1); - chr8(0, m_chr_source); - - m_latch = 0; - m_irq_enable = 0; - m_irq_count = 0; - memset(m_reg, 0, sizeof(m_reg)); - prg_update(); -} - -void nes_ks7017_device::device_start() -{ - common_start(); - irq_timer = timer_alloc(TIMER_IRQ); - irq_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1)); - - save_item(NAME(m_latch)); - save_item(NAME(m_irq_enable)); - save_item(NAME(m_irq_count)); - save_item(NAME(m_irq_status)); -} - -void nes_ks7017_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(0); - prg16_cdef(2); - chr8(0, m_chr_source); - - m_latch = 0; - m_irq_enable = 0; - m_irq_count = 0; - m_irq_status = 0; -} - -void nes_ks7012_device::device_start() -{ - common_start(); -} - -void nes_ks7012_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0xff); - chr8(0, m_chr_source); -} - -void nes_ks7013b_device::device_start() -{ - common_start(); -} - -void nes_ks7013b_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(0); - prg16_cdef(m_prg_chunks - 1); - chr8(0, m_chr_source); -} - -void nes_ks7031_device::device_start() -{ - common_start(); - save_item(NAME(m_reg)); -} - -void nes_ks7031_device::pcb_reset() -{ - prg32(0); // not really used... - chr8(0, CHRRAM); - - m_reg[0] = 0; - m_reg[1] = 0; - m_reg[2] = 0; - m_reg[3] = 0; -} - - - - - -/*------------------------------------------------- - mapper specific handlers - -------------------------------------------------*/ - -/*------------------------------------------------- - - Kaiser Board KS7058 - - Games: Tui Do Woo Ma Jeung - - Writes to 0xf000-0xffff set 4k chr banks. Namely, if - offset&0x80 is 0 the lower 4k are set, if it is 1 the - upper 4k are set. - - iNES: mapper 171 - - In MESS: Supported. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_ks7058_device::write_h) -{ - LOG_MMC(("ks7058 write_h, offset: %04x, data: %02x\n", offset, data)); - - switch (offset & 0x7080) - { - case 0x7000: - chr4_0(data, CHRROM); - break; - case 0x7080: - chr4_4(data, CHRROM); - break; - } -} - -/*------------------------------------------------- - - Kaiser Board KS7022 - - Games: 15 in 1 - - iNES: mapper 175 - - In MESS: Supported? - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_ks7022_device::write_h) -{ - LOG_MMC(("ks7022 write_h, offset: %04x, data: %02x\n", offset, data)); - - if (offset == 0) - set_nt_mirroring(BIT(data, 2) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); - - if (offset == 0x2000) - m_latch = data & 0x0f; -} - -READ8_MEMBER(nes_ks7022_device::read_h) -{ - LOG_MMC(("ks7022 read_h, offset: %04x\n", offset)); - - if (offset == 0x7ffc) - { - chr8(m_latch, CHRROM); - prg16_89ab(m_latch); - prg16_cdef(m_latch); - } - - return hi_access_rom(offset); -} - -/*------------------------------------------------- - - Kaiser Board KS7032 - - Games: A few FDS conversions like Bubble Bobble - or SMB2 - - iNES: - - TODO: available dumps do not seem to use WRAM... - yet m_reg[4] should switch WRAM bank... investigate! - - In MESS: Supported? - - -------------------------------------------------*/ - -void nes_ks7032_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) -{ - if (id == TIMER_IRQ) - { - if (m_irq_enable) - { - if (m_irq_count == 0xffff) - { - m_irq_enable = 0; - m_irq_count = 0; - m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE); - } - else - m_irq_count++; - } - } -} - -void nes_ks7032_device::prg_update() -{ - prg8_89(m_reg[1]); - prg8_ab(m_reg[2]); - prg8_cd(m_reg[3]); -} - -WRITE8_MEMBER(nes_ks7032_device::ks7032_write) -{ - LOG_MMC(("ks7032_write, offset: %04x, data: %02x\n", offset, data)); - - switch (offset & 0x7000) - { - case 0x0000: - m_irq_count = (m_irq_count & 0xfff0) | (data & 0x0f); - break; - case 0x1000: - m_irq_count = (m_irq_count & 0xff0f) | ((data & 0x0f) << 4); - break; - case 0x2000: - m_irq_count = (m_irq_count & 0xf0ff) | ((data & 0x0f) << 8); - break; - case 0x3000: - m_irq_count = (m_irq_count & 0x0fff) | ((data & 0x0f) << 12); - break; - case 0x4000: - m_irq_enable = 1; - break; - case 0x6000: - m_latch = data & 0x07; - break; - case 0x7000: - m_reg[m_latch] = data; - prg_update(); - break; - } -} - -READ8_MEMBER(nes_ks7032_device::read_m) -{ - LOG_MMC(("ks7032 read_m, offset: %04x\n", offset)); - return m_prg[((m_reg[4] * 0x2000) + (offset & 0x1fff)) & (m_prg_size - 1)]; -} - -/*------------------------------------------------- - - Kaiser Board KS202 - - Games: Super Mario Bros. 3 (Pirate, Alt) - - iNES: - - In MESS: Supported? - - -------------------------------------------------*/ - - -WRITE8_MEMBER(nes_ks202_device::write_h) -{ - LOG_MMC(("ks202 write_h, offset: %04x, data: %02x\n", offset, data)); - - switch (offset & 0x7000) - { - case 0x7000: - m_reg[m_latch] = data; - prg_update(); - switch (offset & 0xc00) - { - case 0x800: - set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ); - break; - case 0xc00: - chr1_x(offset & 0x07, data, CHRROM); - break; - } - break; - default: - ks7032_write(space, offset, data, mem_mask); - break; - } -} - -READ8_MEMBER(nes_ks202_device::read_m) -{ - LOG_MMC(("ks202 read_m, offset: %04x\n", offset)); - return m_prgram[offset & 0x1fff]; -} - -/*------------------------------------------------- - - Kaiser Board KS7017 - - Games: Almana no Kiseki FDS conversion - - iNES: - - In MESS: Supported. - - -------------------------------------------------*/ - -void nes_ks7017_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) -{ - if (id == TIMER_IRQ) - { - if (m_irq_enable) - { - if (!m_irq_count) - { - m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE); - m_irq_enable = 0; - m_irq_status |= 0x01; - } - else - m_irq_count--; - } - } -} - -WRITE8_MEMBER(nes_ks7017_device::write_l) -{ - LOG_MMC(("ks7017 write_l, offset: %04x, data: %02x\n", offset, data)); - - offset += 0x100; - - if (offset >= 0xa00 && offset < 0xb00) - m_latch = ((offset >> 2) & 0x03) | ((offset >> 4) & 0x04); - - if (offset >= 0x1100 && offset < 0x1200) - prg16_89ab(m_latch); -} - -WRITE8_MEMBER(nes_ks7017_device::write_ex) -{ - LOG_MMC(("ks7017 write_ex, offset: %04x, data: %02x\n", offset, data)); - offset += 0x20; - - if (offset == 0x0020) // 0x4020 - m_irq_count = (m_irq_count & 0xff00) | data; - - if (offset == 0x0021) // 0x4021 - { - m_irq_count = (m_irq_count & 0x00ff) | (data << 8); - m_irq_enable = 1; - } - - if (offset == 0x0025) // 0x4025 - set_nt_mirroring(BIT(data, 3) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); -} - -READ8_MEMBER(nes_ks7017_device::read_ex) -{ - LOG_MMC(("ks7017 read_ex, offset: %04x\n", offset)); - offset += 0x20; - - if (offset == 0x0030) // 0x4030 - { - int temp = m_irq_status; - m_irq_status &= ~0x01; - return temp; - } - - return m_open_bus; // open bus -} - -/*------------------------------------------------- - - Kaiser Board KS7012 - - Games: Zanac FDS Conversion - - iNES: - - In MESS: Not working - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_ks7012_device::write_h) -{ - LOG_MMC(("ks7012 write_h, offset: %04x, data: %02x\n", offset, data)); - - if (offset == 0x60a0) - prg32(0); - if (offset == 0x6e36) - prg32(1); -} - - -/*------------------------------------------------- - - Kaiser Board KS7013B - - Games: Highway Star FDS Conversion - - iNES: - - In MESS: Supported. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_ks7013b_device::write_m) -{ - LOG_MMC(("ks7013b write_l, offset: %04x, data: %02x\n", offset, data)); - prg16_89ab(data); -} - -WRITE8_MEMBER(nes_ks7013b_device::write_h) -{ - LOG_MMC(("ks7013b write_h, offset: %04x, data: %02x\n", offset, data)); - set_nt_mirroring((data & 1) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); -} - - -/*------------------------------------------------- - - Kaiser Board KS7031 - - Games: Dracula II FDS Conversion - - This board is quite weird. It handles 2K PRG chunks - and the chip contains chunks in reverse order, so - that the first 2K are actually loaded at the top - of the 0x8000-0xffff region. Main bank is fixed, while - the 8K mapped at 0x6000-0x7fff varies with reg writes. - - TODO: understand how SRAM is handled... - - iNES: - - In MESS: Supported. - - -------------------------------------------------*/ - -READ8_MEMBER(nes_ks7031_device::read_m) -{ -// LOG_MMC(("ks7031 read_m, offset: %04x\n", offset)); - return m_prg[(m_reg[(offset >> 11) & 3] * 0x0800) + (offset & 0x7ff)]; -} - -READ8_MEMBER(nes_ks7031_device::read_h) -{ - // here the first 32K are accessed, but in 16x2K blocks loaded in reverse order - int accessed_2k = (offset >> 11) & 0x0f; - return m_prg[((0x0f - accessed_2k) * 0x0800) + (offset & 0x7ff)]; -} - -WRITE8_MEMBER(nes_ks7031_device::write_h) -{ - LOG_MMC(("ks7031 write_h, offset: %04x, data: %02x\n", offset, data)); - m_reg[(offset >> 11) & 3] = data & 0x3f; -} diff --git a/src/devices/bus/nes/kaiser.cpp b/src/devices/bus/nes/kaiser.cpp new file mode 100644 index 00000000000..1c7d7bced0a --- /dev/null +++ b/src/devices/bus/nes/kaiser.cpp @@ -0,0 +1,588 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for Kaiser PCBs + + + Here we emulate the following Kaiser bootleg PCBs + + * Kaiser KS202 + * Kaiser KS7012 + * Kaiser KS7013B + * Kaiser KS7017 + * Kaiser KS7022 + * Kaiser KS7032 + * Kaiser KS7058 + + The Kaiser KS7057 bootleg board is emulated in nes_mmc3_clones.c + + + TODO: + - FCEUmm lists more Kaiser PCBs: + * KS7030 (for Yume Koujou Doki Doki Panic by Kaiser?) + * KS7037 + but there seem to be no available dumps... + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "kaiser.h" + +#include "cpu/m6502/m6502.h" + + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_KS7058 = &device_creator; +const device_type NES_KS7022 = &device_creator; +const device_type NES_KS7032 = &device_creator; +const device_type NES_KS202 = &device_creator; +const device_type NES_KS7017 = &device_creator; +const device_type NES_KS7012 = &device_creator; +const device_type NES_KS7013B = &device_creator; +const device_type NES_KS7031 = &device_creator; + + +nes_ks7058_device::nes_ks7058_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_KS7058, "NES Cart Kaiser KS-7058 PCB", tag, owner, clock, "nes_ks7058", __FILE__) +{ +} + +nes_ks7022_device::nes_ks7022_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_KS7022, "NES Cart Kaiser KS-7022 PCB", tag, owner, clock, "nes_ks7022", __FILE__) +{ +} + +nes_ks7032_device::nes_ks7032_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +nes_ks7032_device::nes_ks7032_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_KS7032, "NES Cart Kaiser KS-7032 PCB", tag, owner, clock, "nes_ks7032", __FILE__) +{ +} + +nes_ks202_device::nes_ks202_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_ks7032_device(mconfig, NES_KS202, "NES Cart Kaiser KS-202 PCB", tag, owner, clock, "nes_ks202", __FILE__) +{ +} + +nes_ks7017_device::nes_ks7017_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_KS7017, "NES Cart Kaiser KS-7017 PCB", tag, owner, clock, "nes_ks7017", __FILE__) +{ +} + +nes_ks7012_device::nes_ks7012_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_KS7012, "NES Cart Kaiser KS-7012 PCB", tag, owner, clock, "nes_ks7012", __FILE__) +{ +} + +nes_ks7013b_device::nes_ks7013b_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_KS7013B, "NES Cart Kaiser KS-7013B PCB", tag, owner, clock, "nes_ks7013b", __FILE__) +{ +} + +nes_ks7031_device::nes_ks7031_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_KS7031, "NES Cart Kaiser KS-7031 PCB", tag, owner, clock, "nes_ks7031", __FILE__) +{ +} + + + + +void nes_ks7058_device::device_start() +{ + common_start(); +} + +void nes_ks7058_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + +void nes_ks7022_device::device_start() +{ + common_start(); + save_item(NAME(m_latch)); +} + +void nes_ks7022_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + + m_latch = 0; +} + +void nes_ks7032_device::device_start() +{ + common_start(); + irq_timer = timer_alloc(TIMER_IRQ); + irq_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1)); + + save_item(NAME(m_latch)); + save_item(NAME(m_irq_enable)); + save_item(NAME(m_irq_count)); + save_item(NAME(m_reg)); +} + +void nes_ks7032_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + + m_latch = 0; + m_irq_enable = 0; + m_irq_count = 0; + memset(m_reg, 0, sizeof(m_reg)); + prg_update(); +} + +void nes_ks7017_device::device_start() +{ + common_start(); + irq_timer = timer_alloc(TIMER_IRQ); + irq_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1)); + + save_item(NAME(m_latch)); + save_item(NAME(m_irq_enable)); + save_item(NAME(m_irq_count)); + save_item(NAME(m_irq_status)); +} + +void nes_ks7017_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(2); + chr8(0, m_chr_source); + + m_latch = 0; + m_irq_enable = 0; + m_irq_count = 0; + m_irq_status = 0; +} + +void nes_ks7012_device::device_start() +{ + common_start(); +} + +void nes_ks7012_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0xff); + chr8(0, m_chr_source); +} + +void nes_ks7013b_device::device_start() +{ + common_start(); +} + +void nes_ks7013b_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); +} + +void nes_ks7031_device::device_start() +{ + common_start(); + save_item(NAME(m_reg)); +} + +void nes_ks7031_device::pcb_reset() +{ + prg32(0); // not really used... + chr8(0, CHRRAM); + + m_reg[0] = 0; + m_reg[1] = 0; + m_reg[2] = 0; + m_reg[3] = 0; +} + + + + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + Kaiser Board KS7058 + + Games: Tui Do Woo Ma Jeung + + Writes to 0xf000-0xffff set 4k chr banks. Namely, if + offset&0x80 is 0 the lower 4k are set, if it is 1 the + upper 4k are set. + + iNES: mapper 171 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_ks7058_device::write_h) +{ + LOG_MMC(("ks7058 write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x7080) + { + case 0x7000: + chr4_0(data, CHRROM); + break; + case 0x7080: + chr4_4(data, CHRROM); + break; + } +} + +/*------------------------------------------------- + + Kaiser Board KS7022 + + Games: 15 in 1 + + iNES: mapper 175 + + In MESS: Supported? + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_ks7022_device::write_h) +{ + LOG_MMC(("ks7022 write_h, offset: %04x, data: %02x\n", offset, data)); + + if (offset == 0) + set_nt_mirroring(BIT(data, 2) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + + if (offset == 0x2000) + m_latch = data & 0x0f; +} + +READ8_MEMBER(nes_ks7022_device::read_h) +{ + LOG_MMC(("ks7022 read_h, offset: %04x\n", offset)); + + if (offset == 0x7ffc) + { + chr8(m_latch, CHRROM); + prg16_89ab(m_latch); + prg16_cdef(m_latch); + } + + return hi_access_rom(offset); +} + +/*------------------------------------------------- + + Kaiser Board KS7032 + + Games: A few FDS conversions like Bubble Bobble + or SMB2 + + iNES: + + TODO: available dumps do not seem to use WRAM... + yet m_reg[4] should switch WRAM bank... investigate! + + In MESS: Supported? + + -------------------------------------------------*/ + +void nes_ks7032_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (id == TIMER_IRQ) + { + if (m_irq_enable) + { + if (m_irq_count == 0xffff) + { + m_irq_enable = 0; + m_irq_count = 0; + m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE); + } + else + m_irq_count++; + } + } +} + +void nes_ks7032_device::prg_update() +{ + prg8_89(m_reg[1]); + prg8_ab(m_reg[2]); + prg8_cd(m_reg[3]); +} + +WRITE8_MEMBER(nes_ks7032_device::ks7032_write) +{ + LOG_MMC(("ks7032_write, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x7000) + { + case 0x0000: + m_irq_count = (m_irq_count & 0xfff0) | (data & 0x0f); + break; + case 0x1000: + m_irq_count = (m_irq_count & 0xff0f) | ((data & 0x0f) << 4); + break; + case 0x2000: + m_irq_count = (m_irq_count & 0xf0ff) | ((data & 0x0f) << 8); + break; + case 0x3000: + m_irq_count = (m_irq_count & 0x0fff) | ((data & 0x0f) << 12); + break; + case 0x4000: + m_irq_enable = 1; + break; + case 0x6000: + m_latch = data & 0x07; + break; + case 0x7000: + m_reg[m_latch] = data; + prg_update(); + break; + } +} + +READ8_MEMBER(nes_ks7032_device::read_m) +{ + LOG_MMC(("ks7032 read_m, offset: %04x\n", offset)); + return m_prg[((m_reg[4] * 0x2000) + (offset & 0x1fff)) & (m_prg_size - 1)]; +} + +/*------------------------------------------------- + + Kaiser Board KS202 + + Games: Super Mario Bros. 3 (Pirate, Alt) + + iNES: + + In MESS: Supported? + + -------------------------------------------------*/ + + +WRITE8_MEMBER(nes_ks202_device::write_h) +{ + LOG_MMC(("ks202 write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x7000) + { + case 0x7000: + m_reg[m_latch] = data; + prg_update(); + switch (offset & 0xc00) + { + case 0x800: + set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ); + break; + case 0xc00: + chr1_x(offset & 0x07, data, CHRROM); + break; + } + break; + default: + ks7032_write(space, offset, data, mem_mask); + break; + } +} + +READ8_MEMBER(nes_ks202_device::read_m) +{ + LOG_MMC(("ks202 read_m, offset: %04x\n", offset)); + return m_prgram[offset & 0x1fff]; +} + +/*------------------------------------------------- + + Kaiser Board KS7017 + + Games: Almana no Kiseki FDS conversion + + iNES: + + In MESS: Supported. + + -------------------------------------------------*/ + +void nes_ks7017_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (id == TIMER_IRQ) + { + if (m_irq_enable) + { + if (!m_irq_count) + { + m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE); + m_irq_enable = 0; + m_irq_status |= 0x01; + } + else + m_irq_count--; + } + } +} + +WRITE8_MEMBER(nes_ks7017_device::write_l) +{ + LOG_MMC(("ks7017 write_l, offset: %04x, data: %02x\n", offset, data)); + + offset += 0x100; + + if (offset >= 0xa00 && offset < 0xb00) + m_latch = ((offset >> 2) & 0x03) | ((offset >> 4) & 0x04); + + if (offset >= 0x1100 && offset < 0x1200) + prg16_89ab(m_latch); +} + +WRITE8_MEMBER(nes_ks7017_device::write_ex) +{ + LOG_MMC(("ks7017 write_ex, offset: %04x, data: %02x\n", offset, data)); + offset += 0x20; + + if (offset == 0x0020) // 0x4020 + m_irq_count = (m_irq_count & 0xff00) | data; + + if (offset == 0x0021) // 0x4021 + { + m_irq_count = (m_irq_count & 0x00ff) | (data << 8); + m_irq_enable = 1; + } + + if (offset == 0x0025) // 0x4025 + set_nt_mirroring(BIT(data, 3) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); +} + +READ8_MEMBER(nes_ks7017_device::read_ex) +{ + LOG_MMC(("ks7017 read_ex, offset: %04x\n", offset)); + offset += 0x20; + + if (offset == 0x0030) // 0x4030 + { + int temp = m_irq_status; + m_irq_status &= ~0x01; + return temp; + } + + return m_open_bus; // open bus +} + +/*------------------------------------------------- + + Kaiser Board KS7012 + + Games: Zanac FDS Conversion + + iNES: + + In MESS: Not working + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_ks7012_device::write_h) +{ + LOG_MMC(("ks7012 write_h, offset: %04x, data: %02x\n", offset, data)); + + if (offset == 0x60a0) + prg32(0); + if (offset == 0x6e36) + prg32(1); +} + + +/*------------------------------------------------- + + Kaiser Board KS7013B + + Games: Highway Star FDS Conversion + + iNES: + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_ks7013b_device::write_m) +{ + LOG_MMC(("ks7013b write_l, offset: %04x, data: %02x\n", offset, data)); + prg16_89ab(data); +} + +WRITE8_MEMBER(nes_ks7013b_device::write_h) +{ + LOG_MMC(("ks7013b write_h, offset: %04x, data: %02x\n", offset, data)); + set_nt_mirroring((data & 1) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); +} + + +/*------------------------------------------------- + + Kaiser Board KS7031 + + Games: Dracula II FDS Conversion + + This board is quite weird. It handles 2K PRG chunks + and the chip contains chunks in reverse order, so + that the first 2K are actually loaded at the top + of the 0x8000-0xffff region. Main bank is fixed, while + the 8K mapped at 0x6000-0x7fff varies with reg writes. + + TODO: understand how SRAM is handled... + + iNES: + + In MESS: Supported. + + -------------------------------------------------*/ + +READ8_MEMBER(nes_ks7031_device::read_m) +{ +// LOG_MMC(("ks7031 read_m, offset: %04x\n", offset)); + return m_prg[(m_reg[(offset >> 11) & 3] * 0x0800) + (offset & 0x7ff)]; +} + +READ8_MEMBER(nes_ks7031_device::read_h) +{ + // here the first 32K are accessed, but in 16x2K blocks loaded in reverse order + int accessed_2k = (offset >> 11) & 0x0f; + return m_prg[((0x0f - accessed_2k) * 0x0800) + (offset & 0x7ff)]; +} + +WRITE8_MEMBER(nes_ks7031_device::write_h) +{ + LOG_MMC(("ks7031 write_h, offset: %04x, data: %02x\n", offset, data)); + m_reg[(offset >> 11) & 3] = data & 0x3f; +} diff --git a/src/devices/bus/nes/karastudio.c b/src/devices/bus/nes/karastudio.c deleted file mode 100644 index 002bdf6eea3..00000000000 --- a/src/devices/bus/nes/karastudio.c +++ /dev/null @@ -1,309 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Fabio Priuli -/*********************************************************************************************************** - - - NES/Famicom cartridge emulation for Bandai Karaoke Studio - - - Here we emulate the following PCBs Bandai Karaoke Studio [mapper 188] - - The Karaoke Studio cart consist of a large connector which fits the FC cart slot, with a microphone - connected. The game data is in the connector itself. The microphone has two buttons on it, and the - game uses these only to navigate through the menus (the two buttons are not read through the controller - port, which is not accessible from the cart, but from $6000-$7fff). Part of the connector body can be - removed to be replaced by an expansion cart containing new songs (we emulate this by adding a -cart2 slot). - - - TODO: - - verify expansion slot emulation for the Senyou Cassettes: - not much documentation exists about the expansion carts (except for few paragraphs - at Enri's FC webpage), so I implemented it based on "common sense" - * expansion carts do not contain the required game data => main PRG must be in the main cart - so to remain connected even when an expansion is inserted (differently from Datach, where - the base unit contains no PRG) - * bankswicth writes with bit3=0 (to access expansion) when no expansion is present should do - nothing - - ***********************************************************************************************************/ - - -#include "emu.h" -#include "karastudio.h" - -#ifdef NES_PCB_DEBUG -#define VERBOSE 1 -#else -#define VERBOSE 0 -#endif - -#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) - - -//----------------------------------------- -// -// Karaoke Studio Cartslot implementation -// -//----------------------------------------- - -//------------------------------------------------- -// sub-cart interface -//------------------------------------------------- - -kstudio_cart_interface::kstudio_cart_interface(const machine_config &mconfig, device_t &device) - : device_slot_card_interface(mconfig, device), - m_rom(NULL) -{ -} - -kstudio_cart_interface::~kstudio_cart_interface() -{ -} - -READ8_MEMBER(kstudio_cart_interface::read) -{ - return m_rom[(m_bank * 0x4000) + (offset & 0x3fff)]; -} - -//------------------------------------------------- -// sub-cart slot device -//------------------------------------------------- - -const device_type NES_KSEXPANSION_SLOT = &device_creator; - -nes_kstudio_slot_device::nes_kstudio_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : - device_t(mconfig, NES_KSEXPANSION_SLOT, "NES Karaoke Studio Expansion Slot", tag, owner, clock, "nes_ks_slot", __FILE__), - device_image_interface(mconfig, *this), - device_slot_interface(mconfig, *this) -{ -} - -nes_kstudio_slot_device::~nes_kstudio_slot_device() -{ -} - - -void nes_kstudio_slot_device::device_start() -{ - m_cart = dynamic_cast(get_card_device()); -} - -READ8_MEMBER(nes_kstudio_slot_device::read) -{ - if (m_cart) - return m_cart->read(space, offset, mem_mask); - - return 0xff; -} - -bool nes_kstudio_slot_device::call_load() -{ - if (m_cart) - { - UINT8 *ROM = m_cart->get_cart_base(); - - if (!ROM) - return IMAGE_INIT_FAIL; - - // Existing exapnsion carts are all 128K, so we only load files of this size - if (software_entry() == NULL) - { - if (length() != 0x20000) - return IMAGE_INIT_FAIL; - - fread(&ROM, 0x20000); - } - else - { - if (get_software_region_length("rom") != 0x20000) - return IMAGE_INIT_FAIL; - - memcpy(ROM, get_software_region("rom"), 0x20000); - } - } - - return IMAGE_INIT_PASS; -} - - -bool nes_kstudio_slot_device::call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry) -{ - load_software_part_region(*this, swlist, swname, start_entry ); - return TRUE; -} - -void nes_kstudio_slot_device::get_default_card_software(std::string &result) -{ - software_get_default_slot(result, "ks_exp"); -} - - -//----------------------------------------------- -// -// Karaoke Studio Expansion cart implementation -// -//----------------------------------------------- - -ROM_START( ks_exp_rom ) - ROM_REGION(0x20000, "exrom", ROMREGION_ERASEFF) -ROM_END - -const device_type NES_KSEXPANSION_ROM = &device_creator; - -nes_kstudio_rom_device::nes_kstudio_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : device_t(mconfig, NES_KSEXPANSION_ROM, "NES Karaoke Studio Expansion ROM", tag, owner, clock, "nes_ks_rom", __FILE__), - kstudio_cart_interface( mconfig, *this ) -{ -} - -void nes_kstudio_rom_device::device_start() -{ - m_rom = (UINT8*)memregion("exrom")->base(); - save_item(NAME(m_bank)); -} - -void nes_kstudio_rom_device::device_reset() -{ - m_bank = 0; -} - -const rom_entry *nes_kstudio_rom_device::device_rom_region() const -{ - return ROM_NAME( ks_exp_rom ); -} - -UINT8 *nes_kstudio_rom_device::get_cart_base() -{ - return m_rom; -} - - -//------------------------------------------ -// -// Karaoke Studio Base Cart implementation -// -//------------------------------------------ - -const device_type NES_KARAOKESTUDIO = &device_creator; - - -nes_karaokestudio_device::nes_karaokestudio_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_KARAOKESTUDIO, "NES Cart Bandai Karaoke Studio PCB", tag, owner, clock, "nes_karaoke", __FILE__), - m_subslot(*this, "exp_slot"), - m_mic_ipt(*this, "MIC") -{ -} - - -void nes_karaokestudio_device::device_start() -{ - common_start(); - save_item(NAME(m_exp_active)); -} - -void nes_karaokestudio_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(0); - prg16_cdef((m_prg_chunks - 1) ^ 0x08); - chr8(0, m_chr_source); - m_exp_active = 0; -} - - -/*------------------------------------------------- - mapper specific handlers - -------------------------------------------------*/ - -/*------------------------------------------------- - - Bandai Karaoke Studio board emulation - - Games: Karaoke Studio + expansion carts with - additional songs - - Note: we currently do not emulate properly the - expansion slot - - iNES: mapper 188 - - -------------------------------------------------*/ - -READ8_MEMBER(nes_karaokestudio_device::read_m) -{ - LOG_MMC(("karaoke studio read_m, offset: %04x\n", offset)); - return m_mic_ipt->read(); -} - -READ8_MEMBER(nes_karaokestudio_device::read_h) -{ - LOG_MMC(("karaoke studio read_h, offset: %04x\n", offset)); - // this shall be the proper code, but it's a bit slower, so we access directly the subcart below - //return m_subslot->read(space, offset, mem_mask); - - // access expansion cart only if all of the followings are verified - // * we are in $8000-$bfff range - // * there has been a bankswitch write to map the expansion to such range - // * there actually is an expansion cart mounted - if (offset < 0x4000 && m_exp_active && m_subslot->m_cart) - return m_subslot->m_cart->read(space, offset, mem_mask); - else - return hi_access_rom(offset); -} - -WRITE8_MEMBER(nes_karaokestudio_device::write_h) -{ - LOG_MMC(("karaoke studio write_h, offset: %04x, data: %02x\n", offset, data)); - // bit3 1 = M ROM (main unit), 0=E ROM (expansion) - // HACK(?): currently it is not clear how the unit acknowledges the presence of the expansion - // cart (when expansion is present, code keeps switching both from the expansion rom and from - // the main ROM) - // my guess is that writes with bit3=0 and no expansion just do nothing, but it shall be verified - - if (offset >= 04000) - { - if (BIT(data, 3)) - { - m_exp_active = 0; - prg16_89ab(data & 7); - } - else // expansion cart - { - m_exp_active = 1; - m_subslot->write_prg_bank(data & 7); - } - } -} - - -static INPUT_PORTS_START( karaoke_mic ) - PORT_START("MIC") - PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("A (Mic Select)") PORT_CODE(KEYCODE_X) - PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("B (Mic Start)") PORT_CODE(KEYCODE_Z) - PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_NAME("Microphone (?)") PORT_CODE(KEYCODE_C) - PORT_BIT( 0xf8, IP_ACTIVE_HIGH, IPT_UNUSED ) -INPUT_PORTS_END - -ioport_constructor nes_karaokestudio_device::device_input_ports() const -{ - return INPUT_PORTS_NAME( karaoke_mic ); -} - - -//------------------------------------------------- -// CART SLOT -//------------------------------------------------- - -static SLOT_INTERFACE_START(karaoke_studio_cart) - SLOT_INTERFACE_INTERNAL("ks_exp", NES_KSEXPANSION_ROM) -SLOT_INTERFACE_END - - -MACHINE_CONFIG_FRAGMENT( karaoke_studio ) - MCFG_KSTUDIO_MINICART_ADD("exp_slot", karaoke_studio_cart) -MACHINE_CONFIG_END - -machine_config_constructor nes_karaokestudio_device::device_mconfig_additions() const -{ - return MACHINE_CONFIG_NAME( karaoke_studio ); -} diff --git a/src/devices/bus/nes/karastudio.cpp b/src/devices/bus/nes/karastudio.cpp new file mode 100644 index 00000000000..002bdf6eea3 --- /dev/null +++ b/src/devices/bus/nes/karastudio.cpp @@ -0,0 +1,309 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for Bandai Karaoke Studio + + + Here we emulate the following PCBs Bandai Karaoke Studio [mapper 188] + + The Karaoke Studio cart consist of a large connector which fits the FC cart slot, with a microphone + connected. The game data is in the connector itself. The microphone has two buttons on it, and the + game uses these only to navigate through the menus (the two buttons are not read through the controller + port, which is not accessible from the cart, but from $6000-$7fff). Part of the connector body can be + removed to be replaced by an expansion cart containing new songs (we emulate this by adding a -cart2 slot). + + + TODO: + - verify expansion slot emulation for the Senyou Cassettes: + not much documentation exists about the expansion carts (except for few paragraphs + at Enri's FC webpage), so I implemented it based on "common sense" + * expansion carts do not contain the required game data => main PRG must be in the main cart + so to remain connected even when an expansion is inserted (differently from Datach, where + the base unit contains no PRG) + * bankswicth writes with bit3=0 (to access expansion) when no expansion is present should do + nothing + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "karastudio.h" + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//----------------------------------------- +// +// Karaoke Studio Cartslot implementation +// +//----------------------------------------- + +//------------------------------------------------- +// sub-cart interface +//------------------------------------------------- + +kstudio_cart_interface::kstudio_cart_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig, device), + m_rom(NULL) +{ +} + +kstudio_cart_interface::~kstudio_cart_interface() +{ +} + +READ8_MEMBER(kstudio_cart_interface::read) +{ + return m_rom[(m_bank * 0x4000) + (offset & 0x3fff)]; +} + +//------------------------------------------------- +// sub-cart slot device +//------------------------------------------------- + +const device_type NES_KSEXPANSION_SLOT = &device_creator; + +nes_kstudio_slot_device::nes_kstudio_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, NES_KSEXPANSION_SLOT, "NES Karaoke Studio Expansion Slot", tag, owner, clock, "nes_ks_slot", __FILE__), + device_image_interface(mconfig, *this), + device_slot_interface(mconfig, *this) +{ +} + +nes_kstudio_slot_device::~nes_kstudio_slot_device() +{ +} + + +void nes_kstudio_slot_device::device_start() +{ + m_cart = dynamic_cast(get_card_device()); +} + +READ8_MEMBER(nes_kstudio_slot_device::read) +{ + if (m_cart) + return m_cart->read(space, offset, mem_mask); + + return 0xff; +} + +bool nes_kstudio_slot_device::call_load() +{ + if (m_cart) + { + UINT8 *ROM = m_cart->get_cart_base(); + + if (!ROM) + return IMAGE_INIT_FAIL; + + // Existing exapnsion carts are all 128K, so we only load files of this size + if (software_entry() == NULL) + { + if (length() != 0x20000) + return IMAGE_INIT_FAIL; + + fread(&ROM, 0x20000); + } + else + { + if (get_software_region_length("rom") != 0x20000) + return IMAGE_INIT_FAIL; + + memcpy(ROM, get_software_region("rom"), 0x20000); + } + } + + return IMAGE_INIT_PASS; +} + + +bool nes_kstudio_slot_device::call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry) +{ + load_software_part_region(*this, swlist, swname, start_entry ); + return TRUE; +} + +void nes_kstudio_slot_device::get_default_card_software(std::string &result) +{ + software_get_default_slot(result, "ks_exp"); +} + + +//----------------------------------------------- +// +// Karaoke Studio Expansion cart implementation +// +//----------------------------------------------- + +ROM_START( ks_exp_rom ) + ROM_REGION(0x20000, "exrom", ROMREGION_ERASEFF) +ROM_END + +const device_type NES_KSEXPANSION_ROM = &device_creator; + +nes_kstudio_rom_device::nes_kstudio_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, NES_KSEXPANSION_ROM, "NES Karaoke Studio Expansion ROM", tag, owner, clock, "nes_ks_rom", __FILE__), + kstudio_cart_interface( mconfig, *this ) +{ +} + +void nes_kstudio_rom_device::device_start() +{ + m_rom = (UINT8*)memregion("exrom")->base(); + save_item(NAME(m_bank)); +} + +void nes_kstudio_rom_device::device_reset() +{ + m_bank = 0; +} + +const rom_entry *nes_kstudio_rom_device::device_rom_region() const +{ + return ROM_NAME( ks_exp_rom ); +} + +UINT8 *nes_kstudio_rom_device::get_cart_base() +{ + return m_rom; +} + + +//------------------------------------------ +// +// Karaoke Studio Base Cart implementation +// +//------------------------------------------ + +const device_type NES_KARAOKESTUDIO = &device_creator; + + +nes_karaokestudio_device::nes_karaokestudio_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_KARAOKESTUDIO, "NES Cart Bandai Karaoke Studio PCB", tag, owner, clock, "nes_karaoke", __FILE__), + m_subslot(*this, "exp_slot"), + m_mic_ipt(*this, "MIC") +{ +} + + +void nes_karaokestudio_device::device_start() +{ + common_start(); + save_item(NAME(m_exp_active)); +} + +void nes_karaokestudio_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef((m_prg_chunks - 1) ^ 0x08); + chr8(0, m_chr_source); + m_exp_active = 0; +} + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + Bandai Karaoke Studio board emulation + + Games: Karaoke Studio + expansion carts with + additional songs + + Note: we currently do not emulate properly the + expansion slot + + iNES: mapper 188 + + -------------------------------------------------*/ + +READ8_MEMBER(nes_karaokestudio_device::read_m) +{ + LOG_MMC(("karaoke studio read_m, offset: %04x\n", offset)); + return m_mic_ipt->read(); +} + +READ8_MEMBER(nes_karaokestudio_device::read_h) +{ + LOG_MMC(("karaoke studio read_h, offset: %04x\n", offset)); + // this shall be the proper code, but it's a bit slower, so we access directly the subcart below + //return m_subslot->read(space, offset, mem_mask); + + // access expansion cart only if all of the followings are verified + // * we are in $8000-$bfff range + // * there has been a bankswitch write to map the expansion to such range + // * there actually is an expansion cart mounted + if (offset < 0x4000 && m_exp_active && m_subslot->m_cart) + return m_subslot->m_cart->read(space, offset, mem_mask); + else + return hi_access_rom(offset); +} + +WRITE8_MEMBER(nes_karaokestudio_device::write_h) +{ + LOG_MMC(("karaoke studio write_h, offset: %04x, data: %02x\n", offset, data)); + // bit3 1 = M ROM (main unit), 0=E ROM (expansion) + // HACK(?): currently it is not clear how the unit acknowledges the presence of the expansion + // cart (when expansion is present, code keeps switching both from the expansion rom and from + // the main ROM) + // my guess is that writes with bit3=0 and no expansion just do nothing, but it shall be verified + + if (offset >= 04000) + { + if (BIT(data, 3)) + { + m_exp_active = 0; + prg16_89ab(data & 7); + } + else // expansion cart + { + m_exp_active = 1; + m_subslot->write_prg_bank(data & 7); + } + } +} + + +static INPUT_PORTS_START( karaoke_mic ) + PORT_START("MIC") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("A (Mic Select)") PORT_CODE(KEYCODE_X) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("B (Mic Start)") PORT_CODE(KEYCODE_Z) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_NAME("Microphone (?)") PORT_CODE(KEYCODE_C) + PORT_BIT( 0xf8, IP_ACTIVE_HIGH, IPT_UNUSED ) +INPUT_PORTS_END + +ioport_constructor nes_karaokestudio_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( karaoke_mic ); +} + + +//------------------------------------------------- +// CART SLOT +//------------------------------------------------- + +static SLOT_INTERFACE_START(karaoke_studio_cart) + SLOT_INTERFACE_INTERNAL("ks_exp", NES_KSEXPANSION_ROM) +SLOT_INTERFACE_END + + +MACHINE_CONFIG_FRAGMENT( karaoke_studio ) + MCFG_KSTUDIO_MINICART_ADD("exp_slot", karaoke_studio_cart) +MACHINE_CONFIG_END + +machine_config_constructor nes_karaokestudio_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( karaoke_studio ); +} diff --git a/src/devices/bus/nes/konami.c b/src/devices/bus/nes/konami.c deleted file mode 100644 index 4cd4f1fd872..00000000000 --- a/src/devices/bus/nes/konami.c +++ /dev/null @@ -1,787 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Fabio Priuli -/*********************************************************************************************************** - - - NES/Famicom cartridge emulation for Konami PCBs - - - Here we emulate the following PCBs (multiple mappers needed due to different wirings in the pcbs - causing different addresses to be used for bankswitch & irq) - - * Konami VRC-1 [mapper 75] - * Konami VRC-2 [mapper 22,23,25] - * Konami VRC-3 [mapper 73] - * Konami VRC-4 [mapper 21,23,25] - * Konami VRC-6 [mapper 24,26] - * Konami VRC-7 [mapper 85] - - - TODO: - - improve IRQ (CPU mode not currently emulated) - - add VRC-6 sound features - - ***********************************************************************************************************/ - - -#include "emu.h" -#include "konami.h" - -#include "cpu/m6502/m6502.h" - -#ifdef NES_PCB_DEBUG -#define VERBOSE 1 -#else -#define VERBOSE 0 -#endif - -#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) - -#define N2A03_DEFAULTCLOCK (21477272.724 / 12) - -//------------------------------------------------- -// constructor -//------------------------------------------------- - -const device_type NES_VRC1 = &device_creator; -const device_type NES_VRC2 = &device_creator; -const device_type NES_VRC3 = &device_creator; -const device_type NES_VRC4 = &device_creator; -const device_type NES_VRC6 = &device_creator; -const device_type NES_VRC7 = &device_creator; - - -nes_konami_vrc1_device::nes_konami_vrc1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_VRC1, "NES Cart Konami VRC-1 PCB", tag, owner, clock, "nes_vrc1", __FILE__) -{ -} - -nes_konami_vrc2_device::nes_konami_vrc2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_VRC2, "NES Cart Konami VRC-2 PCB", tag, owner, clock, "nes_vrc2", __FILE__) -{ -} - -nes_konami_vrc3_device::nes_konami_vrc3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_VRC3, "NES Cart Konami VRC-3 PCB", tag, owner, clock, "nes_vrc3", __FILE__) -{ -} - -nes_konami_vrc4_device::nes_konami_vrc4_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) - : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source) -{ -} - -nes_konami_vrc4_device::nes_konami_vrc4_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_VRC4, "NES Cart Konami VRC-4 PCB", tag, owner, clock, "nes_vrc4", __FILE__) -{ -} - -nes_konami_vrc6_device::nes_konami_vrc6_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_konami_vrc4_device(mconfig, NES_VRC6, "NES Cart Konami VRC-6 PCB", tag, owner, clock, "nes_vrc6", __FILE__), - m_vrc6snd(*this, "vrc6snd") -{ -} - -nes_konami_vrc7_device::nes_konami_vrc7_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_konami_vrc4_device(mconfig, NES_VRC7, "NES Cart Konami VRC-7 PCB", tag, owner, clock, "nes_vrc7", __FILE__), - m_ym2413(*this, "ym") -{ -} - - - -void nes_konami_vrc1_device::device_start() -{ - common_start(); - save_item(NAME(m_mmc_vrom_bank)); -} - -void nes_konami_vrc1_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(0); - prg16_cdef(m_prg_chunks - 1); - chr8(0, m_chr_source); - - memset(m_mmc_vrom_bank, 0, sizeof(m_mmc_vrom_bank)); -} - -void nes_konami_vrc2_device::device_start() -{ - common_start(); - save_item(NAME(m_mmc_vrom_bank)); - save_item(NAME(m_latch)); -} - -void nes_konami_vrc2_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(0); - prg16_cdef(m_prg_chunks - 1); - chr8(0, m_chr_source); - - m_latch = 0; - memset(m_mmc_vrom_bank, 0, sizeof(m_mmc_vrom_bank)); -} - -void nes_konami_vrc3_device::device_start() -{ - common_start(); - irq_timer = timer_alloc(TIMER_IRQ); - irq_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1)); - - save_item(NAME(m_irq_mode)); - save_item(NAME(m_irq_enable)); - save_item(NAME(m_irq_enable_latch)); - save_item(NAME(m_irq_count)); - save_item(NAME(m_irq_count_latch)); -} - -void nes_konami_vrc3_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(0); - prg16_cdef(m_prg_chunks - 1); - chr8(0, m_chr_source); - - m_irq_mode = 0; - m_irq_enable = 0; - m_irq_enable_latch = 0; - m_irq_count = 0; - m_irq_count_latch = 0; -} - - -void nes_konami_vrc4_device::device_start() -{ - common_start(); - irq_timer = timer_alloc(TIMER_IRQ); - irq_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1)); - - save_item(NAME(m_irq_mode)); - save_item(NAME(m_irq_prescale)); - save_item(NAME(m_irq_enable)); - save_item(NAME(m_irq_enable_latch)); - save_item(NAME(m_irq_count)); - save_item(NAME(m_irq_count_latch)); - save_item(NAME(m_latch)); - save_item(NAME(m_mmc_prg_bank)); - save_item(NAME(m_mmc_vrom_bank)); -} - -void nes_konami_vrc4_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(0); - prg16_cdef(m_prg_chunks - 1); - chr8(0, m_chr_source); - - m_irq_mode = 0; - m_irq_prescale = 341; - m_irq_enable = 0; - m_irq_enable_latch = 0; - m_irq_count = 0; - m_irq_count_latch = 0; - - m_latch = 0; - m_mmc_prg_bank = 0; - memset(m_mmc_vrom_bank, 0, sizeof(m_mmc_vrom_bank)); -} - -void nes_konami_vrc6_device::device_start() -{ - nes_konami_vrc4_device::device_start(); -} - -void nes_konami_vrc7_device::device_start() -{ - common_start(); - irq_timer = timer_alloc(TIMER_IRQ); - irq_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1)); - - save_item(NAME(m_irq_mode)); - save_item(NAME(m_irq_prescale)); - save_item(NAME(m_irq_enable)); - save_item(NAME(m_irq_enable_latch)); - save_item(NAME(m_irq_count)); - save_item(NAME(m_irq_count_latch)); -} - -void nes_konami_vrc7_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg8_89(0); - prg8_ab(0); - prg8_cd(0); - prg8_ef(0xff); - chr8(0, m_chr_source); - - m_irq_mode = 0; - m_irq_prescale = 341; - m_irq_enable = 0; - m_irq_enable_latch = 0; - m_irq_count = 0; - m_irq_count_latch = 0; -} - - - -/*------------------------------------------------- - mapper specific handlers - -------------------------------------------------*/ - -/*------------------------------------------------- - - Konami VRC1 and Jaleco JF20, JF22 - - Games: Exciting Boxing, Ganbare Goemon!, Tetsuwan Atom - - iNES: mapper 75 - - In MESS: Supported. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_konami_vrc1_device::write_h) -{ - LOG_MMC(("VRC-1 write_h, offset: %04x, data: %02x\n", offset, data)); - - switch (offset & 0x7000) - { - case 0x0000: - prg8_89(data); - break; - case 0x2000: - prg8_ab(data); - break; - case 0x4000: - prg8_cd(data); - break; - case 0x1000: - set_nt_mirroring((data & 0x01) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); - m_mmc_vrom_bank[0] = (m_mmc_vrom_bank[0] & 0x0f) | ((data & 0x02) << 3); - m_mmc_vrom_bank[1] = (m_mmc_vrom_bank[1] & 0x0f) | ((data & 0x04) << 2); - chr4_0(m_mmc_vrom_bank[0], CHRROM); - chr4_4(m_mmc_vrom_bank[1], CHRROM); - break; - case 0x6000: - m_mmc_vrom_bank[0] = (m_mmc_vrom_bank[0] & 0x10) | (data & 0x0f); - chr4_0(m_mmc_vrom_bank[0], CHRROM); - break; - case 0x7000: - m_mmc_vrom_bank[1] = (m_mmc_vrom_bank[1] & 0x10) | (data & 0x0f); - chr4_4(m_mmc_vrom_bank[1], CHRROM); - break; - } -} - -/*------------------------------------------------- - - Konami VRC-2 - - In MESS: Supported. - - -------------------------------------------------*/ - -READ8_MEMBER(nes_konami_vrc2_device::read_m) -{ - LOG_MMC(("VRC-2 read_m, offset: %04x\n", offset)); - - if (!m_battery.empty()) - return m_battery[offset & (m_battery.size() - 1)]; - else if (!m_prgram.empty()) - return m_prgram[offset & (m_prgram.size() - 1)]; - else // sort of protection? it returns open bus in $7000-$7fff and (open bus & 0xfe) | m_latch in $6000-$6fff - return (offset < 0x1000) ? ((m_open_bus & 0xfe) | (m_latch & 1)) : m_open_bus; -} - -WRITE8_MEMBER(nes_konami_vrc2_device::write_m) -{ - LOG_MMC(("VRC-2 write_m, offset: %04x, data: %02x\n", offset, data)); - - if (!m_battery.empty()) - m_battery[offset & (m_battery.size() - 1)] = data; - else if (!m_prgram.empty()) - m_prgram[offset & (m_prgram.size() - 1)] = data; - else if (offset < 0x1000) - m_latch = data; -} - -WRITE8_MEMBER(nes_konami_vrc2_device::write_h) -{ - UINT8 bank, shift, mask; - UINT16 add_lines = ((offset << (9 - m_vrc_ls_prg_a)) & 0x200) | ((offset << (8 - m_vrc_ls_prg_b)) & 0x100); - LOG_MMC(("VRC-2 write_h, offset: %04x, data: %02x\n", offset, data)); - - switch (offset & 0x7000) - { - case 0x0000: - prg8_89(data); - break; - case 0x2000: - prg8_ab(data); - break; - case 0x1000: - switch (data & 0x03) - { - case 0x00: set_nt_mirroring(PPU_MIRROR_VERT); break; - case 0x01: set_nt_mirroring(PPU_MIRROR_HORZ); break; - case 0x02: set_nt_mirroring(PPU_MIRROR_LOW); break; - case 0x03: set_nt_mirroring(PPU_MIRROR_HIGH); break; - } - break; - case 0x3000: - case 0x4000: - case 0x5000: - case 0x6000: - bank = ((offset & 0x7000) - 0x3000) / 0x0800 + BIT(add_lines, 9); - shift = BIT(add_lines, 8) * 4; - mask = (0xf0 >> shift); - m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & mask) | (((data >> m_vrc_ls_chr) & 0x0f) << shift); - chr1_x(bank, m_mmc_vrom_bank[bank], CHRROM); - break; - default: - logerror("VRC-2 write_h uncaught write, addr: %04x value: %02x\n", offset + 0x8000, data); - break; - } -} - -/*------------------------------------------------- - - Konami VRC3 - - Games: Salamander - - iNES: mapper 73 - - In MESS: Supported. - - -------------------------------------------------*/ - -void nes_konami_vrc3_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) -{ - if (id == TIMER_IRQ) - { - if (m_irq_enable) - { - if (m_irq_mode) // 8bits mode - { - if ((m_irq_count & 0x00ff) == 0xff) - { - m_maincpu->set_input_line(M6502_IRQ_LINE, ASSERT_LINE); - m_irq_count = m_irq_count_latch; - } - else - m_irq_count = (m_irq_count & 0xff00) | ((m_irq_count & 0x00ff) + 1); - } - else // 16bits mode - { - if (m_irq_count == 0xffff) - { - m_maincpu->set_input_line(M6502_IRQ_LINE, ASSERT_LINE); - m_irq_count = m_irq_count_latch; - } - else - m_irq_count++; - } - } - } -} - -WRITE8_MEMBER(nes_konami_vrc3_device::write_h) -{ - LOG_MMC(("VRC-3 write_h, offset: %04x, data: %02x\n", offset, data)); - - switch (offset & 0x7000) - { - case 0x0000: - m_irq_count_latch = (m_irq_count_latch & 0xfff0) | ((data & 0x0f) << 0); - break; - case 0x1000: - m_irq_count_latch = (m_irq_count_latch & 0xff0f) | ((data & 0x0f) << 4); - break; - case 0x2000: - m_irq_count_latch = (m_irq_count_latch & 0xf0ff) | ((data & 0x0f) << 8); - break; - case 0x3000: - m_irq_count_latch = (m_irq_count_latch & 0x0fff) | ((data & 0x0f) << 12); - break; - case 0x4000: - m_irq_mode = data & 0x04; - m_irq_enable = data & 0x02; - m_irq_enable_latch = data & 0x01; - if (data & 0x02) - m_irq_count = m_irq_count_latch; - m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); - break; - case 0x5000: - m_irq_enable = m_irq_enable_latch; - m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); - break; - case 0x7000: - prg16_89ab(data); - break; - default: - logerror("VRC-3 write_h uncaught write, offset %04x, data: %02x\n", offset, data); - break; - } -} - -/*------------------------------------------------- - - Konami VRC-4 - - In MESS: Supported - - -------------------------------------------------*/ - -void nes_konami_vrc4_device::irq_tick() -{ - if (m_irq_count == 0xff) - { - m_irq_count = m_irq_count_latch; - m_maincpu->set_input_line(M6502_IRQ_LINE, ASSERT_LINE); - } - else - m_irq_count++; -} - -void nes_konami_vrc4_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) -{ - if (id == TIMER_IRQ) - { - if (m_irq_enable) - { - if (m_irq_mode) // cycle mode - irq_tick(); - else // scanline mode - { - // A prescaler divides the passing CPU cycles by 114, 114, then 113 (and repeats that order). - // This approximates 113+2/3 CPU cycles, which is one NTSC scanline. - // Since this is a CPU-based IRQ, though, it is triggered also during non visible scanlines... - if (m_irq_prescale < 3) - { - m_irq_prescale += 341; - irq_tick(); - } - - m_irq_prescale -= 3; - } - } - } -} - -void nes_konami_vrc4_device::set_prg() -{ - if (m_latch & 0x02) - { - prg8_89(0xfe); - prg8_cd(m_mmc_prg_bank); - } - else - { - prg8_89(m_mmc_prg_bank); - prg8_cd(0xfe); - } -} - -WRITE8_MEMBER(nes_konami_vrc4_device::write_h) -{ - UINT8 bank, shift, mask; - UINT16 add_lines = ((offset << (9 - m_vrc_ls_prg_a)) & 0x200) | ((offset << (8 - m_vrc_ls_prg_b)) & 0x100); - LOG_MMC(("VRC-4 write_h, offset: %04x, data: %02x\n", offset, data)); - - switch (offset & 0x7000) - { - case 0x0000: - m_mmc_prg_bank = data; - set_prg(); - break; - case 0x2000: - prg8_ab(data); - break; - case 0x1000: - if (add_lines & 0x200) - { - m_latch = data & 0x02; - set_prg(); - } - else - { - switch (data & 0x03) - { - case 0x00: set_nt_mirroring(PPU_MIRROR_VERT); break; - case 0x01: set_nt_mirroring(PPU_MIRROR_HORZ); break; - case 0x02: set_nt_mirroring(PPU_MIRROR_LOW); break; - case 0x03: set_nt_mirroring(PPU_MIRROR_HIGH); break; - } - } - break; - case 0x3000: - case 0x4000: - case 0x5000: - case 0x6000: - bank = ((offset & 0x7000) - 0x3000) / 0x0800 + BIT(add_lines, 9); - shift = BIT(add_lines, 8) * 4; - mask = (0xf0 >> shift); - m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & mask) | ((data & 0x0f) << shift); - chr1_x(bank, m_mmc_vrom_bank[bank], CHRROM); - break; - case 0x7000: - switch (add_lines) - { - case 0x000: - m_irq_count_latch = (m_irq_count_latch & 0xf0) | (data & 0x0f); - break; - case 0x100: - m_irq_count_latch = (m_irq_count_latch & 0x0f) | ((data & 0x0f) << 4); - break; - case 0x200: - m_irq_mode = data & 0x04; - m_irq_enable = data & 0x02; - m_irq_enable_latch = data & 0x01; - if (data & 0x02) - m_irq_count = m_irq_count_latch; - m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); - break; - case 0x300: - m_irq_enable = m_irq_enable_latch; - m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); - break; - } - break; - default: - logerror("VRC-4 write_h uncaught write, addr: %04x value: %02x\n", ((offset & 0x7000) | add_lines) + 0x8000, data); - break; - } -} - -/*------------------------------------------------- - - Konami VRC-6 - - In MESS: Supported. It also uses konami_irq (there are IRQ - issues though: see Akumajou Densetsu intro). - - TODO: Add sound capabilities support! - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_konami_vrc6_device::write_h) -{ - UINT8 bank; - UINT16 add_lines = ((offset << (9 - m_vrc_ls_prg_a)) & 0x200) | ((offset << (8 - m_vrc_ls_prg_b)) & 0x100); - LOG_MMC(("VRC-6 write_h, offset: %04x, data: %02x\n", offset, data)); - - switch (offset & 0x7000) - { - case 0x0000: - prg16_89ab(data); - break; - case 0x4000: - prg8_cd(data); - break; - case 0x1000: // pulse 1 & global control - m_vrc6snd->write(space, add_lines>>8, data); - break; - case 0x2000: // pulse 2 - m_vrc6snd->write(space, (add_lines>>8) | 0x100, data); - break; - case 0x3000: - if (add_lines == 0x300) - { - switch (data & 0x0c) - { - case 0x00: set_nt_mirroring(PPU_MIRROR_VERT); break; - case 0x04: set_nt_mirroring(PPU_MIRROR_HORZ); break; - case 0x08: set_nt_mirroring(PPU_MIRROR_LOW); break; - case 0x0c: set_nt_mirroring(PPU_MIRROR_HIGH); break; - } - } - else // saw - m_vrc6snd->write(space, (add_lines>>8) | 0x200, data); - break; - case 0x5000: - case 0x6000: - bank = ((offset & 0x7000) - 0x5000) / 0x0400 + ((add_lines & 0x0300) >> 8); - chr1_x(bank, data, CHRROM); - break; - case 0x7000: - switch (add_lines) - { - case 0x000: - m_irq_count_latch = data; - break; - case 0x100: - m_irq_mode = data & 0x04; - m_irq_enable = data & 0x02; - m_irq_enable_latch = data & 0x01; - if (data & 0x02) - m_irq_count = m_irq_count_latch; - m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); - break; - case 0x200: - m_irq_enable = m_irq_enable_latch; - m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); - break; - default: - logerror("VRC-6 write_h uncaught write, addr: %04x value: %02x\n", ((offset & 0x7000) | add_lines) + 0x8000, data); - break; - } - break; - default: - logerror("VRC-6 write_h uncaught write, addr: %04x value: %02x\n", ((offset & 0x7000) | add_lines) + 0x8000, data); - break; - } -} - -static MACHINE_CONFIG_FRAGMENT( vrc6 ) - - // additional sound hardware - MCFG_SPEAKER_STANDARD_MONO("addon") - - MCFG_SOUND_ADD("vrc6snd", VRC6, N2A03_DEFAULTCLOCK) - MCFG_SOUND_ROUTE(ALL_OUTPUTS, "addon", 0.5) -MACHINE_CONFIG_END - -//------------------------------------------------- -// machine_config_additions - device-specific -// machine configurations -//------------------------------------------------- - -machine_config_constructor nes_konami_vrc6_device::device_mconfig_additions() const -{ - return MACHINE_CONFIG_NAME( vrc6 ); -} - -/*------------------------------------------------- - - Konami VRC7 - - Games: Lagrange Point, Tiny Toon Adventures 2 - - iNES: mapper 85 - - In MESS: Supported. It also uses konami_irq. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_konami_vrc7_device::write_h) -{ - UINT8 bank; - LOG_MMC(("VRC-7 write_h, offset: %04x, data: %02x\n", offset, data)); - - switch (offset & 0x7038) - { - case 0x0000: - prg8_89(data); - break; - case 0x0008: - case 0x0010: - case 0x0018: - prg8_ab(data); - break; - - case 0x1000: - prg8_cd(data); - break; - - case 0x1010: - case 0x1018: - m_ym2413->register_port_w(space, 0, data); - break; - case 0x1030: - case 0x1038: - m_ym2413->data_port_w(space, 0, data); - break; - - case 0x2000: - case 0x2008: - case 0x2010: - case 0x2018: - case 0x3000: - case 0x3008: - case 0x3010: - case 0x3018: - case 0x4000: - case 0x4008: - case 0x4010: - case 0x4018: - case 0x5000: - case 0x5008: - case 0x5010: - case 0x5018: - bank = ((offset & 0x7000) - 0x2000) / 0x0800 + ((offset & 0x0018) ? 1 : 0); - chr1_x(bank, data, m_chr_source); - break; - - case 0x6000: - switch (data & 0x03) - { - case 0x00: set_nt_mirroring(PPU_MIRROR_VERT); break; - case 0x01: set_nt_mirroring(PPU_MIRROR_HORZ); break; - case 0x02: set_nt_mirroring(PPU_MIRROR_LOW); break; - case 0x03: set_nt_mirroring(PPU_MIRROR_HIGH); break; - } - break; - case 0x6008: case 0x6010: case 0x6018: - m_irq_count_latch = data; - break; - case 0x7000: - m_irq_mode = data & 0x04; - m_irq_enable = data & 0x02; - m_irq_enable_latch = data & 0x01; - if (data & 0x02) - m_irq_count = m_irq_count_latch; - m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); - break; - case 0x7008: case 0x7010: case 0x7018: - m_irq_enable = m_irq_enable_latch; - m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); - break; - - default: - logerror("VRC-7 write_h uncaught write, addr: %04x value: %02x\n", offset + 0x8000, data); - break; - } -} - - -//------------------------------------------------- -// MACHINE_DRIVER( vrc7 ) -//------------------------------------------------- - -// From NESdev wiki: The VRC7, in addition to being a mapper chip, also produces 6 channels of -// 2-operator FM Synthesis Audio. It is a derivative of the Yamaha YM2413 OPLL, implementing a -// subset of its features and containing a custom fixed patch set. -// The synthesis core is related to the Yamaha YM2413 OPLL: -// - Register layout is the same. -// - VRC7 has 6 channels, OPLL has 9. -// - VRC7 has no rhythm channels, OPLL does (the last 3 channels are either FM or Rhythm on OPLL). -// - VRC7 built-in instruments are not the same as OPLL instruments. -// - VRC7 has no readily-accessible status register, under normal circumstances it is write-only; -// OPLL has an undocumented, 2-bit 'internal state' register. -// - VRC7 has an internal state output pin (may be serial version of the 2 bit internal state register) -// and has one output pin for audio, multiplexed for all 6 channels; OPLL has two output pins, one for -// FM and one for Rhythm, and has no special status pin. - -// FIXME: we currently emulate this as a base YM2413! - -static MACHINE_CONFIG_FRAGMENT( vrc7 ) - - // additional sound hardware - MCFG_SPEAKER_STANDARD_MONO("addon") - - MCFG_SOUND_ADD("ym", YM2413, N2A03_DEFAULTCLOCK) - MCFG_SOUND_ROUTE(ALL_OUTPUTS, "addon", 0.5) -MACHINE_CONFIG_END - -//------------------------------------------------- -// machine_config_additions - device-specific -// machine configurations -//------------------------------------------------- - -machine_config_constructor nes_konami_vrc7_device::device_mconfig_additions() const -{ - return MACHINE_CONFIG_NAME( vrc7 ); -} diff --git a/src/devices/bus/nes/konami.cpp b/src/devices/bus/nes/konami.cpp new file mode 100644 index 00000000000..4cd4f1fd872 --- /dev/null +++ b/src/devices/bus/nes/konami.cpp @@ -0,0 +1,787 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for Konami PCBs + + + Here we emulate the following PCBs (multiple mappers needed due to different wirings in the pcbs + causing different addresses to be used for bankswitch & irq) + + * Konami VRC-1 [mapper 75] + * Konami VRC-2 [mapper 22,23,25] + * Konami VRC-3 [mapper 73] + * Konami VRC-4 [mapper 21,23,25] + * Konami VRC-6 [mapper 24,26] + * Konami VRC-7 [mapper 85] + + + TODO: + - improve IRQ (CPU mode not currently emulated) + - add VRC-6 sound features + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "konami.h" + +#include "cpu/m6502/m6502.h" + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + +#define N2A03_DEFAULTCLOCK (21477272.724 / 12) + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_VRC1 = &device_creator; +const device_type NES_VRC2 = &device_creator; +const device_type NES_VRC3 = &device_creator; +const device_type NES_VRC4 = &device_creator; +const device_type NES_VRC6 = &device_creator; +const device_type NES_VRC7 = &device_creator; + + +nes_konami_vrc1_device::nes_konami_vrc1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_VRC1, "NES Cart Konami VRC-1 PCB", tag, owner, clock, "nes_vrc1", __FILE__) +{ +} + +nes_konami_vrc2_device::nes_konami_vrc2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_VRC2, "NES Cart Konami VRC-2 PCB", tag, owner, clock, "nes_vrc2", __FILE__) +{ +} + +nes_konami_vrc3_device::nes_konami_vrc3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_VRC3, "NES Cart Konami VRC-3 PCB", tag, owner, clock, "nes_vrc3", __FILE__) +{ +} + +nes_konami_vrc4_device::nes_konami_vrc4_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +nes_konami_vrc4_device::nes_konami_vrc4_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_VRC4, "NES Cart Konami VRC-4 PCB", tag, owner, clock, "nes_vrc4", __FILE__) +{ +} + +nes_konami_vrc6_device::nes_konami_vrc6_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_konami_vrc4_device(mconfig, NES_VRC6, "NES Cart Konami VRC-6 PCB", tag, owner, clock, "nes_vrc6", __FILE__), + m_vrc6snd(*this, "vrc6snd") +{ +} + +nes_konami_vrc7_device::nes_konami_vrc7_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_konami_vrc4_device(mconfig, NES_VRC7, "NES Cart Konami VRC-7 PCB", tag, owner, clock, "nes_vrc7", __FILE__), + m_ym2413(*this, "ym") +{ +} + + + +void nes_konami_vrc1_device::device_start() +{ + common_start(); + save_item(NAME(m_mmc_vrom_bank)); +} + +void nes_konami_vrc1_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + + memset(m_mmc_vrom_bank, 0, sizeof(m_mmc_vrom_bank)); +} + +void nes_konami_vrc2_device::device_start() +{ + common_start(); + save_item(NAME(m_mmc_vrom_bank)); + save_item(NAME(m_latch)); +} + +void nes_konami_vrc2_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + + m_latch = 0; + memset(m_mmc_vrom_bank, 0, sizeof(m_mmc_vrom_bank)); +} + +void nes_konami_vrc3_device::device_start() +{ + common_start(); + irq_timer = timer_alloc(TIMER_IRQ); + irq_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1)); + + save_item(NAME(m_irq_mode)); + save_item(NAME(m_irq_enable)); + save_item(NAME(m_irq_enable_latch)); + save_item(NAME(m_irq_count)); + save_item(NAME(m_irq_count_latch)); +} + +void nes_konami_vrc3_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + + m_irq_mode = 0; + m_irq_enable = 0; + m_irq_enable_latch = 0; + m_irq_count = 0; + m_irq_count_latch = 0; +} + + +void nes_konami_vrc4_device::device_start() +{ + common_start(); + irq_timer = timer_alloc(TIMER_IRQ); + irq_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1)); + + save_item(NAME(m_irq_mode)); + save_item(NAME(m_irq_prescale)); + save_item(NAME(m_irq_enable)); + save_item(NAME(m_irq_enable_latch)); + save_item(NAME(m_irq_count)); + save_item(NAME(m_irq_count_latch)); + save_item(NAME(m_latch)); + save_item(NAME(m_mmc_prg_bank)); + save_item(NAME(m_mmc_vrom_bank)); +} + +void nes_konami_vrc4_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + + m_irq_mode = 0; + m_irq_prescale = 341; + m_irq_enable = 0; + m_irq_enable_latch = 0; + m_irq_count = 0; + m_irq_count_latch = 0; + + m_latch = 0; + m_mmc_prg_bank = 0; + memset(m_mmc_vrom_bank, 0, sizeof(m_mmc_vrom_bank)); +} + +void nes_konami_vrc6_device::device_start() +{ + nes_konami_vrc4_device::device_start(); +} + +void nes_konami_vrc7_device::device_start() +{ + common_start(); + irq_timer = timer_alloc(TIMER_IRQ); + irq_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1)); + + save_item(NAME(m_irq_mode)); + save_item(NAME(m_irq_prescale)); + save_item(NAME(m_irq_enable)); + save_item(NAME(m_irq_enable_latch)); + save_item(NAME(m_irq_count)); + save_item(NAME(m_irq_count_latch)); +} + +void nes_konami_vrc7_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg8_89(0); + prg8_ab(0); + prg8_cd(0); + prg8_ef(0xff); + chr8(0, m_chr_source); + + m_irq_mode = 0; + m_irq_prescale = 341; + m_irq_enable = 0; + m_irq_enable_latch = 0; + m_irq_count = 0; + m_irq_count_latch = 0; +} + + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + Konami VRC1 and Jaleco JF20, JF22 + + Games: Exciting Boxing, Ganbare Goemon!, Tetsuwan Atom + + iNES: mapper 75 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_konami_vrc1_device::write_h) +{ + LOG_MMC(("VRC-1 write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x7000) + { + case 0x0000: + prg8_89(data); + break; + case 0x2000: + prg8_ab(data); + break; + case 0x4000: + prg8_cd(data); + break; + case 0x1000: + set_nt_mirroring((data & 0x01) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + m_mmc_vrom_bank[0] = (m_mmc_vrom_bank[0] & 0x0f) | ((data & 0x02) << 3); + m_mmc_vrom_bank[1] = (m_mmc_vrom_bank[1] & 0x0f) | ((data & 0x04) << 2); + chr4_0(m_mmc_vrom_bank[0], CHRROM); + chr4_4(m_mmc_vrom_bank[1], CHRROM); + break; + case 0x6000: + m_mmc_vrom_bank[0] = (m_mmc_vrom_bank[0] & 0x10) | (data & 0x0f); + chr4_0(m_mmc_vrom_bank[0], CHRROM); + break; + case 0x7000: + m_mmc_vrom_bank[1] = (m_mmc_vrom_bank[1] & 0x10) | (data & 0x0f); + chr4_4(m_mmc_vrom_bank[1], CHRROM); + break; + } +} + +/*------------------------------------------------- + + Konami VRC-2 + + In MESS: Supported. + + -------------------------------------------------*/ + +READ8_MEMBER(nes_konami_vrc2_device::read_m) +{ + LOG_MMC(("VRC-2 read_m, offset: %04x\n", offset)); + + if (!m_battery.empty()) + return m_battery[offset & (m_battery.size() - 1)]; + else if (!m_prgram.empty()) + return m_prgram[offset & (m_prgram.size() - 1)]; + else // sort of protection? it returns open bus in $7000-$7fff and (open bus & 0xfe) | m_latch in $6000-$6fff + return (offset < 0x1000) ? ((m_open_bus & 0xfe) | (m_latch & 1)) : m_open_bus; +} + +WRITE8_MEMBER(nes_konami_vrc2_device::write_m) +{ + LOG_MMC(("VRC-2 write_m, offset: %04x, data: %02x\n", offset, data)); + + if (!m_battery.empty()) + m_battery[offset & (m_battery.size() - 1)] = data; + else if (!m_prgram.empty()) + m_prgram[offset & (m_prgram.size() - 1)] = data; + else if (offset < 0x1000) + m_latch = data; +} + +WRITE8_MEMBER(nes_konami_vrc2_device::write_h) +{ + UINT8 bank, shift, mask; + UINT16 add_lines = ((offset << (9 - m_vrc_ls_prg_a)) & 0x200) | ((offset << (8 - m_vrc_ls_prg_b)) & 0x100); + LOG_MMC(("VRC-2 write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x7000) + { + case 0x0000: + prg8_89(data); + break; + case 0x2000: + prg8_ab(data); + break; + case 0x1000: + switch (data & 0x03) + { + case 0x00: set_nt_mirroring(PPU_MIRROR_VERT); break; + case 0x01: set_nt_mirroring(PPU_MIRROR_HORZ); break; + case 0x02: set_nt_mirroring(PPU_MIRROR_LOW); break; + case 0x03: set_nt_mirroring(PPU_MIRROR_HIGH); break; + } + break; + case 0x3000: + case 0x4000: + case 0x5000: + case 0x6000: + bank = ((offset & 0x7000) - 0x3000) / 0x0800 + BIT(add_lines, 9); + shift = BIT(add_lines, 8) * 4; + mask = (0xf0 >> shift); + m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & mask) | (((data >> m_vrc_ls_chr) & 0x0f) << shift); + chr1_x(bank, m_mmc_vrom_bank[bank], CHRROM); + break; + default: + logerror("VRC-2 write_h uncaught write, addr: %04x value: %02x\n", offset + 0x8000, data); + break; + } +} + +/*------------------------------------------------- + + Konami VRC3 + + Games: Salamander + + iNES: mapper 73 + + In MESS: Supported. + + -------------------------------------------------*/ + +void nes_konami_vrc3_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (id == TIMER_IRQ) + { + if (m_irq_enable) + { + if (m_irq_mode) // 8bits mode + { + if ((m_irq_count & 0x00ff) == 0xff) + { + m_maincpu->set_input_line(M6502_IRQ_LINE, ASSERT_LINE); + m_irq_count = m_irq_count_latch; + } + else + m_irq_count = (m_irq_count & 0xff00) | ((m_irq_count & 0x00ff) + 1); + } + else // 16bits mode + { + if (m_irq_count == 0xffff) + { + m_maincpu->set_input_line(M6502_IRQ_LINE, ASSERT_LINE); + m_irq_count = m_irq_count_latch; + } + else + m_irq_count++; + } + } + } +} + +WRITE8_MEMBER(nes_konami_vrc3_device::write_h) +{ + LOG_MMC(("VRC-3 write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x7000) + { + case 0x0000: + m_irq_count_latch = (m_irq_count_latch & 0xfff0) | ((data & 0x0f) << 0); + break; + case 0x1000: + m_irq_count_latch = (m_irq_count_latch & 0xff0f) | ((data & 0x0f) << 4); + break; + case 0x2000: + m_irq_count_latch = (m_irq_count_latch & 0xf0ff) | ((data & 0x0f) << 8); + break; + case 0x3000: + m_irq_count_latch = (m_irq_count_latch & 0x0fff) | ((data & 0x0f) << 12); + break; + case 0x4000: + m_irq_mode = data & 0x04; + m_irq_enable = data & 0x02; + m_irq_enable_latch = data & 0x01; + if (data & 0x02) + m_irq_count = m_irq_count_latch; + m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); + break; + case 0x5000: + m_irq_enable = m_irq_enable_latch; + m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); + break; + case 0x7000: + prg16_89ab(data); + break; + default: + logerror("VRC-3 write_h uncaught write, offset %04x, data: %02x\n", offset, data); + break; + } +} + +/*------------------------------------------------- + + Konami VRC-4 + + In MESS: Supported + + -------------------------------------------------*/ + +void nes_konami_vrc4_device::irq_tick() +{ + if (m_irq_count == 0xff) + { + m_irq_count = m_irq_count_latch; + m_maincpu->set_input_line(M6502_IRQ_LINE, ASSERT_LINE); + } + else + m_irq_count++; +} + +void nes_konami_vrc4_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (id == TIMER_IRQ) + { + if (m_irq_enable) + { + if (m_irq_mode) // cycle mode + irq_tick(); + else // scanline mode + { + // A prescaler divides the passing CPU cycles by 114, 114, then 113 (and repeats that order). + // This approximates 113+2/3 CPU cycles, which is one NTSC scanline. + // Since this is a CPU-based IRQ, though, it is triggered also during non visible scanlines... + if (m_irq_prescale < 3) + { + m_irq_prescale += 341; + irq_tick(); + } + + m_irq_prescale -= 3; + } + } + } +} + +void nes_konami_vrc4_device::set_prg() +{ + if (m_latch & 0x02) + { + prg8_89(0xfe); + prg8_cd(m_mmc_prg_bank); + } + else + { + prg8_89(m_mmc_prg_bank); + prg8_cd(0xfe); + } +} + +WRITE8_MEMBER(nes_konami_vrc4_device::write_h) +{ + UINT8 bank, shift, mask; + UINT16 add_lines = ((offset << (9 - m_vrc_ls_prg_a)) & 0x200) | ((offset << (8 - m_vrc_ls_prg_b)) & 0x100); + LOG_MMC(("VRC-4 write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x7000) + { + case 0x0000: + m_mmc_prg_bank = data; + set_prg(); + break; + case 0x2000: + prg8_ab(data); + break; + case 0x1000: + if (add_lines & 0x200) + { + m_latch = data & 0x02; + set_prg(); + } + else + { + switch (data & 0x03) + { + case 0x00: set_nt_mirroring(PPU_MIRROR_VERT); break; + case 0x01: set_nt_mirroring(PPU_MIRROR_HORZ); break; + case 0x02: set_nt_mirroring(PPU_MIRROR_LOW); break; + case 0x03: set_nt_mirroring(PPU_MIRROR_HIGH); break; + } + } + break; + case 0x3000: + case 0x4000: + case 0x5000: + case 0x6000: + bank = ((offset & 0x7000) - 0x3000) / 0x0800 + BIT(add_lines, 9); + shift = BIT(add_lines, 8) * 4; + mask = (0xf0 >> shift); + m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & mask) | ((data & 0x0f) << shift); + chr1_x(bank, m_mmc_vrom_bank[bank], CHRROM); + break; + case 0x7000: + switch (add_lines) + { + case 0x000: + m_irq_count_latch = (m_irq_count_latch & 0xf0) | (data & 0x0f); + break; + case 0x100: + m_irq_count_latch = (m_irq_count_latch & 0x0f) | ((data & 0x0f) << 4); + break; + case 0x200: + m_irq_mode = data & 0x04; + m_irq_enable = data & 0x02; + m_irq_enable_latch = data & 0x01; + if (data & 0x02) + m_irq_count = m_irq_count_latch; + m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); + break; + case 0x300: + m_irq_enable = m_irq_enable_latch; + m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); + break; + } + break; + default: + logerror("VRC-4 write_h uncaught write, addr: %04x value: %02x\n", ((offset & 0x7000) | add_lines) + 0x8000, data); + break; + } +} + +/*------------------------------------------------- + + Konami VRC-6 + + In MESS: Supported. It also uses konami_irq (there are IRQ + issues though: see Akumajou Densetsu intro). + + TODO: Add sound capabilities support! + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_konami_vrc6_device::write_h) +{ + UINT8 bank; + UINT16 add_lines = ((offset << (9 - m_vrc_ls_prg_a)) & 0x200) | ((offset << (8 - m_vrc_ls_prg_b)) & 0x100); + LOG_MMC(("VRC-6 write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x7000) + { + case 0x0000: + prg16_89ab(data); + break; + case 0x4000: + prg8_cd(data); + break; + case 0x1000: // pulse 1 & global control + m_vrc6snd->write(space, add_lines>>8, data); + break; + case 0x2000: // pulse 2 + m_vrc6snd->write(space, (add_lines>>8) | 0x100, data); + break; + case 0x3000: + if (add_lines == 0x300) + { + switch (data & 0x0c) + { + case 0x00: set_nt_mirroring(PPU_MIRROR_VERT); break; + case 0x04: set_nt_mirroring(PPU_MIRROR_HORZ); break; + case 0x08: set_nt_mirroring(PPU_MIRROR_LOW); break; + case 0x0c: set_nt_mirroring(PPU_MIRROR_HIGH); break; + } + } + else // saw + m_vrc6snd->write(space, (add_lines>>8) | 0x200, data); + break; + case 0x5000: + case 0x6000: + bank = ((offset & 0x7000) - 0x5000) / 0x0400 + ((add_lines & 0x0300) >> 8); + chr1_x(bank, data, CHRROM); + break; + case 0x7000: + switch (add_lines) + { + case 0x000: + m_irq_count_latch = data; + break; + case 0x100: + m_irq_mode = data & 0x04; + m_irq_enable = data & 0x02; + m_irq_enable_latch = data & 0x01; + if (data & 0x02) + m_irq_count = m_irq_count_latch; + m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); + break; + case 0x200: + m_irq_enable = m_irq_enable_latch; + m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); + break; + default: + logerror("VRC-6 write_h uncaught write, addr: %04x value: %02x\n", ((offset & 0x7000) | add_lines) + 0x8000, data); + break; + } + break; + default: + logerror("VRC-6 write_h uncaught write, addr: %04x value: %02x\n", ((offset & 0x7000) | add_lines) + 0x8000, data); + break; + } +} + +static MACHINE_CONFIG_FRAGMENT( vrc6 ) + + // additional sound hardware + MCFG_SPEAKER_STANDARD_MONO("addon") + + MCFG_SOUND_ADD("vrc6snd", VRC6, N2A03_DEFAULTCLOCK) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "addon", 0.5) +MACHINE_CONFIG_END + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor nes_konami_vrc6_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( vrc6 ); +} + +/*------------------------------------------------- + + Konami VRC7 + + Games: Lagrange Point, Tiny Toon Adventures 2 + + iNES: mapper 85 + + In MESS: Supported. It also uses konami_irq. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_konami_vrc7_device::write_h) +{ + UINT8 bank; + LOG_MMC(("VRC-7 write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x7038) + { + case 0x0000: + prg8_89(data); + break; + case 0x0008: + case 0x0010: + case 0x0018: + prg8_ab(data); + break; + + case 0x1000: + prg8_cd(data); + break; + + case 0x1010: + case 0x1018: + m_ym2413->register_port_w(space, 0, data); + break; + case 0x1030: + case 0x1038: + m_ym2413->data_port_w(space, 0, data); + break; + + case 0x2000: + case 0x2008: + case 0x2010: + case 0x2018: + case 0x3000: + case 0x3008: + case 0x3010: + case 0x3018: + case 0x4000: + case 0x4008: + case 0x4010: + case 0x4018: + case 0x5000: + case 0x5008: + case 0x5010: + case 0x5018: + bank = ((offset & 0x7000) - 0x2000) / 0x0800 + ((offset & 0x0018) ? 1 : 0); + chr1_x(bank, data, m_chr_source); + break; + + case 0x6000: + switch (data & 0x03) + { + case 0x00: set_nt_mirroring(PPU_MIRROR_VERT); break; + case 0x01: set_nt_mirroring(PPU_MIRROR_HORZ); break; + case 0x02: set_nt_mirroring(PPU_MIRROR_LOW); break; + case 0x03: set_nt_mirroring(PPU_MIRROR_HIGH); break; + } + break; + case 0x6008: case 0x6010: case 0x6018: + m_irq_count_latch = data; + break; + case 0x7000: + m_irq_mode = data & 0x04; + m_irq_enable = data & 0x02; + m_irq_enable_latch = data & 0x01; + if (data & 0x02) + m_irq_count = m_irq_count_latch; + m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); + break; + case 0x7008: case 0x7010: case 0x7018: + m_irq_enable = m_irq_enable_latch; + m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); + break; + + default: + logerror("VRC-7 write_h uncaught write, addr: %04x value: %02x\n", offset + 0x8000, data); + break; + } +} + + +//------------------------------------------------- +// MACHINE_DRIVER( vrc7 ) +//------------------------------------------------- + +// From NESdev wiki: The VRC7, in addition to being a mapper chip, also produces 6 channels of +// 2-operator FM Synthesis Audio. It is a derivative of the Yamaha YM2413 OPLL, implementing a +// subset of its features and containing a custom fixed patch set. +// The synthesis core is related to the Yamaha YM2413 OPLL: +// - Register layout is the same. +// - VRC7 has 6 channels, OPLL has 9. +// - VRC7 has no rhythm channels, OPLL does (the last 3 channels are either FM or Rhythm on OPLL). +// - VRC7 built-in instruments are not the same as OPLL instruments. +// - VRC7 has no readily-accessible status register, under normal circumstances it is write-only; +// OPLL has an undocumented, 2-bit 'internal state' register. +// - VRC7 has an internal state output pin (may be serial version of the 2 bit internal state register) +// and has one output pin for audio, multiplexed for all 6 channels; OPLL has two output pins, one for +// FM and one for Rhythm, and has no special status pin. + +// FIXME: we currently emulate this as a base YM2413! + +static MACHINE_CONFIG_FRAGMENT( vrc7 ) + + // additional sound hardware + MCFG_SPEAKER_STANDARD_MONO("addon") + + MCFG_SOUND_ADD("ym", YM2413, N2A03_DEFAULTCLOCK) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "addon", 0.5) +MACHINE_CONFIG_END + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor nes_konami_vrc7_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( vrc7 ); +} diff --git a/src/devices/bus/nes/legacy.c b/src/devices/bus/nes/legacy.c deleted file mode 100644 index 3a452fd2f39..00000000000 --- a/src/devices/bus/nes/legacy.c +++ /dev/null @@ -1,311 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Fabio Priuli -/*********************************************************************************************************** - - - NES/Famicom cartridge emulation for FFE PCBs - - - Here we emulate the mappers used by available Far Front East copier hacked games [mappers 6, 8, 17] - - TODO: - - investigate IRQ mechanism (current code is broken) - - replace this with proper copier emulation, using disk images... - - ***********************************************************************************************************/ - - -#include "emu.h" -#include "legacy.h" - -#include "cpu/m6502/m6502.h" - - -#ifdef NES_PCB_DEBUG -#define VERBOSE 1 -#else -#define VERBOSE 0 -#endif - -#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) - - -//------------------------------------------------- -// constructor -//------------------------------------------------- - -const device_type NES_FFE3 = &device_creator; -const device_type NES_FFE4 = &device_creator; -const device_type NES_FFE8 = &device_creator; - - -nes_ffe3_device::nes_ffe3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_FFE3, "NES Cart FFE-3 PCB", tag, owner, clock, "nes_ff3", __FILE__) -{ -} - -nes_ffe4_device::nes_ffe4_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) - : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source) -{ -} - -nes_ffe4_device::nes_ffe4_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_FFE4, "NES Cart FFE-4 PCB", tag, owner, clock, "nes_ff4", __FILE__) -{ -} - -nes_ffe8_device::nes_ffe8_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_ffe4_device(mconfig, NES_FFE8, "NES Cart FFE-8 PCB", tag, owner, clock, "nes_ff8", __FILE__) -{ -} - - - -void nes_ffe3_device::device_start() -{ - common_start(); -} - -void nes_ffe3_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0); - chr8(0, m_chr_source); -} - - -void nes_ffe4_device::device_start() -{ - common_start(); - irq_timer = timer_alloc(TIMER_IRQ); - irq_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1)); - - save_item(NAME(m_exram)); - save_item(NAME(m_exram_enabled)); - save_item(NAME(m_exram_bank)); - - save_item(NAME(m_irq_enable)); - save_item(NAME(m_irq_count)); - save_item(NAME(m_latch)); -} - -void nes_ffe4_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(0); - prg16_cdef(7); - chr8(0, m_chr_source); - - m_exram_enabled = 0; - m_exram_bank = 0; - - m_latch = 0; - m_irq_enable = 0; - m_irq_count = 0; -} - - -void nes_ffe8_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(0); - prg16_cdef(0xff); - chr8(0, m_chr_source); - - // extra vram is not used by this board, so these will remain always zero - m_exram_enabled = 0; - m_exram_bank = 0; - - m_latch = 0; - m_irq_enable = 0; - m_irq_count = 0; -} - - - -/*------------------------------------------------- - mapper specific handlers - -------------------------------------------------*/ - -/*------------------------------------------------- - - Mapper 8 - - Known Boards: FFE3 Copier Board - Games: Hacked versions of games - - In MESS: Supported? (I have no games to test this) - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_ffe3_device::write_h) -{ - LOG_MMC(("mapper8 write_h, offset: %04x, data: %02x\n", offset, data)); - - chr8(data & 0x07, CHRROM); - prg16_89ab(data >> 3); -} - -/*------------------------------------------------- - - Mapper 6 - - Known Boards: FFE4 Copier Board - Games: Hacked versions of games - - In MESS: Supported? Not sure if we could also have ExRAM or not... - However, priority is pretty low for this mapper. - - -------------------------------------------------*/ - -void nes_ffe4_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) -{ - if (id == TIMER_IRQ) - { - if (m_irq_enable) - { - if (m_irq_count == 0xffff) - { - m_maincpu->set_input_line(M6502_IRQ_LINE, ASSERT_LINE); - m_irq_count = 0; - m_irq_enable = 0; - } - else - m_irq_count++; - } - } -} - -WRITE8_MEMBER(nes_ffe4_device::write_l) -{ - LOG_MMC(("mapper6 write_l, offset: %04x, data: %02x\n", offset, data)); - - switch (offset) - { - case 0x1fe: - m_latch = data & 0x80; - set_nt_mirroring(BIT(data, 4) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW); - break; - case 0x1ff: - set_nt_mirroring(BIT(data, 4) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); - break; - - case 0x401: - m_irq_enable = 0; - m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); - break; - case 0x402: - m_irq_count = (m_irq_count & 0xff00) | data; - break; - case 0x403: - m_irq_enable = 1; - m_irq_count = (m_irq_count & 0x00ff) | (data << 8); - break; - } -} - -WRITE8_MEMBER(nes_ffe4_device::chr_w) -{ - int bank = offset >> 10; - if (m_exram_enabled) - m_exram[(m_exram_bank * 0x2000) + (bank * 0x400) + (offset & 0x3ff)] = data; - - if (m_chr_src[bank] == CHRRAM) - m_chr_access[bank][offset & 0x3ff] = data; -} - -READ8_MEMBER(nes_ffe4_device::chr_r) -{ - int bank = offset >> 10; - if (m_exram_enabled) - return m_exram[(m_exram_bank * 0x2000) + (bank * 0x400) + (offset & 0x3ff)]; - - return m_chr_access[bank][offset & 0x3ff]; -} - - -WRITE8_MEMBER(nes_ffe4_device::write_h) -{ - LOG_MMC(("mapper6 write_h, offset: %04x, data: %02x\n", offset, data)); - - if (!m_latch) // when in "FFE mode" we are forced to use CHRRAM/EXRAM bank? - { - prg16_89ab(data >> 2); - - // This part is not fully documented, so we proceed a bit blindly... - if ((data & 0x03) == 0) - { - m_exram_enabled = 0; - chr8(0, CHRRAM); - } - else - { - m_exram_enabled = 1; - m_exram_bank = data & 0x03; - } - } - else // otherwise, we use CHRROM (shall we check if it's present?) - chr8(data, CHRROM); -} - -/*------------------------------------------------- - - Mapper 17 - - Known Boards: FFE8 Copier Board - Games: Hacked versions of games - - In MESS: Partially Supported. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_ffe8_device::write_l) -{ - LOG_MMC(("mapper17 write_l, offset: %04x, data: %02x\n", offset, data)); - - switch (offset) - { - case 0x1fe: - set_nt_mirroring(BIT(data, 4) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW); - break; - case 0x1ff: - set_nt_mirroring(BIT(data, 4) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); - break; - - case 0x401: - m_irq_enable = 0; - m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); - break; - case 0x402: - m_irq_count = (m_irq_count & 0xff00) | data; - break; - case 0x403: - m_irq_enable = 1; - m_irq_count = (m_irq_count & 0x00ff) | (data << 8); - break; - - case 0x404: - prg8_89(data); - break; - case 0x405: - prg8_ab(data); - break; - case 0x406: - prg8_cd(data); - break; - case 0x407: - prg8_ef(data); - break; - - case 0x410: - case 0x411: - case 0x412: - case 0x413: - case 0x414: - case 0x415: - case 0x416: - case 0x417: - chr1_x(offset & 7, data, CHRROM); - break; - } -} diff --git a/src/devices/bus/nes/legacy.cpp b/src/devices/bus/nes/legacy.cpp new file mode 100644 index 00000000000..3a452fd2f39 --- /dev/null +++ b/src/devices/bus/nes/legacy.cpp @@ -0,0 +1,311 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for FFE PCBs + + + Here we emulate the mappers used by available Far Front East copier hacked games [mappers 6, 8, 17] + + TODO: + - investigate IRQ mechanism (current code is broken) + - replace this with proper copier emulation, using disk images... + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "legacy.h" + +#include "cpu/m6502/m6502.h" + + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_FFE3 = &device_creator; +const device_type NES_FFE4 = &device_creator; +const device_type NES_FFE8 = &device_creator; + + +nes_ffe3_device::nes_ffe3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_FFE3, "NES Cart FFE-3 PCB", tag, owner, clock, "nes_ff3", __FILE__) +{ +} + +nes_ffe4_device::nes_ffe4_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +nes_ffe4_device::nes_ffe4_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_FFE4, "NES Cart FFE-4 PCB", tag, owner, clock, "nes_ff4", __FILE__) +{ +} + +nes_ffe8_device::nes_ffe8_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_ffe4_device(mconfig, NES_FFE8, "NES Cart FFE-8 PCB", tag, owner, clock, "nes_ff8", __FILE__) +{ +} + + + +void nes_ffe3_device::device_start() +{ + common_start(); +} + +void nes_ffe3_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + + +void nes_ffe4_device::device_start() +{ + common_start(); + irq_timer = timer_alloc(TIMER_IRQ); + irq_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1)); + + save_item(NAME(m_exram)); + save_item(NAME(m_exram_enabled)); + save_item(NAME(m_exram_bank)); + + save_item(NAME(m_irq_enable)); + save_item(NAME(m_irq_count)); + save_item(NAME(m_latch)); +} + +void nes_ffe4_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(7); + chr8(0, m_chr_source); + + m_exram_enabled = 0; + m_exram_bank = 0; + + m_latch = 0; + m_irq_enable = 0; + m_irq_count = 0; +} + + +void nes_ffe8_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(0xff); + chr8(0, m_chr_source); + + // extra vram is not used by this board, so these will remain always zero + m_exram_enabled = 0; + m_exram_bank = 0; + + m_latch = 0; + m_irq_enable = 0; + m_irq_count = 0; +} + + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + Mapper 8 + + Known Boards: FFE3 Copier Board + Games: Hacked versions of games + + In MESS: Supported? (I have no games to test this) + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_ffe3_device::write_h) +{ + LOG_MMC(("mapper8 write_h, offset: %04x, data: %02x\n", offset, data)); + + chr8(data & 0x07, CHRROM); + prg16_89ab(data >> 3); +} + +/*------------------------------------------------- + + Mapper 6 + + Known Boards: FFE4 Copier Board + Games: Hacked versions of games + + In MESS: Supported? Not sure if we could also have ExRAM or not... + However, priority is pretty low for this mapper. + + -------------------------------------------------*/ + +void nes_ffe4_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (id == TIMER_IRQ) + { + if (m_irq_enable) + { + if (m_irq_count == 0xffff) + { + m_maincpu->set_input_line(M6502_IRQ_LINE, ASSERT_LINE); + m_irq_count = 0; + m_irq_enable = 0; + } + else + m_irq_count++; + } + } +} + +WRITE8_MEMBER(nes_ffe4_device::write_l) +{ + LOG_MMC(("mapper6 write_l, offset: %04x, data: %02x\n", offset, data)); + + switch (offset) + { + case 0x1fe: + m_latch = data & 0x80; + set_nt_mirroring(BIT(data, 4) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW); + break; + case 0x1ff: + set_nt_mirroring(BIT(data, 4) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + break; + + case 0x401: + m_irq_enable = 0; + m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); + break; + case 0x402: + m_irq_count = (m_irq_count & 0xff00) | data; + break; + case 0x403: + m_irq_enable = 1; + m_irq_count = (m_irq_count & 0x00ff) | (data << 8); + break; + } +} + +WRITE8_MEMBER(nes_ffe4_device::chr_w) +{ + int bank = offset >> 10; + if (m_exram_enabled) + m_exram[(m_exram_bank * 0x2000) + (bank * 0x400) + (offset & 0x3ff)] = data; + + if (m_chr_src[bank] == CHRRAM) + m_chr_access[bank][offset & 0x3ff] = data; +} + +READ8_MEMBER(nes_ffe4_device::chr_r) +{ + int bank = offset >> 10; + if (m_exram_enabled) + return m_exram[(m_exram_bank * 0x2000) + (bank * 0x400) + (offset & 0x3ff)]; + + return m_chr_access[bank][offset & 0x3ff]; +} + + +WRITE8_MEMBER(nes_ffe4_device::write_h) +{ + LOG_MMC(("mapper6 write_h, offset: %04x, data: %02x\n", offset, data)); + + if (!m_latch) // when in "FFE mode" we are forced to use CHRRAM/EXRAM bank? + { + prg16_89ab(data >> 2); + + // This part is not fully documented, so we proceed a bit blindly... + if ((data & 0x03) == 0) + { + m_exram_enabled = 0; + chr8(0, CHRRAM); + } + else + { + m_exram_enabled = 1; + m_exram_bank = data & 0x03; + } + } + else // otherwise, we use CHRROM (shall we check if it's present?) + chr8(data, CHRROM); +} + +/*------------------------------------------------- + + Mapper 17 + + Known Boards: FFE8 Copier Board + Games: Hacked versions of games + + In MESS: Partially Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_ffe8_device::write_l) +{ + LOG_MMC(("mapper17 write_l, offset: %04x, data: %02x\n", offset, data)); + + switch (offset) + { + case 0x1fe: + set_nt_mirroring(BIT(data, 4) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW); + break; + case 0x1ff: + set_nt_mirroring(BIT(data, 4) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + break; + + case 0x401: + m_irq_enable = 0; + m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); + break; + case 0x402: + m_irq_count = (m_irq_count & 0xff00) | data; + break; + case 0x403: + m_irq_enable = 1; + m_irq_count = (m_irq_count & 0x00ff) | (data << 8); + break; + + case 0x404: + prg8_89(data); + break; + case 0x405: + prg8_ab(data); + break; + case 0x406: + prg8_cd(data); + break; + case 0x407: + prg8_ef(data); + break; + + case 0x410: + case 0x411: + case 0x412: + case 0x413: + case 0x414: + case 0x415: + case 0x416: + case 0x417: + chr1_x(offset & 7, data, CHRROM); + break; + } +} diff --git a/src/devices/bus/nes/mmc1.c b/src/devices/bus/nes/mmc1.c deleted file mode 100644 index ff31250ee19..00000000000 --- a/src/devices/bus/nes/mmc1.c +++ /dev/null @@ -1,374 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Fabio Priuli -/*********************************************************************************************************** - - - NES/Famicom cartridge emulation for Nintendo MMC-1 PCBs - - - Here we emulate the Nintendo SxROM / MMC-1 PCBs + older variants without WRAM protect bit - - Known issues on specific mappers: - - * 001 Yoshi flashes in-game. - * 001 Back to the Future have heavily corrupted graphics (since forever). - - ***********************************************************************************************************/ - - -#include "emu.h" -#include "mmc1.h" - -#ifdef NES_PCB_DEBUG -#define VERBOSE 1 -#else -#define VERBOSE 0 -#endif - -#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) - - -//------------------------------------------------- -// constructor -//------------------------------------------------- - -const device_type NES_SXROM = &device_creator; -const device_type NES_SOROM = &device_creator; -const device_type NES_SXROM_A = &device_creator; -const device_type NES_SOROM_A = &device_creator; - - - -nes_sxrom_device::nes_sxrom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) - : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source) -{ -} - -nes_sxrom_device::nes_sxrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_SXROM, "NES Cart SxROM (MMC-1) PCB", tag, owner, clock, "nes_sxrom", __FILE__) -{ -} - -nes_sorom_device::nes_sorom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_sxrom_device(mconfig, NES_SOROM, "NES Cart SOROM (MMC-1) PCB", tag, owner, clock, "nes_sorom", __FILE__) -{ -} - -nes_sxrom_a_device::nes_sxrom_a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_sxrom_device(mconfig, NES_SXROM_A, "NES Cart SxROM (MMC-1A) PCB", tag, owner, clock, "nes_sxrom_a", __FILE__) -{ -} - -nes_sorom_a_device::nes_sorom_a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_sxrom_device(mconfig, NES_SOROM_A, "NES Cart SOROM (MMC-1A) PCB", tag, owner, clock, "nes_sorom_a", __FILE__) -{ -} - - - -void nes_sxrom_device::device_start() -{ - common_start(); - save_item(NAME(m_latch)); - save_item(NAME(m_count)); - save_item(NAME(m_reg)); - save_item(NAME(m_reg_write_enable)); -} - -void nes_sxrom_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - - m_latch = 0; - m_count = 0; - m_reg[0] = 0x0f; - m_reg[1] = m_reg[2] = m_reg[3] = 0; - m_reg_write_enable = 1; - - set_nt_mirroring(PPU_MIRROR_HORZ); - set_chr(); - set_prg(); -} - -void nes_sorom_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - - m_latch = 0; - m_count = 0; - m_reg[0] = 0x0f; - m_reg[1] = m_reg[2] = m_reg[3] = 0; - m_reg_write_enable = 1; - - set_nt_mirroring(PPU_MIRROR_HORZ); - set_chr(); - set_prg(); -} - -void nes_sorom_a_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - - m_latch = 0; - m_count = 0; - m_reg[0] = 0x0f; - m_reg[1] = m_reg[2] = m_reg[3] = 0; - m_reg_write_enable = 1; - - set_nt_mirroring(PPU_MIRROR_HORZ); - set_chr(); - set_prg(); -} - - - -/*------------------------------------------------- - mapper specific handlers - -------------------------------------------------*/ - - -/*------------------------------------------------- - - SxROM (MMC1 based) board emulation - - iNES: mapper 1 (and 155 for the MMC1A variant which does not - have WRAM disable bit) - - -------------------------------------------------*/ - -TIMER_CALLBACK_MEMBER( nes_sxrom_device::resync_callback ) -{ - m_reg_write_enable = 1; -} - - -void nes_sxrom_device::set_prg() -{ - UINT8 prg_mode, prg_offset; - - prg_mode = m_reg[0] & 0x0c; - /* prg_mode&0x8 determines bank size: 32k (if 0) or 16k (if 1)? when in 16k mode, - prg_mode&0x4 determines which half of the PRG space we can swap: if it is 4, - m_reg[3] sets banks at 0x8000; if it is 0, m_reg[3] sets banks at 0xc000. */ - - prg_offset = m_reg[1] & 0x10; - /* In principle, m_reg[2]&0x10 might affect "extended" banks as well, when chr_mode=1. - However, quoting Disch's docs: When in 4k CHR mode, 0x10 in both $A000 and $C000 *must* be - set to the same value, or else pages will constantly be swapped as graphics render! - Hence, we use only m_reg[1]&0x10 for prg_offset */ - - switch (prg_mode) - { - case 0x00: - case 0x04: -// printf("PRG 32 bank %d \n", (prg_offset + m_reg[3]) >> 1); - prg32((prg_offset + m_reg[3]) >> 1); - break; - case 0x08: -// printf("PRG 16 bank %d (high) \n", prg_offset + m_reg[3]); - prg16_89ab(prg_offset + 0); - prg16_cdef(prg_offset + m_reg[3]); - break; - case 0x0c: -// printf("PRG 16 bank %d (low) \n", prg_offset + m_reg[3]); - prg16_89ab(prg_offset + m_reg[3]); - prg16_cdef(prg_offset + 0x0f); - break; - } -} - -void nes_sxrom_device::set_chr() -{ - UINT8 chr_mode = BIT(m_reg[0], 4); - - if (chr_mode) - { - chr4_0(m_reg[1] & 0x1f, m_chr_source); - chr4_4(m_reg[2] & 0x1f, m_chr_source); - } - else - chr8((m_reg[1] & 0x1f) >> 1, m_chr_source); -} - -// this allows for easier implementation of the NES-EVENT board used for Nintento World Championships -void nes_sxrom_device::update_regs(int reg) -{ - switch (reg) - { - case 0: - switch (m_reg[0] & 0x03) - { - case 0: set_nt_mirroring(PPU_MIRROR_LOW); break; - case 1: set_nt_mirroring(PPU_MIRROR_HIGH); break; - case 2: set_nt_mirroring(PPU_MIRROR_VERT); break; - case 3: set_nt_mirroring(PPU_MIRROR_HORZ); break; - } - set_chr(); - set_prg(); - break; - case 1: - set_chr(); - set_prg(); - break; - case 2: - set_chr(); - break; - case 3: - set_prg(); - break; - } -} - -WRITE8_MEMBER( nes_sxrom_device::write_h ) -{ - LOG_MMC(("sxrom write_h, offset: %04x, data: %02x\n", offset, data)); - - // There is only one latch and shift counter, shared amongst the 4 regs (testcase: Space Shuttle) - - /* here we would need to add an if(cpu_cycles_passed>1) test, and - if requirement is not met simply return without writing anything. - Some games (AD&D Hillsfar, Bill & Ted Excellent Adventure, Cosmic - Wars, Rocket Ranger, Sesame Street 123 and Snow Brothers) rely on - this behavior!! */ - if (!m_reg_write_enable) - return; - else - { - m_reg_write_enable = 0; - machine().scheduler().synchronize(timer_expired_delegate(FUNC(nes_sxrom_device::resync_callback),this)); - } - - if (data & 0x80) - { - m_count = 0; - m_latch = 0; - - // Set reg at 0x8000 to size 16k and lower half swap - needed for Robocop 3, Dynowars - m_reg[0] |= 0x0c; - set_prg(); - return; - } - - if (m_count < 5) - { - if (m_count == 0) m_latch = 0; - m_latch >>= 1; - m_latch |= (data & 0x01) ? 0x10 : 0x00; - m_count++; - } - - if (m_count == 5) - { - m_reg[(offset & 0x6000) >> 13] = m_latch; - update_regs((offset & 0x6000) >> 13); - m_count = 0; - } -} - -WRITE8_MEMBER(nes_sxrom_device::write_m) -{ - UINT8 bank = (m_reg[1] >> 2) & 3; - LOG_MMC(("sxrom write_m, offset: %04x, data: %02x\n", offset, data)); - - if (!BIT(m_reg[3], 4)) // WRAM enabled - { - if (!m_battery.empty()) - m_battery[((bank * 0x2000) + offset) & (m_battery.size() - 1)] = data; - if (!m_prgram.empty()) - m_prgram[((bank * 0x2000) + offset) & (m_prgram.size() - 1)] = data; - } -} - -READ8_MEMBER(nes_sxrom_device::read_m) -{ - UINT8 bank = (m_reg[1] >> 2) & 3; - LOG_MMC(("sxrom read_m, offset: %04x\n", offset)); - - if (!BIT(m_reg[3], 4)) // WRAM enabled - { - if (!m_battery.empty()) - return m_battery[((bank * 0x2000) + offset) & (m_battery.size() - 1)]; - if (!m_prgram.empty()) - return m_prgram[((bank * 0x2000) + offset) & (m_prgram.size() - 1)]; - } - - return m_open_bus; // open bus -} - -// SOROM has two RAM banks, the first is not battery backed up, the second is. -WRITE8_MEMBER(nes_sorom_device::write_m) -{ - UINT8 type = BIT(m_reg[0], 4) ? BIT(m_reg[1], 4) : BIT(m_reg[1], 3); - LOG_MMC(("sorom write_m, offset: %04x, data: %02x\n", offset, data)); - - if (!BIT(m_reg[3], 4)) // WRAM enabled - { - if (type) - m_battery[offset & (m_battery.size() - 1)] = data; - else - m_prgram[offset & (m_prgram.size() - 1)] = data; - } -} - -READ8_MEMBER(nes_sorom_device::read_m) -{ - UINT8 type = BIT(m_reg[0], 4) ? BIT(m_reg[1], 4) : BIT(m_reg[1], 3); - LOG_MMC(("sorom read_m, offset: %04x\n", offset)); - - if (!BIT(m_reg[3], 4)) // WRAM enabled - { - if (type) - return m_battery[offset & (m_battery.size() - 1)]; - else - return m_prgram[offset & (m_prgram.size() - 1)]; - } - - return m_open_bus; // open bus -} - -// MMC1A boards have no wram enable/disable bit -WRITE8_MEMBER(nes_sxrom_a_device::write_m) -{ - UINT8 bank = (m_reg[1] >> 2) & 3; - LOG_MMC(("sxrom_a write_m, offset: %04x, data: %02x\n", offset, data)); - - if (!m_battery.empty()) - m_battery[((bank * 0x2000) + offset) & (m_battery.size() - 1)] = data; - if (!m_prgram.empty()) - m_prgram[((bank * 0x2000) + offset) & (m_prgram.size() - 1)] = data; -} - -READ8_MEMBER(nes_sxrom_a_device::read_m) -{ - UINT8 bank = (m_reg[1] >> 2) & 3; - LOG_MMC(("sxrom_a read_m, offset: %04x\n", offset)); - - if (!m_battery.empty()) - return m_battery[((bank * 0x2000) + offset) & (m_battery.size() - 1)]; - if (!m_prgram.empty()) - return m_prgram[((bank * 0x2000) + offset) & (m_prgram.size() - 1)]; - - return m_open_bus; // open bus -} - -WRITE8_MEMBER(nes_sorom_a_device::write_m) -{ - UINT8 type = BIT(m_reg[0], 4) ? BIT(m_reg[1], 4) : BIT(m_reg[1], 3); - LOG_MMC(("sorom_a write_m, offset: %04x, data: %02x\n", offset, data)); - - if (type) - m_battery[offset & (m_battery.size() - 1)] = data; - else - m_prgram[offset & (m_prgram.size() - 1)] = data; -} - -READ8_MEMBER(nes_sorom_a_device::read_m) -{ - UINT8 type = BIT(m_reg[0], 4) ? BIT(m_reg[1], 4) : BIT(m_reg[1], 3); - LOG_MMC(("sorom_a read_m, offset: %04x\n", offset)); - - if (type) - return m_battery[offset & (m_battery.size() - 1)]; - else - return m_prgram[offset & (m_prgram.size() - 1)]; -} diff --git a/src/devices/bus/nes/mmc1.cpp b/src/devices/bus/nes/mmc1.cpp new file mode 100644 index 00000000000..ff31250ee19 --- /dev/null +++ b/src/devices/bus/nes/mmc1.cpp @@ -0,0 +1,374 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for Nintendo MMC-1 PCBs + + + Here we emulate the Nintendo SxROM / MMC-1 PCBs + older variants without WRAM protect bit + + Known issues on specific mappers: + + * 001 Yoshi flashes in-game. + * 001 Back to the Future have heavily corrupted graphics (since forever). + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "mmc1.h" + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_SXROM = &device_creator; +const device_type NES_SOROM = &device_creator; +const device_type NES_SXROM_A = &device_creator; +const device_type NES_SOROM_A = &device_creator; + + + +nes_sxrom_device::nes_sxrom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +nes_sxrom_device::nes_sxrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_SXROM, "NES Cart SxROM (MMC-1) PCB", tag, owner, clock, "nes_sxrom", __FILE__) +{ +} + +nes_sorom_device::nes_sorom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_sxrom_device(mconfig, NES_SOROM, "NES Cart SOROM (MMC-1) PCB", tag, owner, clock, "nes_sorom", __FILE__) +{ +} + +nes_sxrom_a_device::nes_sxrom_a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_sxrom_device(mconfig, NES_SXROM_A, "NES Cart SxROM (MMC-1A) PCB", tag, owner, clock, "nes_sxrom_a", __FILE__) +{ +} + +nes_sorom_a_device::nes_sorom_a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_sxrom_device(mconfig, NES_SOROM_A, "NES Cart SOROM (MMC-1A) PCB", tag, owner, clock, "nes_sorom_a", __FILE__) +{ +} + + + +void nes_sxrom_device::device_start() +{ + common_start(); + save_item(NAME(m_latch)); + save_item(NAME(m_count)); + save_item(NAME(m_reg)); + save_item(NAME(m_reg_write_enable)); +} + +void nes_sxrom_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + + m_latch = 0; + m_count = 0; + m_reg[0] = 0x0f; + m_reg[1] = m_reg[2] = m_reg[3] = 0; + m_reg_write_enable = 1; + + set_nt_mirroring(PPU_MIRROR_HORZ); + set_chr(); + set_prg(); +} + +void nes_sorom_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + + m_latch = 0; + m_count = 0; + m_reg[0] = 0x0f; + m_reg[1] = m_reg[2] = m_reg[3] = 0; + m_reg_write_enable = 1; + + set_nt_mirroring(PPU_MIRROR_HORZ); + set_chr(); + set_prg(); +} + +void nes_sorom_a_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + + m_latch = 0; + m_count = 0; + m_reg[0] = 0x0f; + m_reg[1] = m_reg[2] = m_reg[3] = 0; + m_reg_write_enable = 1; + + set_nt_mirroring(PPU_MIRROR_HORZ); + set_chr(); + set_prg(); +} + + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + + +/*------------------------------------------------- + + SxROM (MMC1 based) board emulation + + iNES: mapper 1 (and 155 for the MMC1A variant which does not + have WRAM disable bit) + + -------------------------------------------------*/ + +TIMER_CALLBACK_MEMBER( nes_sxrom_device::resync_callback ) +{ + m_reg_write_enable = 1; +} + + +void nes_sxrom_device::set_prg() +{ + UINT8 prg_mode, prg_offset; + + prg_mode = m_reg[0] & 0x0c; + /* prg_mode&0x8 determines bank size: 32k (if 0) or 16k (if 1)? when in 16k mode, + prg_mode&0x4 determines which half of the PRG space we can swap: if it is 4, + m_reg[3] sets banks at 0x8000; if it is 0, m_reg[3] sets banks at 0xc000. */ + + prg_offset = m_reg[1] & 0x10; + /* In principle, m_reg[2]&0x10 might affect "extended" banks as well, when chr_mode=1. + However, quoting Disch's docs: When in 4k CHR mode, 0x10 in both $A000 and $C000 *must* be + set to the same value, or else pages will constantly be swapped as graphics render! + Hence, we use only m_reg[1]&0x10 for prg_offset */ + + switch (prg_mode) + { + case 0x00: + case 0x04: +// printf("PRG 32 bank %d \n", (prg_offset + m_reg[3]) >> 1); + prg32((prg_offset + m_reg[3]) >> 1); + break; + case 0x08: +// printf("PRG 16 bank %d (high) \n", prg_offset + m_reg[3]); + prg16_89ab(prg_offset + 0); + prg16_cdef(prg_offset + m_reg[3]); + break; + case 0x0c: +// printf("PRG 16 bank %d (low) \n", prg_offset + m_reg[3]); + prg16_89ab(prg_offset + m_reg[3]); + prg16_cdef(prg_offset + 0x0f); + break; + } +} + +void nes_sxrom_device::set_chr() +{ + UINT8 chr_mode = BIT(m_reg[0], 4); + + if (chr_mode) + { + chr4_0(m_reg[1] & 0x1f, m_chr_source); + chr4_4(m_reg[2] & 0x1f, m_chr_source); + } + else + chr8((m_reg[1] & 0x1f) >> 1, m_chr_source); +} + +// this allows for easier implementation of the NES-EVENT board used for Nintento World Championships +void nes_sxrom_device::update_regs(int reg) +{ + switch (reg) + { + case 0: + switch (m_reg[0] & 0x03) + { + case 0: set_nt_mirroring(PPU_MIRROR_LOW); break; + case 1: set_nt_mirroring(PPU_MIRROR_HIGH); break; + case 2: set_nt_mirroring(PPU_MIRROR_VERT); break; + case 3: set_nt_mirroring(PPU_MIRROR_HORZ); break; + } + set_chr(); + set_prg(); + break; + case 1: + set_chr(); + set_prg(); + break; + case 2: + set_chr(); + break; + case 3: + set_prg(); + break; + } +} + +WRITE8_MEMBER( nes_sxrom_device::write_h ) +{ + LOG_MMC(("sxrom write_h, offset: %04x, data: %02x\n", offset, data)); + + // There is only one latch and shift counter, shared amongst the 4 regs (testcase: Space Shuttle) + + /* here we would need to add an if(cpu_cycles_passed>1) test, and + if requirement is not met simply return without writing anything. + Some games (AD&D Hillsfar, Bill & Ted Excellent Adventure, Cosmic + Wars, Rocket Ranger, Sesame Street 123 and Snow Brothers) rely on + this behavior!! */ + if (!m_reg_write_enable) + return; + else + { + m_reg_write_enable = 0; + machine().scheduler().synchronize(timer_expired_delegate(FUNC(nes_sxrom_device::resync_callback),this)); + } + + if (data & 0x80) + { + m_count = 0; + m_latch = 0; + + // Set reg at 0x8000 to size 16k and lower half swap - needed for Robocop 3, Dynowars + m_reg[0] |= 0x0c; + set_prg(); + return; + } + + if (m_count < 5) + { + if (m_count == 0) m_latch = 0; + m_latch >>= 1; + m_latch |= (data & 0x01) ? 0x10 : 0x00; + m_count++; + } + + if (m_count == 5) + { + m_reg[(offset & 0x6000) >> 13] = m_latch; + update_regs((offset & 0x6000) >> 13); + m_count = 0; + } +} + +WRITE8_MEMBER(nes_sxrom_device::write_m) +{ + UINT8 bank = (m_reg[1] >> 2) & 3; + LOG_MMC(("sxrom write_m, offset: %04x, data: %02x\n", offset, data)); + + if (!BIT(m_reg[3], 4)) // WRAM enabled + { + if (!m_battery.empty()) + m_battery[((bank * 0x2000) + offset) & (m_battery.size() - 1)] = data; + if (!m_prgram.empty()) + m_prgram[((bank * 0x2000) + offset) & (m_prgram.size() - 1)] = data; + } +} + +READ8_MEMBER(nes_sxrom_device::read_m) +{ + UINT8 bank = (m_reg[1] >> 2) & 3; + LOG_MMC(("sxrom read_m, offset: %04x\n", offset)); + + if (!BIT(m_reg[3], 4)) // WRAM enabled + { + if (!m_battery.empty()) + return m_battery[((bank * 0x2000) + offset) & (m_battery.size() - 1)]; + if (!m_prgram.empty()) + return m_prgram[((bank * 0x2000) + offset) & (m_prgram.size() - 1)]; + } + + return m_open_bus; // open bus +} + +// SOROM has two RAM banks, the first is not battery backed up, the second is. +WRITE8_MEMBER(nes_sorom_device::write_m) +{ + UINT8 type = BIT(m_reg[0], 4) ? BIT(m_reg[1], 4) : BIT(m_reg[1], 3); + LOG_MMC(("sorom write_m, offset: %04x, data: %02x\n", offset, data)); + + if (!BIT(m_reg[3], 4)) // WRAM enabled + { + if (type) + m_battery[offset & (m_battery.size() - 1)] = data; + else + m_prgram[offset & (m_prgram.size() - 1)] = data; + } +} + +READ8_MEMBER(nes_sorom_device::read_m) +{ + UINT8 type = BIT(m_reg[0], 4) ? BIT(m_reg[1], 4) : BIT(m_reg[1], 3); + LOG_MMC(("sorom read_m, offset: %04x\n", offset)); + + if (!BIT(m_reg[3], 4)) // WRAM enabled + { + if (type) + return m_battery[offset & (m_battery.size() - 1)]; + else + return m_prgram[offset & (m_prgram.size() - 1)]; + } + + return m_open_bus; // open bus +} + +// MMC1A boards have no wram enable/disable bit +WRITE8_MEMBER(nes_sxrom_a_device::write_m) +{ + UINT8 bank = (m_reg[1] >> 2) & 3; + LOG_MMC(("sxrom_a write_m, offset: %04x, data: %02x\n", offset, data)); + + if (!m_battery.empty()) + m_battery[((bank * 0x2000) + offset) & (m_battery.size() - 1)] = data; + if (!m_prgram.empty()) + m_prgram[((bank * 0x2000) + offset) & (m_prgram.size() - 1)] = data; +} + +READ8_MEMBER(nes_sxrom_a_device::read_m) +{ + UINT8 bank = (m_reg[1] >> 2) & 3; + LOG_MMC(("sxrom_a read_m, offset: %04x\n", offset)); + + if (!m_battery.empty()) + return m_battery[((bank * 0x2000) + offset) & (m_battery.size() - 1)]; + if (!m_prgram.empty()) + return m_prgram[((bank * 0x2000) + offset) & (m_prgram.size() - 1)]; + + return m_open_bus; // open bus +} + +WRITE8_MEMBER(nes_sorom_a_device::write_m) +{ + UINT8 type = BIT(m_reg[0], 4) ? BIT(m_reg[1], 4) : BIT(m_reg[1], 3); + LOG_MMC(("sorom_a write_m, offset: %04x, data: %02x\n", offset, data)); + + if (type) + m_battery[offset & (m_battery.size() - 1)] = data; + else + m_prgram[offset & (m_prgram.size() - 1)] = data; +} + +READ8_MEMBER(nes_sorom_a_device::read_m) +{ + UINT8 type = BIT(m_reg[0], 4) ? BIT(m_reg[1], 4) : BIT(m_reg[1], 3); + LOG_MMC(("sorom_a read_m, offset: %04x\n", offset)); + + if (type) + return m_battery[offset & (m_battery.size() - 1)]; + else + return m_prgram[offset & (m_prgram.size() - 1)]; +} diff --git a/src/devices/bus/nes/mmc2.c b/src/devices/bus/nes/mmc2.c deleted file mode 100644 index b9ef5402a00..00000000000 --- a/src/devices/bus/nes/mmc2.c +++ /dev/null @@ -1,198 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Fabio Priuli -/*********************************************************************************************************** - - - NES/Famicom cartridge emulation for Nintendo MMC-2 & MMC-4 PCBs - - - Here we emulate the Nintendo PxROM and FxROM PCBs [mapper 9 & 10] - - ***********************************************************************************************************/ - - -#include "emu.h" -#include "mmc2.h" - - -#ifdef NES_PCB_DEBUG -#define VERBOSE 1 -#else -#define VERBOSE 0 -#endif - -#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) - - -//------------------------------------------------- -// constructor -//------------------------------------------------- - -const device_type NES_PXROM = &device_creator; -const device_type NES_FXROM = &device_creator; - - -nes_pxrom_device::nes_pxrom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) - : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source) -{ -} - -nes_pxrom_device::nes_pxrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_PXROM, "NES Cart PxROM (MMC-2) PCB", tag, owner, clock, "nes_pxrom", __FILE__) -{ -} - -nes_fxrom_device::nes_fxrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_pxrom_device(mconfig, NES_FXROM, "NES Cart FxROM (MMC-4) PCB", tag, owner, clock, "nes_fxrom", __FILE__) -{ -} - - - - -void nes_pxrom_device::device_start() -{ - common_start(); - save_item(NAME(m_latch1)); - save_item(NAME(m_latch2)); - save_item(NAME(m_reg)); -} - -void nes_pxrom_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg8_89(0); - prg8_ab((m_prg_chunks << 1) - 3); - prg8_cd((m_prg_chunks << 1) - 2); - prg8_ef((m_prg_chunks << 1) - 1); - chr8(0, m_chr_source); - - m_reg[0] = m_reg[2] = 0; - m_reg[1] = m_reg[3] = 0; - m_latch1 = m_latch2 = 0xfe; -} - -void nes_fxrom_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(0); - prg16_cdef(m_prg_chunks - 1); - chr8(0, m_chr_source); - - m_reg[0] = m_reg[2] = 0; - m_reg[1] = m_reg[3] = 0; - m_latch1 = m_latch2 = 0xfe; -} - - - - -/*------------------------------------------------- - mapper specific handlers - -------------------------------------------------*/ - -/*------------------------------------------------- - - PxROM (MMC2 based) board emulation - - Games: Punch Out!!, Mike Tyson's Punch Out!! - - iNES: mapper 9 - - In MESS: Supported - - -------------------------------------------------*/ - -void nes_pxrom_device::ppu_latch(offs_t offset) -{ - if ((offset & 0x3ff0) == 0x0fd0) - { - LOG_MMC(("mmc2 vrom latch switch (bank 0 low): %02x\n", m_reg[0])); - m_latch1 = 0xfd; - chr4_0(m_reg[0], CHRROM); - } - else if ((offset & 0x3ff0) == 0x0fe0) - { - LOG_MMC(("mmc2 vrom latch switch (bank 0 high): %02x\n", m_reg[1])); - m_latch1 = 0xfe; - chr4_0(m_reg[1], CHRROM); - } - else if ((offset & 0x3ff0) == 0x1fd0) - { - LOG_MMC(("mmc2 vrom latch switch (bank 1 low): %02x\n", m_reg[2])); - m_latch2 = 0xfd; - chr4_4(m_reg[2], CHRROM); - } - else if ((offset & 0x3ff0) == 0x1fe0) - { - LOG_MMC(("mmc2 vrom latch switch (bank 0 high): %02x\n", m_reg[3])); - m_latch2 = 0xfe; - chr4_4(m_reg[3], CHRROM); - } -} - -WRITE8_MEMBER( nes_pxrom_device::pxrom_write ) -{ - LOG_MMC(("pxrom write_h, offset: %04x, data: %02x\n", offset, data)); - switch (offset & 0x7000) - { - case 0x2000: - prg8_89(data); - break; - case 0x3000: - m_reg[0] = data; - if (m_latch1 == 0xfd) - chr4_0(m_reg[0], CHRROM); - break; - case 0x4000: - m_reg[1] = data; - if (m_latch1 == 0xfe) - chr4_0(m_reg[1], CHRROM); - break; - case 0x5000: - m_reg[2] = data; - if (m_latch2 == 0xfd) - chr4_4(m_reg[2], CHRROM); - break; - case 0x6000: - m_reg[3] = data; - if (m_latch2 == 0xfe) - chr4_4(m_reg[3], CHRROM); - break; - case 0x7000: - set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); - break; - default: - LOG_MMC(("MMC2 uncaught w: %04x:%02x\n", offset, data)); - break; - } -} - -/*------------------------------------------------- - - FxROM (MMC4 based) board emulation - - Games: Famicom Wars, Fire Emblem, Fire Emblem Gaiden - - This is a small hardware variants of MMC2 (additional - prg bankswitch line) - - iNES: mapper 10 - - In MESS: Supported - - -------------------------------------------------*/ - -WRITE8_MEMBER( nes_fxrom_device::write_h ) -{ - LOG_MMC(("fxrom write_h, offset: %04x, data: %02x\n", offset, data)); - switch (offset & 0x7000) - { - case 0x2000: - prg16_89ab(data); - break; - default: - pxrom_write(space, offset, data, mem_mask); - break; - } -} diff --git a/src/devices/bus/nes/mmc2.cpp b/src/devices/bus/nes/mmc2.cpp new file mode 100644 index 00000000000..b9ef5402a00 --- /dev/null +++ b/src/devices/bus/nes/mmc2.cpp @@ -0,0 +1,198 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for Nintendo MMC-2 & MMC-4 PCBs + + + Here we emulate the Nintendo PxROM and FxROM PCBs [mapper 9 & 10] + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "mmc2.h" + + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_PXROM = &device_creator; +const device_type NES_FXROM = &device_creator; + + +nes_pxrom_device::nes_pxrom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +nes_pxrom_device::nes_pxrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_PXROM, "NES Cart PxROM (MMC-2) PCB", tag, owner, clock, "nes_pxrom", __FILE__) +{ +} + +nes_fxrom_device::nes_fxrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_pxrom_device(mconfig, NES_FXROM, "NES Cart FxROM (MMC-4) PCB", tag, owner, clock, "nes_fxrom", __FILE__) +{ +} + + + + +void nes_pxrom_device::device_start() +{ + common_start(); + save_item(NAME(m_latch1)); + save_item(NAME(m_latch2)); + save_item(NAME(m_reg)); +} + +void nes_pxrom_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg8_89(0); + prg8_ab((m_prg_chunks << 1) - 3); + prg8_cd((m_prg_chunks << 1) - 2); + prg8_ef((m_prg_chunks << 1) - 1); + chr8(0, m_chr_source); + + m_reg[0] = m_reg[2] = 0; + m_reg[1] = m_reg[3] = 0; + m_latch1 = m_latch2 = 0xfe; +} + +void nes_fxrom_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + + m_reg[0] = m_reg[2] = 0; + m_reg[1] = m_reg[3] = 0; + m_latch1 = m_latch2 = 0xfe; +} + + + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + PxROM (MMC2 based) board emulation + + Games: Punch Out!!, Mike Tyson's Punch Out!! + + iNES: mapper 9 + + In MESS: Supported + + -------------------------------------------------*/ + +void nes_pxrom_device::ppu_latch(offs_t offset) +{ + if ((offset & 0x3ff0) == 0x0fd0) + { + LOG_MMC(("mmc2 vrom latch switch (bank 0 low): %02x\n", m_reg[0])); + m_latch1 = 0xfd; + chr4_0(m_reg[0], CHRROM); + } + else if ((offset & 0x3ff0) == 0x0fe0) + { + LOG_MMC(("mmc2 vrom latch switch (bank 0 high): %02x\n", m_reg[1])); + m_latch1 = 0xfe; + chr4_0(m_reg[1], CHRROM); + } + else if ((offset & 0x3ff0) == 0x1fd0) + { + LOG_MMC(("mmc2 vrom latch switch (bank 1 low): %02x\n", m_reg[2])); + m_latch2 = 0xfd; + chr4_4(m_reg[2], CHRROM); + } + else if ((offset & 0x3ff0) == 0x1fe0) + { + LOG_MMC(("mmc2 vrom latch switch (bank 0 high): %02x\n", m_reg[3])); + m_latch2 = 0xfe; + chr4_4(m_reg[3], CHRROM); + } +} + +WRITE8_MEMBER( nes_pxrom_device::pxrom_write ) +{ + LOG_MMC(("pxrom write_h, offset: %04x, data: %02x\n", offset, data)); + switch (offset & 0x7000) + { + case 0x2000: + prg8_89(data); + break; + case 0x3000: + m_reg[0] = data; + if (m_latch1 == 0xfd) + chr4_0(m_reg[0], CHRROM); + break; + case 0x4000: + m_reg[1] = data; + if (m_latch1 == 0xfe) + chr4_0(m_reg[1], CHRROM); + break; + case 0x5000: + m_reg[2] = data; + if (m_latch2 == 0xfd) + chr4_4(m_reg[2], CHRROM); + break; + case 0x6000: + m_reg[3] = data; + if (m_latch2 == 0xfe) + chr4_4(m_reg[3], CHRROM); + break; + case 0x7000: + set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + break; + default: + LOG_MMC(("MMC2 uncaught w: %04x:%02x\n", offset, data)); + break; + } +} + +/*------------------------------------------------- + + FxROM (MMC4 based) board emulation + + Games: Famicom Wars, Fire Emblem, Fire Emblem Gaiden + + This is a small hardware variants of MMC2 (additional + prg bankswitch line) + + iNES: mapper 10 + + In MESS: Supported + + -------------------------------------------------*/ + +WRITE8_MEMBER( nes_fxrom_device::write_h ) +{ + LOG_MMC(("fxrom write_h, offset: %04x, data: %02x\n", offset, data)); + switch (offset & 0x7000) + { + case 0x2000: + prg16_89ab(data); + break; + default: + pxrom_write(space, offset, data, mem_mask); + break; + } +} diff --git a/src/devices/bus/nes/mmc3.c b/src/devices/bus/nes/mmc3.c deleted file mode 100644 index 8e81fac286f..00000000000 --- a/src/devices/bus/nes/mmc3.c +++ /dev/null @@ -1,560 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Fabio Priuli -/*********************************************************************************************************** - - - NES/Famicom cartridge emulation for Nintendo MMC-3 & MMC-6 PCBs - - - Here we emulate the following PCBs - - * Nintendo TxROM, aka MMC-3 [mapper 4] - * Nintendo HKROM, aka MMC-6 [mapper 4] - * Nintendo TxSROM [mapper 118] - * Nintendo TQROM [mapper 119] - * Nintendo NES-QJ [mapper 47] - * Nintendo PAL-ZZ [mapper 37] - - - Known issues on specific mappers: - - * 004 Mendel Palace has never worked properly - * 004 Ninja Gaiden 2 has flashing bg graphics in the second level - * 119 Pin Bot has glitches when the ball is in the upper half of the screen - - ***********************************************************************************************************/ - - -#include "emu.h" -#include "mmc3.h" - -#include "cpu/m6502/m6502.h" -#include "video/ppu2c0x.h" // this has to be included so that IRQ functions can access PPU_BOTTOM_VISIBLE_SCANLINE - - -#ifdef NES_PCB_DEBUG -#define VERBOSE 1 -#else -#define VERBOSE 0 -#endif - -#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) - - -//------------------------------------------------- -// constructor -//------------------------------------------------- - -const device_type NES_TXROM = &device_creator; -const device_type NES_HKROM = &device_creator; -const device_type NES_TXSROM = &device_creator; -const device_type NES_TQROM = &device_creator; -const device_type NES_QJ_PCB = &device_creator; -const device_type NES_ZZ_PCB = &device_creator; - - -nes_txrom_device::nes_txrom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) - : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source) -{ -} - -nes_txrom_device::nes_txrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_TXROM, "NES Cart TxROM (MMC-3) PCB", tag, owner, clock, "nes_txrom", __FILE__) -{ -} - -nes_hkrom_device::nes_hkrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_txrom_device(mconfig, NES_HKROM, "NES Cart HKROM (MMC-6) PCB", tag, owner, clock, "nes_hkrom", __FILE__) -{ -} - -nes_txsrom_device::nes_txsrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_txrom_device(mconfig, NES_TXSROM, "NES Cart TxSROM PCB", tag, owner, clock, "nes_txsrom", __FILE__) -{ -} - -nes_tqrom_device::nes_tqrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_txrom_device(mconfig, NES_TQROM, "NES Cart TQROM PCB", tag, owner, clock, "nes_tqrom", __FILE__) -{ -} - -nes_qj_device::nes_qj_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_txrom_device(mconfig, NES_QJ_PCB, "NES Cart NES-QJ PCB", tag, owner, clock, "nes_qj", __FILE__) -{ -} - -nes_zz_device::nes_zz_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_txrom_device(mconfig, NES_ZZ_PCB, "NES Cart PAL-ZZ PCB", tag, owner, clock, "nes_zz", __FILE__) -{ -} - - - -void nes_txrom_device::mmc3_start() -{ - common_start(); - save_item(NAME(m_mmc_prg_bank)); - save_item(NAME(m_mmc_vrom_bank)); - save_item(NAME(m_latch)); - save_item(NAME(m_wram_protect)); - save_item(NAME(m_prg_base)); - save_item(NAME(m_prg_mask)); - save_item(NAME(m_chr_base)); - save_item(NAME(m_chr_mask)); - save_item(NAME(m_alt_irq)); - save_item(NAME(m_irq_enable)); - save_item(NAME(m_irq_count)); - save_item(NAME(m_irq_count_latch)); - save_item(NAME(m_irq_clear)); -} - -void nes_txrom_device::mmc3_common_initialize( int prg_mask, int chr_mask, int irq_type ) -{ - m_mmc_prg_bank[0] = m_mmc_prg_bank[2] = 0xffe; // m_mmc_prg_bank[2] & m_mmc_prg_bank[3] remain always the same in most MMC3 variants - m_mmc_prg_bank[1] = m_mmc_prg_bank[3] = 0xfff; // but some pirate clone mappers change them after writing certain registers - memset(m_mmc_vrom_bank, 0, sizeof(m_mmc_vrom_bank)); - - m_latch = 0; - m_wram_protect = 0x80; - - m_prg_base = m_chr_base = 0; - m_prg_mask = prg_mask; - m_chr_mask = chr_mask; - - m_alt_irq = irq_type; // later MMC3 boards seem to use MMC6-type IRQ... more investigations are in progress at NESDev... - m_irq_enable = 0; - m_irq_count = m_irq_count_latch = 0; - m_irq_clear = 0; - - set_prg(m_prg_base, m_prg_mask); - set_chr(m_chr_source, m_chr_base, m_chr_mask); -} - - -void nes_txrom_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - // 4-screen mirroring is taken care in pcb_start, if needed... - mmc3_common_initialize(0xff, 0xff, 0); -} - - -void nes_hkrom_device::device_start() -{ - mmc3_start(); - save_item(NAME(m_mmc6_reg)); - save_item(NAME(m_wram_enable)); - - save_item(NAME(m_mmc6_ram)); - - m_mapper_sram_size = 0x400; - m_mapper_sram = m_mmc6_ram; -} - -void nes_hkrom_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - mmc3_common_initialize(0xff, 0xff, 1); - m_mmc6_reg = 0xf0; - m_wram_enable = 0; -} - - -void nes_qj_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - mmc3_common_initialize(0x0f, 0x7f, 0); -} - - -void nes_zz_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - mmc3_common_initialize(0x07, 0x7f, 0); -} - - -/*------------------------------------------------- - mapper specific handlers - -------------------------------------------------*/ - -/*------------------------------------------------- - - TxROM (MMC3 based) board emulation - - iNES: mapper 4 - - -------------------------------------------------*/ - -/* Here, IRQ counter decrements every scanline. */ -void nes_txrom_device::hblank_irq(int scanline, int vblank, int blanked) -{ - if (scanline < PPU_BOTTOM_VISIBLE_SCANLINE) - { - int prior_count = m_irq_count; - if ((m_irq_count == 0) || m_irq_clear) - m_irq_count = m_irq_count_latch; - else - m_irq_count--; - - if (m_irq_enable && !blanked && (m_irq_count == 0) && (prior_count || m_irq_clear /*|| !m_mmc3_alt_irq*/)) // according to blargg the latter should be present as well, but it breaks Rampart and Joe & Mac US: they probably use the alt irq! - { - LOG_MMC(("irq fired, scanline: %d (MAME %d, beam pos: %d)\n", scanline, - machine().first_screen()->vpos(), machine().first_screen()->hpos())); - m_maincpu->set_input_line(M6502_IRQ_LINE, ASSERT_LINE); - } - } - m_irq_clear = 0; -} - -// base MMC3 simply calls prg8_x -void nes_txrom_device::prg_cb( int start, int bank ) -{ - prg8_x(start, bank); -} - -// base MMC3 simply calls chr1_x -void nes_txrom_device::chr_cb( int start, int bank, int source ) -{ - chr1_x(start, bank, source); -} - - -void nes_txrom_device::set_prg( int prg_base, int prg_mask ) -{ - UINT8 prg_flip = (m_latch & 0x40) ? 2 : 0; - - prg_cb(0, prg_base | (m_mmc_prg_bank[0 ^ prg_flip] & prg_mask)); - prg_cb(1, prg_base | (m_mmc_prg_bank[1] & prg_mask)); - prg_cb(2, prg_base | (m_mmc_prg_bank[2 ^ prg_flip] & prg_mask)); - prg_cb(3, prg_base | (m_mmc_prg_bank[3] & prg_mask)); -} - -void nes_txrom_device::set_chr( UINT8 chr, int chr_base, int chr_mask ) -{ - UINT8 chr_page = (m_latch & 0x80) >> 5; - - chr_cb(chr_page ^ 0, chr_base | ((m_mmc_vrom_bank[0] & ~0x01) & chr_mask), chr); - chr_cb(chr_page ^ 1, chr_base | ((m_mmc_vrom_bank[0] | 0x01) & chr_mask), chr); - chr_cb(chr_page ^ 2, chr_base | ((m_mmc_vrom_bank[1] & ~0x01) & chr_mask), chr); - chr_cb(chr_page ^ 3, chr_base | ((m_mmc_vrom_bank[1] | 0x01) & chr_mask), chr); - chr_cb(chr_page ^ 4, chr_base | (m_mmc_vrom_bank[2] & chr_mask), chr); - chr_cb(chr_page ^ 5, chr_base | (m_mmc_vrom_bank[3] & chr_mask), chr); - chr_cb(chr_page ^ 6, chr_base | (m_mmc_vrom_bank[4] & chr_mask), chr); - chr_cb(chr_page ^ 7, chr_base | (m_mmc_vrom_bank[5] & chr_mask), chr); -} - -WRITE8_MEMBER(nes_txrom_device::txrom_write) -{ - UINT8 mmc_helper, cmd; - - LOG_MMC(("txrom_write, offset: %04x, data: %02x\n", offset, data)); - - switch (offset & 0x6001) - { - case 0x0000: - mmc_helper = m_latch ^ data; - m_latch = data; - - // Has PRG Mode changed? - if (mmc_helper & 0x40) - set_prg(m_prg_base, m_prg_mask); - - // Has CHR Mode changed? - if (mmc_helper & 0x80) - set_chr(m_chr_source, m_chr_base, m_chr_mask); - break; - - case 0x0001: - cmd = m_latch & 0x07; - switch (cmd) - { - case 0: case 1: // these do not need to be separated: we take care of them in set_chr! - case 2: case 3: case 4: case 5: - m_mmc_vrom_bank[cmd] = data; - set_chr(m_chr_source, m_chr_base, m_chr_mask); - break; - case 6: - case 7: - m_mmc_prg_bank[cmd - 6] = data; - set_prg(m_prg_base, m_prg_mask); - break; - } - break; - - case 0x2000: - set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); - break; - - case 0x2001: - m_wram_protect = data; - break; - - case 0x4000: - m_irq_count_latch = data; - break; - - case 0x4001: - m_irq_count = 0; - break; - - case 0x6000: - m_irq_enable = 0; - m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); - break; - - case 0x6001: - m_irq_enable = 1; - break; - - default: - logerror("txrom_write uncaught: %04x value: %02x\n", offset + 0x8000, data); - break; - } -} - -WRITE8_MEMBER(nes_txrom_device::write_m) -{ - LOG_MMC(("txrom write_m, offset: %04x, data: %02x\n", offset, data)); - - if (BIT(m_wram_protect, 7) && !BIT(m_wram_protect, 6)) - { - if (!m_battery.empty()) - m_battery[offset & (m_battery.size() - 1)] = data; - if (!m_prgram.empty()) - m_prgram[offset & (m_prgram.size() - 1)] = data; - } -} - -READ8_MEMBER(nes_txrom_device::read_m) -{ - LOG_MMC(("txrom read_m, offset: %04x\n", offset)); - - if (BIT(m_wram_protect, 7)) - { - if (!m_battery.empty()) - return m_battery[offset & (m_battery.size() - 1)]; - if (!m_prgram.empty()) - return m_prgram[offset & (m_prgram.size() - 1)]; - } - - return m_open_bus; // open bus -} - - -/*------------------------------------------------- - - HKROM (MMC6 based) board emulation - - iNES: mapper 4 - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_hkrom_device::write_m) -{ - UINT8 write_hi, write_lo; - LOG_MMC(("hkrom write_m, offset: %04x, data: %02x\n", offset, data)); - - if (offset < 0x1000) - return; - - // banks can be written only if both read & write is enabled! - write_hi = ((m_mmc6_reg & 0xc0) == 0xc0); - write_lo = ((m_mmc6_reg & 0x30) == 0x30); - - if (BIT(offset, 9) && write_hi) // access to upper half of 1k - m_mmc6_ram[offset & 0x3ff] = data; - - if (!BIT(offset, 9) && write_lo) // access to lower half of 1k - m_mmc6_ram[offset & 0x3ff] = data; -} - -READ8_MEMBER(nes_hkrom_device::read_m) -{ - LOG_MMC(("hkrom read_m, offset: %04x\n", offset)); - - if (offset < 0x1000) - return m_open_bus; // open bus - - if (!(m_mmc6_reg & 0xa0)) - return m_open_bus; // open bus - - if (BIT(offset, 9) && BIT(m_mmc6_reg, 7)) // access to upper half of 1k when upper read is enabled - return m_mmc6_ram[offset & 0x3ff]; - - if (!BIT(offset, 9) && BIT(m_mmc6_reg, 5)) // access to lower half of 1k when lower read is enabled - return m_mmc6_ram[offset & 0x3ff]; - - // If only one bank is enabled for reading, the other reads back as zero - return 0x00; -} - -WRITE8_MEMBER(nes_hkrom_device::write_h) -{ - UINT8 mmc6_helper; - LOG_MMC(("hkrom write_h, offset: %04x, data: %02x\n", offset, data)); - - switch (offset & 0x6001) - { - case 0x0000: - mmc6_helper = m_latch ^ data; - m_latch = data; - - if (!m_wram_enable && BIT(data, 5)) // if WRAM is disabled and has to be enabled, write - m_wram_enable = BIT(data, 5); // (once WRAM has been enabled, it cannot be disabled without resetting the game) - - // Has PRG Mode changed? - if (BIT(mmc6_helper, 6)) - set_prg(m_prg_base, m_prg_mask); - - // Has CHR Mode changed? - if (BIT(mmc6_helper, 7)) - set_chr(m_chr_source, m_chr_base, m_chr_mask); - break; - - case 0x2001: - if (m_wram_enable) - m_mmc6_reg = data; - break; - - case 0x4001: - m_irq_count = 0; - m_irq_clear = 1; - break; - - default: - txrom_write(space, offset, data, mem_mask); - break; - } -} - -/*------------------------------------------------- - - TxSROM (MMC3 based) board emulation - - Games: Armadillo, Play Action Football, Pro Hockey, RPG - Jinsei Game, Y's 3 - - iNES: mapper 118 - - In MESS: Supported. It also uses mmc3_irq. - - -------------------------------------------------*/ - -void nes_txsrom_device::set_mirror() -{ - if (m_latch & 0x80) - { - set_nt_page(0, CIRAM, BIT(m_mmc_vrom_bank[2],7), 1); - set_nt_page(1, CIRAM, BIT(m_mmc_vrom_bank[3],7), 1); - set_nt_page(2, CIRAM, BIT(m_mmc_vrom_bank[4],7), 1); - set_nt_page(3, CIRAM, BIT(m_mmc_vrom_bank[5],7), 1); - } - else - { - set_nt_page(0, CIRAM, BIT(m_mmc_vrom_bank[0],7), 1); - set_nt_page(1, CIRAM, BIT(m_mmc_vrom_bank[0],7), 1); - set_nt_page(2, CIRAM, BIT(m_mmc_vrom_bank[1],7), 1); - set_nt_page(3, CIRAM, BIT(m_mmc_vrom_bank[1],7), 1); - } -} - -void nes_txsrom_device::chr_cb( int start, int bank, int source ) -{ - set_mirror(); // we could probably update only for one (e.g. the first) call, to slightly optimize the code - chr1_x(start, bank, source); -} - -WRITE8_MEMBER(nes_txsrom_device::write_h) -{ - LOG_MMC(("txsrom write_h, offset: %04x, data: %02x\n", offset, data)); - - switch (offset & 0x6001) - { - case 0x2000: - break; - - default: - txrom_write(space, offset, data, mem_mask); - break; - } -} - -/*------------------------------------------------- - - TQROM (MMC3 based) board emulation - - Games: Pin Bot, High Speed - - iNES: mapper 119 - - In MESS: Supported. It also uses mmc3_irq. - - -------------------------------------------------*/ - -void nes_tqrom_device::set_chr( UINT8 chr, int chr_base, int chr_mask ) -{ - UINT8 chr_page = (m_latch & 0x80) >> 5; - UINT8 src[6], mask[6]; - - // TQROM ignores the source, base and mask set by the MMC3 and determines them based on vrom bank bits - for (int i = 0; i < 6; i++) - { - src[i] = (m_mmc_vrom_bank[i] & 0x40) ? CHRRAM : CHRROM; - mask[i] = (m_mmc_vrom_bank[i] & 0x40) ? 0x07 : 0x3f; - } - - chr1_x(chr_page ^ 0, ((m_mmc_vrom_bank[0] & ~0x01) & mask[0]), src[0]); - chr1_x(chr_page ^ 1, ((m_mmc_vrom_bank[0] | 0x01) & mask[0]), src[0]); - chr1_x(chr_page ^ 2, ((m_mmc_vrom_bank[1] & ~0x01) & mask[1]), src[1]); - chr1_x(chr_page ^ 3, ((m_mmc_vrom_bank[1] | 0x01) & mask[1]), src[1]); - chr1_x(chr_page ^ 4, (m_mmc_vrom_bank[2] & mask[2]), src[2]); - chr1_x(chr_page ^ 5, (m_mmc_vrom_bank[3] & mask[3]), src[3]); - chr1_x(chr_page ^ 6, (m_mmc_vrom_bank[4] & mask[4]), src[4]); - chr1_x(chr_page ^ 7, (m_mmc_vrom_bank[5] & mask[5]), src[5]); -} - - -/*------------------------------------------------- - - NES-QJ board (MMC3 variant for US 2-in-1 Nintendo cart - Super Spike V'Ball + Nintendo World Cup) - - iNES: mapper 47 - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_qj_device::write_m) -{ - LOG_MMC(("qj write_m, offset: %04x, data: %02x\n", offset, data)); - - m_prg_base = BIT(data, 0) << 4; - m_prg_mask = 0x0f; - m_chr_base = BIT(data, 0) << 7; - m_chr_mask = 0x7f; - set_prg(m_prg_base, m_prg_mask); - set_chr(m_chr_source, m_chr_base, m_chr_mask); -} - - -/*------------------------------------------------- - - PAL-ZZ board (MMC3 variant for European 3-in-1 Nintendo cart - Super Mario Bros. + Tetris + Nintendo World Cup) - - iNES: mapper 37 - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_zz_device::write_m) -{ - UINT8 mmc_helper = data & 0x07; - LOG_MMC(("zz write_m, offset: %04x, data: %02x\n", offset, data)); - - m_prg_base = (BIT(mmc_helper, 2) << 4) | (((mmc_helper & 0x03) == 0x03) ? 0x08 : 0); - m_prg_mask = (mmc_helper << 1) | 0x07; - m_chr_base = BIT(mmc_helper, 2) << 7; - m_chr_mask = 0x7f; - set_prg(m_prg_base, m_prg_mask); - set_chr(m_chr_source, m_chr_base, m_chr_mask); -} diff --git a/src/devices/bus/nes/mmc3.cpp b/src/devices/bus/nes/mmc3.cpp new file mode 100644 index 00000000000..8e81fac286f --- /dev/null +++ b/src/devices/bus/nes/mmc3.cpp @@ -0,0 +1,560 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for Nintendo MMC-3 & MMC-6 PCBs + + + Here we emulate the following PCBs + + * Nintendo TxROM, aka MMC-3 [mapper 4] + * Nintendo HKROM, aka MMC-6 [mapper 4] + * Nintendo TxSROM [mapper 118] + * Nintendo TQROM [mapper 119] + * Nintendo NES-QJ [mapper 47] + * Nintendo PAL-ZZ [mapper 37] + + + Known issues on specific mappers: + + * 004 Mendel Palace has never worked properly + * 004 Ninja Gaiden 2 has flashing bg graphics in the second level + * 119 Pin Bot has glitches when the ball is in the upper half of the screen + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "mmc3.h" + +#include "cpu/m6502/m6502.h" +#include "video/ppu2c0x.h" // this has to be included so that IRQ functions can access PPU_BOTTOM_VISIBLE_SCANLINE + + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_TXROM = &device_creator; +const device_type NES_HKROM = &device_creator; +const device_type NES_TXSROM = &device_creator; +const device_type NES_TQROM = &device_creator; +const device_type NES_QJ_PCB = &device_creator; +const device_type NES_ZZ_PCB = &device_creator; + + +nes_txrom_device::nes_txrom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +nes_txrom_device::nes_txrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_TXROM, "NES Cart TxROM (MMC-3) PCB", tag, owner, clock, "nes_txrom", __FILE__) +{ +} + +nes_hkrom_device::nes_hkrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_HKROM, "NES Cart HKROM (MMC-6) PCB", tag, owner, clock, "nes_hkrom", __FILE__) +{ +} + +nes_txsrom_device::nes_txsrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_TXSROM, "NES Cart TxSROM PCB", tag, owner, clock, "nes_txsrom", __FILE__) +{ +} + +nes_tqrom_device::nes_tqrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_TQROM, "NES Cart TQROM PCB", tag, owner, clock, "nes_tqrom", __FILE__) +{ +} + +nes_qj_device::nes_qj_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_QJ_PCB, "NES Cart NES-QJ PCB", tag, owner, clock, "nes_qj", __FILE__) +{ +} + +nes_zz_device::nes_zz_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_ZZ_PCB, "NES Cart PAL-ZZ PCB", tag, owner, clock, "nes_zz", __FILE__) +{ +} + + + +void nes_txrom_device::mmc3_start() +{ + common_start(); + save_item(NAME(m_mmc_prg_bank)); + save_item(NAME(m_mmc_vrom_bank)); + save_item(NAME(m_latch)); + save_item(NAME(m_wram_protect)); + save_item(NAME(m_prg_base)); + save_item(NAME(m_prg_mask)); + save_item(NAME(m_chr_base)); + save_item(NAME(m_chr_mask)); + save_item(NAME(m_alt_irq)); + save_item(NAME(m_irq_enable)); + save_item(NAME(m_irq_count)); + save_item(NAME(m_irq_count_latch)); + save_item(NAME(m_irq_clear)); +} + +void nes_txrom_device::mmc3_common_initialize( int prg_mask, int chr_mask, int irq_type ) +{ + m_mmc_prg_bank[0] = m_mmc_prg_bank[2] = 0xffe; // m_mmc_prg_bank[2] & m_mmc_prg_bank[3] remain always the same in most MMC3 variants + m_mmc_prg_bank[1] = m_mmc_prg_bank[3] = 0xfff; // but some pirate clone mappers change them after writing certain registers + memset(m_mmc_vrom_bank, 0, sizeof(m_mmc_vrom_bank)); + + m_latch = 0; + m_wram_protect = 0x80; + + m_prg_base = m_chr_base = 0; + m_prg_mask = prg_mask; + m_chr_mask = chr_mask; + + m_alt_irq = irq_type; // later MMC3 boards seem to use MMC6-type IRQ... more investigations are in progress at NESDev... + m_irq_enable = 0; + m_irq_count = m_irq_count_latch = 0; + m_irq_clear = 0; + + set_prg(m_prg_base, m_prg_mask); + set_chr(m_chr_source, m_chr_base, m_chr_mask); +} + + +void nes_txrom_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + // 4-screen mirroring is taken care in pcb_start, if needed... + mmc3_common_initialize(0xff, 0xff, 0); +} + + +void nes_hkrom_device::device_start() +{ + mmc3_start(); + save_item(NAME(m_mmc6_reg)); + save_item(NAME(m_wram_enable)); + + save_item(NAME(m_mmc6_ram)); + + m_mapper_sram_size = 0x400; + m_mapper_sram = m_mmc6_ram; +} + +void nes_hkrom_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + mmc3_common_initialize(0xff, 0xff, 1); + m_mmc6_reg = 0xf0; + m_wram_enable = 0; +} + + +void nes_qj_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + mmc3_common_initialize(0x0f, 0x7f, 0); +} + + +void nes_zz_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + mmc3_common_initialize(0x07, 0x7f, 0); +} + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + TxROM (MMC3 based) board emulation + + iNES: mapper 4 + + -------------------------------------------------*/ + +/* Here, IRQ counter decrements every scanline. */ +void nes_txrom_device::hblank_irq(int scanline, int vblank, int blanked) +{ + if (scanline < PPU_BOTTOM_VISIBLE_SCANLINE) + { + int prior_count = m_irq_count; + if ((m_irq_count == 0) || m_irq_clear) + m_irq_count = m_irq_count_latch; + else + m_irq_count--; + + if (m_irq_enable && !blanked && (m_irq_count == 0) && (prior_count || m_irq_clear /*|| !m_mmc3_alt_irq*/)) // according to blargg the latter should be present as well, but it breaks Rampart and Joe & Mac US: they probably use the alt irq! + { + LOG_MMC(("irq fired, scanline: %d (MAME %d, beam pos: %d)\n", scanline, + machine().first_screen()->vpos(), machine().first_screen()->hpos())); + m_maincpu->set_input_line(M6502_IRQ_LINE, ASSERT_LINE); + } + } + m_irq_clear = 0; +} + +// base MMC3 simply calls prg8_x +void nes_txrom_device::prg_cb( int start, int bank ) +{ + prg8_x(start, bank); +} + +// base MMC3 simply calls chr1_x +void nes_txrom_device::chr_cb( int start, int bank, int source ) +{ + chr1_x(start, bank, source); +} + + +void nes_txrom_device::set_prg( int prg_base, int prg_mask ) +{ + UINT8 prg_flip = (m_latch & 0x40) ? 2 : 0; + + prg_cb(0, prg_base | (m_mmc_prg_bank[0 ^ prg_flip] & prg_mask)); + prg_cb(1, prg_base | (m_mmc_prg_bank[1] & prg_mask)); + prg_cb(2, prg_base | (m_mmc_prg_bank[2 ^ prg_flip] & prg_mask)); + prg_cb(3, prg_base | (m_mmc_prg_bank[3] & prg_mask)); +} + +void nes_txrom_device::set_chr( UINT8 chr, int chr_base, int chr_mask ) +{ + UINT8 chr_page = (m_latch & 0x80) >> 5; + + chr_cb(chr_page ^ 0, chr_base | ((m_mmc_vrom_bank[0] & ~0x01) & chr_mask), chr); + chr_cb(chr_page ^ 1, chr_base | ((m_mmc_vrom_bank[0] | 0x01) & chr_mask), chr); + chr_cb(chr_page ^ 2, chr_base | ((m_mmc_vrom_bank[1] & ~0x01) & chr_mask), chr); + chr_cb(chr_page ^ 3, chr_base | ((m_mmc_vrom_bank[1] | 0x01) & chr_mask), chr); + chr_cb(chr_page ^ 4, chr_base | (m_mmc_vrom_bank[2] & chr_mask), chr); + chr_cb(chr_page ^ 5, chr_base | (m_mmc_vrom_bank[3] & chr_mask), chr); + chr_cb(chr_page ^ 6, chr_base | (m_mmc_vrom_bank[4] & chr_mask), chr); + chr_cb(chr_page ^ 7, chr_base | (m_mmc_vrom_bank[5] & chr_mask), chr); +} + +WRITE8_MEMBER(nes_txrom_device::txrom_write) +{ + UINT8 mmc_helper, cmd; + + LOG_MMC(("txrom_write, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x6001) + { + case 0x0000: + mmc_helper = m_latch ^ data; + m_latch = data; + + // Has PRG Mode changed? + if (mmc_helper & 0x40) + set_prg(m_prg_base, m_prg_mask); + + // Has CHR Mode changed? + if (mmc_helper & 0x80) + set_chr(m_chr_source, m_chr_base, m_chr_mask); + break; + + case 0x0001: + cmd = m_latch & 0x07; + switch (cmd) + { + case 0: case 1: // these do not need to be separated: we take care of them in set_chr! + case 2: case 3: case 4: case 5: + m_mmc_vrom_bank[cmd] = data; + set_chr(m_chr_source, m_chr_base, m_chr_mask); + break; + case 6: + case 7: + m_mmc_prg_bank[cmd - 6] = data; + set_prg(m_prg_base, m_prg_mask); + break; + } + break; + + case 0x2000: + set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + break; + + case 0x2001: + m_wram_protect = data; + break; + + case 0x4000: + m_irq_count_latch = data; + break; + + case 0x4001: + m_irq_count = 0; + break; + + case 0x6000: + m_irq_enable = 0; + m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); + break; + + case 0x6001: + m_irq_enable = 1; + break; + + default: + logerror("txrom_write uncaught: %04x value: %02x\n", offset + 0x8000, data); + break; + } +} + +WRITE8_MEMBER(nes_txrom_device::write_m) +{ + LOG_MMC(("txrom write_m, offset: %04x, data: %02x\n", offset, data)); + + if (BIT(m_wram_protect, 7) && !BIT(m_wram_protect, 6)) + { + if (!m_battery.empty()) + m_battery[offset & (m_battery.size() - 1)] = data; + if (!m_prgram.empty()) + m_prgram[offset & (m_prgram.size() - 1)] = data; + } +} + +READ8_MEMBER(nes_txrom_device::read_m) +{ + LOG_MMC(("txrom read_m, offset: %04x\n", offset)); + + if (BIT(m_wram_protect, 7)) + { + if (!m_battery.empty()) + return m_battery[offset & (m_battery.size() - 1)]; + if (!m_prgram.empty()) + return m_prgram[offset & (m_prgram.size() - 1)]; + } + + return m_open_bus; // open bus +} + + +/*------------------------------------------------- + + HKROM (MMC6 based) board emulation + + iNES: mapper 4 + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_hkrom_device::write_m) +{ + UINT8 write_hi, write_lo; + LOG_MMC(("hkrom write_m, offset: %04x, data: %02x\n", offset, data)); + + if (offset < 0x1000) + return; + + // banks can be written only if both read & write is enabled! + write_hi = ((m_mmc6_reg & 0xc0) == 0xc0); + write_lo = ((m_mmc6_reg & 0x30) == 0x30); + + if (BIT(offset, 9) && write_hi) // access to upper half of 1k + m_mmc6_ram[offset & 0x3ff] = data; + + if (!BIT(offset, 9) && write_lo) // access to lower half of 1k + m_mmc6_ram[offset & 0x3ff] = data; +} + +READ8_MEMBER(nes_hkrom_device::read_m) +{ + LOG_MMC(("hkrom read_m, offset: %04x\n", offset)); + + if (offset < 0x1000) + return m_open_bus; // open bus + + if (!(m_mmc6_reg & 0xa0)) + return m_open_bus; // open bus + + if (BIT(offset, 9) && BIT(m_mmc6_reg, 7)) // access to upper half of 1k when upper read is enabled + return m_mmc6_ram[offset & 0x3ff]; + + if (!BIT(offset, 9) && BIT(m_mmc6_reg, 5)) // access to lower half of 1k when lower read is enabled + return m_mmc6_ram[offset & 0x3ff]; + + // If only one bank is enabled for reading, the other reads back as zero + return 0x00; +} + +WRITE8_MEMBER(nes_hkrom_device::write_h) +{ + UINT8 mmc6_helper; + LOG_MMC(("hkrom write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x6001) + { + case 0x0000: + mmc6_helper = m_latch ^ data; + m_latch = data; + + if (!m_wram_enable && BIT(data, 5)) // if WRAM is disabled and has to be enabled, write + m_wram_enable = BIT(data, 5); // (once WRAM has been enabled, it cannot be disabled without resetting the game) + + // Has PRG Mode changed? + if (BIT(mmc6_helper, 6)) + set_prg(m_prg_base, m_prg_mask); + + // Has CHR Mode changed? + if (BIT(mmc6_helper, 7)) + set_chr(m_chr_source, m_chr_base, m_chr_mask); + break; + + case 0x2001: + if (m_wram_enable) + m_mmc6_reg = data; + break; + + case 0x4001: + m_irq_count = 0; + m_irq_clear = 1; + break; + + default: + txrom_write(space, offset, data, mem_mask); + break; + } +} + +/*------------------------------------------------- + + TxSROM (MMC3 based) board emulation + + Games: Armadillo, Play Action Football, Pro Hockey, RPG + Jinsei Game, Y's 3 + + iNES: mapper 118 + + In MESS: Supported. It also uses mmc3_irq. + + -------------------------------------------------*/ + +void nes_txsrom_device::set_mirror() +{ + if (m_latch & 0x80) + { + set_nt_page(0, CIRAM, BIT(m_mmc_vrom_bank[2],7), 1); + set_nt_page(1, CIRAM, BIT(m_mmc_vrom_bank[3],7), 1); + set_nt_page(2, CIRAM, BIT(m_mmc_vrom_bank[4],7), 1); + set_nt_page(3, CIRAM, BIT(m_mmc_vrom_bank[5],7), 1); + } + else + { + set_nt_page(0, CIRAM, BIT(m_mmc_vrom_bank[0],7), 1); + set_nt_page(1, CIRAM, BIT(m_mmc_vrom_bank[0],7), 1); + set_nt_page(2, CIRAM, BIT(m_mmc_vrom_bank[1],7), 1); + set_nt_page(3, CIRAM, BIT(m_mmc_vrom_bank[1],7), 1); + } +} + +void nes_txsrom_device::chr_cb( int start, int bank, int source ) +{ + set_mirror(); // we could probably update only for one (e.g. the first) call, to slightly optimize the code + chr1_x(start, bank, source); +} + +WRITE8_MEMBER(nes_txsrom_device::write_h) +{ + LOG_MMC(("txsrom write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x6001) + { + case 0x2000: + break; + + default: + txrom_write(space, offset, data, mem_mask); + break; + } +} + +/*------------------------------------------------- + + TQROM (MMC3 based) board emulation + + Games: Pin Bot, High Speed + + iNES: mapper 119 + + In MESS: Supported. It also uses mmc3_irq. + + -------------------------------------------------*/ + +void nes_tqrom_device::set_chr( UINT8 chr, int chr_base, int chr_mask ) +{ + UINT8 chr_page = (m_latch & 0x80) >> 5; + UINT8 src[6], mask[6]; + + // TQROM ignores the source, base and mask set by the MMC3 and determines them based on vrom bank bits + for (int i = 0; i < 6; i++) + { + src[i] = (m_mmc_vrom_bank[i] & 0x40) ? CHRRAM : CHRROM; + mask[i] = (m_mmc_vrom_bank[i] & 0x40) ? 0x07 : 0x3f; + } + + chr1_x(chr_page ^ 0, ((m_mmc_vrom_bank[0] & ~0x01) & mask[0]), src[0]); + chr1_x(chr_page ^ 1, ((m_mmc_vrom_bank[0] | 0x01) & mask[0]), src[0]); + chr1_x(chr_page ^ 2, ((m_mmc_vrom_bank[1] & ~0x01) & mask[1]), src[1]); + chr1_x(chr_page ^ 3, ((m_mmc_vrom_bank[1] | 0x01) & mask[1]), src[1]); + chr1_x(chr_page ^ 4, (m_mmc_vrom_bank[2] & mask[2]), src[2]); + chr1_x(chr_page ^ 5, (m_mmc_vrom_bank[3] & mask[3]), src[3]); + chr1_x(chr_page ^ 6, (m_mmc_vrom_bank[4] & mask[4]), src[4]); + chr1_x(chr_page ^ 7, (m_mmc_vrom_bank[5] & mask[5]), src[5]); +} + + +/*------------------------------------------------- + + NES-QJ board (MMC3 variant for US 2-in-1 Nintendo cart + Super Spike V'Ball + Nintendo World Cup) + + iNES: mapper 47 + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_qj_device::write_m) +{ + LOG_MMC(("qj write_m, offset: %04x, data: %02x\n", offset, data)); + + m_prg_base = BIT(data, 0) << 4; + m_prg_mask = 0x0f; + m_chr_base = BIT(data, 0) << 7; + m_chr_mask = 0x7f; + set_prg(m_prg_base, m_prg_mask); + set_chr(m_chr_source, m_chr_base, m_chr_mask); +} + + +/*------------------------------------------------- + + PAL-ZZ board (MMC3 variant for European 3-in-1 Nintendo cart + Super Mario Bros. + Tetris + Nintendo World Cup) + + iNES: mapper 37 + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_zz_device::write_m) +{ + UINT8 mmc_helper = data & 0x07; + LOG_MMC(("zz write_m, offset: %04x, data: %02x\n", offset, data)); + + m_prg_base = (BIT(mmc_helper, 2) << 4) | (((mmc_helper & 0x03) == 0x03) ? 0x08 : 0); + m_prg_mask = (mmc_helper << 1) | 0x07; + m_chr_base = BIT(mmc_helper, 2) << 7; + m_chr_mask = 0x7f; + set_prg(m_prg_base, m_prg_mask); + set_chr(m_chr_source, m_chr_base, m_chr_mask); +} diff --git a/src/devices/bus/nes/mmc3_clones.c b/src/devices/bus/nes/mmc3_clones.c deleted file mode 100644 index 4a806d0fde2..00000000000 --- a/src/devices/bus/nes/mmc3_clones.c +++ /dev/null @@ -1,2588 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Fabio Priuli -/*********************************************************************************************************** - - - NES/Famicom cartridge emulation for MMC-3 clone PCBs - - - Here we emulate several pirate PCBs based on MMC-3 boards - - ***********************************************************************************************************/ - - -#include "emu.h" -#include "mmc3_clones.h" - - -#ifdef NES_PCB_DEBUG -#define VERBOSE 1 -#else -#define VERBOSE 0 -#endif - -#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) - - -//------------------------------------------------- -// constructor -//------------------------------------------------- - -const device_type NES_NITRA = &device_creator; -const device_type NES_KS7057 = &device_creator; -const device_type NES_SBROS11 = &device_creator; -const device_type NES_MALISB = &device_creator; -const device_type NES_FAMILY4646 = &device_creator; -const device_type NES_PIKAY2K = &device_creator; -const device_type NES_8237 = &device_creator; -const device_type NES_SG_LIONK = &device_creator; -const device_type NES_SG_BOOG = &device_creator; -const device_type NES_KASING = &device_creator; -const device_type NES_KAY = &device_creator; -const device_type NES_H2288 = &device_creator; -const device_type NES_6035052 = &device_creator; -const device_type NES_TXC_TW = &device_creator; -const device_type NES_KOF97 = &device_creator; -const device_type NES_KOF96 = &device_creator; -const device_type NES_SF3 = &device_creator; -const device_type NES_GOUDER = &device_creator; -const device_type NES_SA9602B = &device_creator; -const device_type NES_SACHEN_SHERO = &device_creator; -//const device_type NES_A9746 = &device_creator; - -const device_type NES_FK23C = &device_creator; -const device_type NES_FK23CA = &device_creator; -const device_type NES_S24IN1SC03 = &device_creator; -const device_type NES_BMC_15IN1 = &device_creator; -const device_type NES_BMC_SBIG7 = &device_creator; -const device_type NES_BMC_HIK8 = &device_creator; -const device_type NES_BMC_HIK4 = &device_creator; -const device_type NES_BMC_MARIO7IN1 = &device_creator; -const device_type NES_BMC_GOLD7IN1 = &device_creator; -const device_type NES_BMC_GC6IN1 = &device_creator; -const device_type NES_BMC_411120C = &device_creator; -const device_type NES_BMC_830118C = &device_creator; -const device_type NES_PJOY84 = &device_creator; - - -nes_nitra_device::nes_nitra_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_txrom_device(mconfig, NES_NITRA, "NES Cart Nitra PCB", tag, owner, clock, "nes_nitra", __FILE__) -{ -} - -nes_ks7057_device::nes_ks7057_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_txrom_device(mconfig, NES_KS7057, "NES Cart KS-7057 PCB", tag, owner, clock, "nes_ks7057", __FILE__) -{ -} - -nes_sbros11_device::nes_sbros11_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_txrom_device(mconfig, NES_SBROS11, "NES Cart SMB 11 PCB", tag, owner, clock, "nes_smb11", __FILE__) -{ -} - -nes_malisb_device::nes_malisb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_txrom_device(mconfig, NES_MALISB, "NES Cart Mali Spash Bomb PCB", tag, owner, clock, "nes_malisb", __FILE__) -{ -} - -nes_family4646_device::nes_family4646_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_txrom_device(mconfig, NES_FAMILY4646, "NES Cart BMC-FAMILY-4646 PCB", tag, owner, clock, "nes_family4646", __FILE__) -{ -} - -nes_pikay2k_device::nes_pikay2k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_txrom_device(mconfig, NES_PIKAY2K, "NES Cart PIKACHU Y2K PCB", tag, owner, clock, "nes_pikay2k", __FILE__) -{ -} - -nes_8237_device::nes_8237_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_txrom_device(mconfig, NES_8237, "NES Cart UNL-8237 PCB", tag, owner, clock, "nes_8237", __FILE__) -{ -} - -nes_sglionk_device::nes_sglionk_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_txrom_device(mconfig, NES_SG_LIONK, "NES Cart SuperGame Lion King PCB", tag, owner, clock, "nes_sglionk", __FILE__) -{ -} - -nes_sgboog_device::nes_sgboog_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_txrom_device(mconfig, NES_SG_BOOG, "NES Cart SuperGame BoogerMan PCB", tag, owner, clock, "nes_sgbooger", __FILE__) -{ -} - -nes_kasing_device::nes_kasing_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_txrom_device(mconfig, NES_KASING, "NES Cart Kasing PCB", tag, owner, clock, "nes_kasing", __FILE__) -{ -} - -nes_kay_device::nes_kay_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_txrom_device(mconfig, NES_KAY, "NES Cart KAY PCB", tag, owner, clock, "nes_kay", __FILE__) -{ -} - -nes_h2288_device::nes_h2288_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_txrom_device(mconfig, NES_H2288, "NES Cart H-2288 PCB", tag, owner, clock, "nes_h2288", __FILE__) -{ -} - -nes_6035052_device::nes_6035052_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_txrom_device(mconfig, NES_6035052, "NES Cart UNL-603-5052 PCB", tag, owner, clock, "nes_6035052", __FILE__) -{ -} - -nes_txc_tw_device::nes_txc_tw_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_txrom_device(mconfig, NES_TXC_TW, "NES Cart TXC Thunder Warrior PCB", tag, owner, clock, "nes_txc_tw", __FILE__) -{ -} - -nes_kof97_device::nes_kof97_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_txrom_device(mconfig, NES_KOF97, "NES Cart KOF 97 PCB", tag, owner, clock, "nes_kof97", __FILE__) -{ -} - -nes_kof96_device::nes_kof96_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_txrom_device(mconfig, NES_KOF96, "NES Cart KOF 96 PCB", tag, owner, clock, "nes_kof96", __FILE__) -{ -} - -nes_sf3_device::nes_sf3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_txrom_device(mconfig, NES_SF3, "NES Cart Super Fighter III PCB", tag, owner, clock, "nes_sf3", __FILE__) -{ -} - -nes_gouder_device::nes_gouder_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_txrom_device(mconfig, NES_GOUDER, "NES Cart Gouder PCB", tag, owner, clock, "nes_gouder", __FILE__) -{ -} - -nes_sa9602b_device::nes_sa9602b_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_txrom_device(mconfig, NES_SA9602B, "NES Cart SA-9602B PCB", tag, owner, clock, "nes_sa9602b", __FILE__) -{ -} - -nes_sachen_shero_device::nes_sachen_shero_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_txrom_device(mconfig, NES_SACHEN_SHERO, "NES Cart Street Hero PCB", tag, owner, clock, "nes_shero", __FILE__) -{ -} - -//nes_a9746_device::nes_a9746_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) -// : nes_txrom_device(mconfig, NES_A9746, "NES Cart A-9746 PCB", tag, owner, clock, "nes_bmc_a9746", __FILE__) -//{ -//} - -nes_fk23c_device::nes_fk23c_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) - : nes_txrom_device(mconfig, type, name, tag, owner, clock, shortname, source) -{ -} - -nes_fk23c_device::nes_fk23c_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_txrom_device(mconfig, NES_FK23C, "NES Cart FK23C PCB", tag, owner, clock, "nes_fk23c", __FILE__) -{ -} - -nes_fk23ca_device::nes_fk23ca_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_fk23c_device(mconfig, NES_FK23CA, "NES Cart FK23CA PCB", tag, owner, clock, "nes_fk23ca", __FILE__) -{ -} - -nes_s24in1sc03_device::nes_s24in1sc03_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_txrom_device(mconfig, NES_S24IN1SC03, "NES Cart Super 24 in 1 SC-03 PCB", tag, owner, clock, "nes_s24in1c03", __FILE__) -{ -} - -nes_bmc_15in1_device::nes_bmc_15in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_txrom_device(mconfig, NES_BMC_15IN1, "NES Cart BMC 15 in 1 PCB", tag, owner, clock, "nes_bmc_15in1", __FILE__) -{ -} - -nes_bmc_sbig7_device::nes_bmc_sbig7_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_txrom_device(mconfig, NES_BMC_SBIG7, "NES Cart BMC Super BIG 7 in 1 PCB", tag, owner, clock, "nes_bmc_sbit7", __FILE__) -{ -} - -nes_bmc_hik8_device::nes_bmc_hik8_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_txrom_device(mconfig, NES_BMC_HIK8, "NES Cart BMC Super HIK 8 in 1 PCB", tag, owner, clock, "nes_bmc_hik8", __FILE__) -{ -} - -nes_bmc_hik4_device::nes_bmc_hik4_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_txrom_device(mconfig, NES_BMC_HIK4, "NES Cart BMC Super HIK 4 in 1 PCB", tag, owner, clock, "nes_bmc_hik4", __FILE__) -{ -} - -nes_bmc_mario7in1_device::nes_bmc_mario7in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_txrom_device(mconfig, NES_BMC_MARIO7IN1, "NES Cart BMC Mario 7 in 1 PCB", tag, owner, clock, "nes_bmc_mario7in1", __FILE__) -{ -} - -nes_bmc_gold7in1_device::nes_bmc_gold7in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_txrom_device(mconfig, NES_BMC_GOLD7IN1, "NES Cart BMC Golden 7 in 1 PCB", tag, owner, clock, "nes_bmc_gold7in1", __FILE__) -{ -} - -nes_bmc_gc6in1_device::nes_bmc_gc6in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_txrom_device(mconfig, NES_BMC_GC6IN1, "NES Cart BMC Golden Card 6 in 1 PCB", tag, owner, clock, "nes_bmc_gc6in1", __FILE__) -{ -} - -nes_bmc_411120c_device::nes_bmc_411120c_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_txrom_device(mconfig, NES_BMC_411120C, "NES Cart BMC 411120C PCB", tag, owner, clock, "nes_bmc_411120c", __FILE__) -{ -} - -nes_bmc_830118c_device::nes_bmc_830118c_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_txrom_device(mconfig, NES_BMC_830118C, "NES Cart BMC 830118C PCB", tag, owner, clock, "nes_bmc_830118c", __FILE__) -{ -} - -nes_pjoy84_device::nes_pjoy84_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_txrom_device(mconfig, NES_PJOY84, "NES Cart Powerjoy 84 PCB", tag, owner, clock, "nes_pjoy84", __FILE__) -{ -} - - - -void nes_family4646_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - mmc3_common_initialize(0x1f, 0xff, 0); -} - -void nes_pikay2k_device::device_start() -{ - mmc3_start(); - save_item(NAME(m_reg)); -} - -void nes_pikay2k_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - - m_reg[0] = 0xff; - m_reg[1] = 0; - mmc3_common_initialize(0xff, 0xff, 0); -} - -void nes_8237_device::device_start() -{ - mmc3_start(); - save_item(NAME(m_reg)); - save_item(NAME(m_cd_enable)); -} - -void nes_8237_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - - m_reg[0] = 0; - m_reg[1] = 0; - m_reg[2] = 0; - m_cd_enable = 0; - mmc3_common_initialize(0xff, 0xff, 0); -} - -void nes_sglionk_device::device_start() -{ - mmc3_start(); - save_item(NAME(m_reg)); - save_item(NAME(m_reg_enabled)); -} - -void nes_sglionk_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - - m_reg = m_reg_enabled = 0; - mmc3_common_initialize(0xff, 0xff, 0); -} - -void nes_sgboog_device::device_start() -{ - mmc3_start(); - save_item(NAME(m_reg)); - save_item(NAME(m_mode)); -} - -void nes_sgboog_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - - m_mode = 0x04; - m_reg[0] = 0x00; - m_reg[1] = 0xff; - m_reg[2] = 0; - mmc3_common_initialize(0x1f, 0xff, 0); - set_prg(m_prg_base, m_prg_mask); - set_chr(m_chr_source, m_chr_base, m_chr_mask); -} - -void nes_kasing_device::device_start() -{ - mmc3_start(); - save_item(NAME(m_reg)); -} - -void nes_kasing_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - - m_reg = 0; - mmc3_common_initialize(0xff, 0xff, 0); -} - - -void nes_kay_device::device_start() -{ - mmc3_start(); - save_item(NAME(m_low_reg)); - save_item(NAME(m_reg)); -} - -void nes_kay_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - - memset(m_reg, 0, sizeof(m_reg)); - m_low_reg = 0; - mmc3_common_initialize(0xff, 0xff, 0); -} - - -void nes_h2288_device::device_start() -{ - mmc3_start(); - save_item(NAME(m_reg)); -} - -void nes_h2288_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - - m_reg[0] = 0; - m_reg[1] = 0; - mmc3_common_initialize(0xff, 0xff, 0); -} - -void nes_6035052_device::device_start() -{ - mmc3_start(); - save_item(NAME(m_prot)); -} - -void nes_6035052_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - mmc3_common_initialize(0xff, 0xff, 0); - - m_prot = 0; -} - -void nes_kof96_device::device_start() -{ - mmc3_start(); - save_item(NAME(m_reg)); -} - -void nes_kof96_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - memset(m_reg, 0, sizeof(m_reg)); - mmc3_common_initialize(0xff, 0xff, 0); -} - -void nes_gouder_device::device_start() -{ - mmc3_start(); - save_item(NAME(m_reg)); -} - -void nes_gouder_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - memset(m_reg, 0, sizeof(m_reg)); - mmc3_common_initialize(0xff, 0xff, 0); -} - -void nes_sa9602b_device::device_start() -{ - mmc3_start(); - save_item(NAME(m_reg)); - save_item(NAME(m_prg_chip)); -} - -void nes_sa9602b_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - - m_reg = 0; - m_prg_chip = 0; - mmc3_common_initialize(0x1ff, 0xff, 0); // 1.5MB of PRG-ROM, no CHR-ROM but 32K CHR-RAM -} - -void nes_sachen_shero_device::device_start() -{ - mmc3_start(); - save_item(NAME(m_reg)); -} - -void nes_sachen_shero_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - - m_reg = 0; - mmc3_common_initialize(0xff, 0x1ff, 0); -} - -void nes_fk23c_device::device_start() -{ - mmc3_start(); - save_item(NAME(m_reg)); - save_item(NAME(m_mmc_cmd1)); -} - -void nes_fk23c_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - - m_mmc_cmd1 = 0; - m_reg[0] = 4; - m_reg[1] = 0xff; - m_reg[2] = m_reg[3] = 0; - m_reg[4] = m_reg[5] = m_reg[6] = m_reg[7] = 0xff; - mmc3_common_initialize(0xff, 0xff, 0); - fk23c_set_prg(); - fk23c_set_chr(); - -} - -void nes_fk23ca_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - - m_mmc_cmd1 = 0; - m_reg[0] = m_reg[1] = m_reg[2] = m_reg[3] = 0; - m_reg[4] = m_reg[5] = m_reg[6] = m_reg[7] = 0xff; - mmc3_common_initialize(0xff, 0xff, 0); - fk23c_set_prg(); - fk23c_set_chr(); -} - -void nes_s24in1sc03_device::device_start() -{ - mmc3_start(); - save_item(NAME(m_reg)); -} - -void nes_s24in1sc03_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - - m_reg[0] = 0x24; - m_reg[1] = 0x9f; - m_reg[2] = 0; - mmc3_common_initialize(0xff, 0xff, 0); -} - -void nes_bmc_15in1_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - - mmc3_common_initialize(0x1f, 0xff, 0); - m_prg_base = 0x10; // this board has a diff prg_base - set_prg(m_prg_base, m_prg_mask); -} - -void nes_bmc_sbig7_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - mmc3_common_initialize(0x0f, 0x7f, 0); -} - -void nes_bmc_hik8_device::device_start() -{ - mmc3_start(); - save_item(NAME(m_reg)); - save_item(NAME(m_count)); -} - -void nes_bmc_hik8_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - - m_count = 0; - memset(m_reg, 0, sizeof(m_reg)); - mmc3_common_initialize(0x3f, 0xff, 0); -} - -void nes_bmc_hik4_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - mmc3_common_initialize(0x0f, 0x7f, 0); -} - -void nes_bmc_mario7in1_device::device_start() -{ - mmc3_start(); - save_item(NAME(m_reg_written)); -} - -void nes_bmc_mario7in1_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - - m_reg_written = 0; - mmc3_common_initialize(0x1f, 0xff, 0); -} - -void nes_bmc_gold7in1_device::device_start() -{ - mmc3_start(); - save_item(NAME(m_reg_written)); -} - -void nes_bmc_gold7in1_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - - m_reg_written = 0; - mmc3_common_initialize(0x1f, 0xff, 0); -} - -void nes_bmc_gc6in1_device::device_start() -{ - mmc3_start(); - save_item(NAME(m_reg)); -} - -void nes_bmc_gc6in1_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - - m_reg[0] = 0x00; - m_reg[1] = 0xff; - m_reg[2] = 0x03; - m_reg[3] = 0; - mmc3_common_initialize(0xff, 0xff, 0); - set_prg(m_prg_base, m_prg_mask); - set_chr(m_chr_source, m_chr_base, m_chr_mask); -} - -void nes_bmc_411120c_device::device_start() -{ - mmc3_start(); - save_item(NAME(m_reg)); -} - -void nes_bmc_411120c_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - - m_reg = 0; - mmc3_common_initialize(0x7f, 0x7f, 0); -} - -void nes_bmc_830118c_device::device_start() -{ - mmc3_start(); - save_item(NAME(m_reg)); -} - -void nes_bmc_830118c_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - - m_reg = 0; - mmc3_common_initialize(0x7f, 0x7f, 0); -} - -void nes_pjoy84_device::device_start() -{ - mmc3_start(); - save_item(NAME(m_reg)); -} - -void nes_pjoy84_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - - memset(m_reg, 0, sizeof(m_reg)); - set_base_mask(); - mmc3_common_initialize(m_prg_mask, m_chr_mask, 0); -} - - - -/*------------------------------------------------- - mapper specific handlers - -------------------------------------------------*/ - -/*------------------------------------------------- - - Bootleg Board by Nitra - - Games: Time Diver Avenger - - This acts basically like a MMC3 with different use of write - address. - - iNES: mapper 250 - - In MESS: Supported. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_nitra_device::write_h) -{ - LOG_MMC(("nitra write_h, offset: %04x, data: %02x\n", offset, data)); - - txrom_write(space, (offset & 0x6000) | ((offset & 0x400) >> 10), offset & 0xff, mem_mask); -} - -/*------------------------------------------------- - - Board UNL-KS7057 - - Games: Street Fighter VI / Fight Street VI - - MMC3 clone (identical, but for switched address lines) - - In MESS: Supported - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_ks7057_device::write_h) -{ - LOG_MMC(("ks7057 write_h, offset: %04x, data: %02x\n", offset, data)); - - offset = (BIT(offset, 0) << 1) | BIT(offset, 1) | (offset & ~0x03); - txrom_write(space, offset, data, mem_mask); -} - -/*------------------------------------------------- - - BTL-SUPERBROS11 - - Games: Super Mario Bros. 11, Super Mario Bros. 17 - - This acts basically like a MMC3 with different use of write - address. - - iNES: mapper 196 - - In MESS: Supported. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_sbros11_device::write_h) -{ - LOG_MMC(("smb11 write_h, offset: %04x, data: %02x\n", offset, data)); - - txrom_write(space, (offset & 0x6000) | ((offset & 0x04) >> 2), data, mem_mask); -} - -/*------------------------------------------------- - - UNL-MALISB - - Games: Super Mali Bros Splash Bomb - - This is very similar to mapper 196, but with additional - data bit swap. - - In MESS: Supported. - - -------------------------------------------------*/ - -void nes_malisb_device::prg_cb(int start, int bank) -{ - bank = (bank & 3) | ((bank & 8) >> 1) | ((bank & 4) << 1); - prg8_x(start, bank); -} - -void nes_malisb_device::chr_cb(int start, int bank, int source) -{ - bank = (bank & 0xdd) | ((bank & 0x20) >> 4) | ((bank & 2) << 4); - chr1_x(start, bank, source); -} - -WRITE8_MEMBER(nes_malisb_device::write_h) -{ - LOG_MMC(("malisb write_h, offset: %04x, data: %02x\n", offset, data)); - - if (offset > 0x4000) - txrom_write(space, (offset & 0xfffe) | ((offset & 0x04) >> 2) | ((offset & 0x08) >> 3), data, mem_mask); - else - txrom_write(space, (offset & 0xfffe) | ((offset & 0x08) >> 3), data, mem_mask); -} - -/*------------------------------------------------- - - BMC-FAMILY-4646B - - Known Boards: Unknown Multigame Bootleg Board (4646B) - Games: 2 in 1 - Family Kid & Aladdin 4 - - MMC3 clone - - iNES: mapper 134 - - In MESS: Supported. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_family4646_device::write_m) -{ - LOG_MMC(("family4646 write_m, offset: %04x, data: %02x\n", offset, data)); - - if (offset == 0x01) - { - m_prg_base = (data & 0x02) << 4; - m_prg_mask = 0x1f; - m_chr_base = (data & 0x20) << 3; - m_chr_mask = 0xff; - set_prg(m_prg_base, m_prg_mask); - set_chr(m_chr_source, m_chr_base, m_chr_mask); - } -} - -/*------------------------------------------------- - - BTL-PIKACHUY2K - - Games: Pikachu Y2k - - iNES: mapper 254 - - In MESS: - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_pikay2k_device::write_h) -{ - LOG_MMC(("pikay2k write_h, offset: %04x, data: %02x\n", offset, data)); - - switch (offset & 0x6001) - { - case 0x2001: - m_reg[1] = data; - break; - - case 0x2000: - m_reg[0] = 0; - default: - txrom_write(space, offset, data, mem_mask); - break; - } -} - -// strange WRAM usage: it is protected at start, and gets unprotected after the first write to 0xa000 -WRITE8_MEMBER(nes_pikay2k_device::write_m) -{ - LOG_MMC(("pikay2k write_m, offset: %04x, data: %02x\n", offset, data)); - - m_prgram[offset & 0x1fff] = data; -} - -READ8_MEMBER(nes_pikay2k_device::read_m) -{ - LOG_MMC(("pikay2k read_m, offset: %04x\n", offset)); - - return m_prgram[offset & 0x1fff] ^ (m_reg[0] & m_reg[1]); -} - -/*------------------------------------------------- - - Board UNL-8237 - - Games: Pocahontas 2 - - MMC3 clone - - In MESS: Supported - - -------------------------------------------------*/ - -void nes_8237_device::prg_cb(int start, int bank) -{ - if (!(m_reg[0] & 0x80)) - prg8_x(start, bank); -} - -void nes_8237_device::chr_cb(int start, int bank, int source) -{ - bank |= ((m_reg[1] << 6) & 0x100); - chr1_x(start, bank, source); -} - -WRITE8_MEMBER(nes_8237_device::write_l) -{ - LOG_MMC(("unl_8237 write_l, offset: %04x, data: %02x\n", offset, data)); - offset += 0x100; - - if (offset == 0x1000) - { - m_reg[0] = data; - if (m_reg[0] & 0x80) - { - if (m_reg[0] & 0x20) - prg32((m_reg[0] & 0x0f) >> 1); - else - { - prg16_89ab(m_reg[0] & 0x1f); - prg16_cdef(m_reg[0] & 0x1f); - } - } - else - set_prg(m_prg_base, m_prg_mask); - } - - if (offset == 0x1001) - { - m_reg[1] = data; - set_chr(m_chr_source, m_chr_base, m_chr_mask); - } - - if (offset == 0x1007) - { - m_reg[2] = data & 0x07; // this selects different permutations for addresses and regs (to be implemented) - } -} - -WRITE8_MEMBER(nes_8237_device::write_h) -{ - static const UINT8 conv_table[8] = {0, 2, 6, 1, 7, 3, 4, 5}; - LOG_MMC(("unl_8237 write_h, offset: %04x, data: %02x\n", offset, data)); - - switch (offset & 0x7000) - { - case 0x0000: - case 0x1000: - set_nt_mirroring((data | (data >> 7)) & 0x01 ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); - break; - - case 0x2000: - case 0x3000: - m_cd_enable = 1; - data = (data & 0xc0) | conv_table[data & 0x07]; - txrom_write(space, 0x0000, data, mem_mask); - break; - - case 0x4000: - case 0x5000: - if (m_cd_enable) - { - m_cd_enable = 0; - txrom_write(space, 0x0001, data, mem_mask); - } - break; - - case 0x6000: - break; - - case 0x7000: - txrom_write(space, 0x6001, data, mem_mask); - txrom_write(space, 0x4000, data, mem_mask); - txrom_write(space, 0x4001, data, mem_mask); - break; - } -} - -/*------------------------------------------------- - - Bootleg Board by Super Game - - Games: The Lion King - - MMC3 clone. - - iNES: mapper 114 - - In MESS: Supported. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_sglionk_device::write_m) -{ - LOG_MMC(("sglionk write_m, offset: %04x, data: %02x\n", offset, data)); - - m_reg = data; - - if (m_reg & 0x80) - { - prg16_89ab(data & 0x1f); - prg16_cdef(data & 0x1f); - } - else - set_prg(m_prg_base, m_prg_mask); - -} - -WRITE8_MEMBER(nes_sglionk_device::write_h) -{ - static const UINT8 conv_table[8] = {0, 3, 1, 5, 6, 7, 2, 4}; - LOG_MMC(("sglionk write_h, offset: %04x, data: %02x\n", offset, data)); - - if (offset < 0x6000) - { - switch (offset & 0x6000) - { - case 0x0000: - set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); - break; - case 0x2000: - m_reg_enabled = 1; - data = (data & 0xc0) | conv_table[data & 0x07]; - txrom_write(space, 0x0000, data, mem_mask); - break; - case 0x4000: - if (m_reg_enabled && (m_reg & 0x80) == 0) - { - m_reg_enabled = 0; - txrom_write(space, 0x0001, data, mem_mask); - } - break; - } - } - else - { - switch (offset & 0x03) - { - case 0x02: - txrom_write(space, 0x6000, data, mem_mask); - break; - case 0x03: - txrom_write(space, 0x6001, data, mem_mask); - txrom_write(space, 0x4000, data, mem_mask); - txrom_write(space, 0x4001, data, mem_mask); - break; - } - } -} - -/*------------------------------------------------- - - Bootleg Board by Super Game - - Games: Boogerman, Mortal Kombat III - - MMC3 clone. Also, it probably needs a hack to support both - variants (Boogerman & MK3). - - iNES: mapper 215 - - In MESS: Preliminary support. - - -------------------------------------------------*/ - -void nes_sgboog_device::prg_cb(int start, int bank) -{ - if (!(m_reg[0] & 0x80)) // if this is != 0 we should never even arrive here - { - if (m_reg[1] & 0x08) - bank = (bank & 0x1f) | 0x20; - else - bank = (bank & 0x0f) | (m_reg[1] & 0x10); - - prg8_x(start, bank); - } -} - -void nes_sgboog_device::chr_cb(int start, int bank, int source) -{ - if ((m_reg[1] & 0x04)) - bank |= 0x100; - else - bank = (bank & 0x7f) | ((m_reg[1] & 0x10) << 3); - - chr1_x(start, bank, source); -} - -void nes_sgboog_device::set_prg(int prg_base, int prg_mask) -{ - if (m_reg[0] & 0x80) - { - prg16_89ab((m_reg[0] & 0xf0) | (m_reg[1] & 0x10)); - prg16_cdef((m_reg[0] & 0xf0) | (m_reg[1] & 0x10)); - } - else - { - // here standard MMC3 bankswitch - UINT8 prg_flip = (m_latch & 0x40) ? 2 : 0; - - prg_cb(0, prg_base | (m_mmc_prg_bank[0 ^ prg_flip] & prg_mask)); - prg_cb(1, prg_base | (m_mmc_prg_bank[1] & prg_mask)); - prg_cb(2, prg_base | (m_mmc_prg_bank[2 ^ prg_flip] & prg_mask)); - prg_cb(3, prg_base | (m_mmc_prg_bank[3] & prg_mask)); - } -} - -WRITE8_MEMBER(nes_sgboog_device::write_l) -{ - LOG_MMC(("sgboog write_l, offset: %04x, data: %02x\n", offset, data)); - offset += 0x100; - - if (offset == 0x1000) - { - m_reg[0] = data; - set_prg(m_prg_base, m_prg_mask); - } - else if (offset == 0x1001) - { - m_reg[1] = data; - set_chr(m_chr_source, m_chr_base, m_chr_mask); - } - else if (offset == 0x1007) - { - m_latch = 0; - m_mode = data; - set_prg(m_prg_base, m_prg_mask); - set_chr(m_chr_source, m_chr_base, m_chr_mask); - } -} - -WRITE8_MEMBER(nes_sgboog_device::write_m) -{ - LOG_MMC(("sgboog write_m, offset: %04x, data: %02x\n", offset, data)); - - if (offset == 0x0000) - { - m_reg[0] = data; - set_prg(m_prg_base, m_prg_mask); - } - else if (offset == 0x0001) - { - m_reg[1] = data; - set_chr(m_chr_source, m_chr_base, m_chr_mask); - } - else if (offset == 0x0007) - { - m_latch = 0; - m_mode = data; - set_prg(m_prg_base, m_prg_mask); - set_chr(m_chr_source, m_chr_base, m_chr_mask); - } -} - -WRITE8_MEMBER(nes_sgboog_device::write_h) -{ - static const UINT8 conv_table[8] = {0,2,5,3,6,1,7,4}; - LOG_MMC(("sgboog write_h, offset: %04x, data: %02x\n", offset, data)); - - if (m_mode) - { - switch (offset & 0x6001) - { - case 0x0000: - break; - - case 0x0001: - if (m_reg[2] && ((m_reg[0] & 0x80) == 0 || (m_latch & 0x07) < 6)) // if we use the prg16 banks and cmd=6,7 DON'T enter! - { - m_reg[2] = 0; - txrom_write(space, 0x0001, data, mem_mask); - } - break; - - case 0x2000: - data = (data & 0xc0) | conv_table[data & 0x07]; - m_reg[2] = 1; - txrom_write(space, 0x0000, data, mem_mask); - break; - - case 0x4000: - set_nt_mirroring(((data >> 7) | data) & 0x01 ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); - break; - - case 0x4001: - txrom_write(space, 0x6001, data, mem_mask); - break; - - case 0x6001: - txrom_write(space, 0x4000, data, mem_mask); - txrom_write(space, 0x4001, data, mem_mask); - break; - - default: - txrom_write(space, offset, data, mem_mask); - break; - } - } - else - txrom_write(space, offset, data, mem_mask); -} - -/*------------------------------------------------- - - Bootleg Board by Kasing - - Games: AV Jiu Ji Mahjong, Bao Qing Tian, Thunderbolt 2, - Shisen Mahjong 2 - - MMC3 clone - - iNES: mapper 115 - - In MESS: Supported - - -------------------------------------------------*/ - -void nes_kasing_device::prg_cb(int start, int bank) -{ - if (BIT(m_reg, 7)) - prg32(m_reg >> 1); - else - prg8_x(start, bank); -} - -WRITE8_MEMBER(nes_kasing_device::write_m) -{ - LOG_MMC(("kasing write_m, offset: %04x, data: %02x\n", offset, data)); - - switch (offset & 0x01) - { - case 0x00: - m_reg = data; - set_prg(m_prg_base, m_prg_mask); - break; - case 0x01: - m_chr_base = (data & 0x01) ? 0x100 : 0x000; - set_chr(m_chr_source, m_chr_base, m_chr_mask); - break; - } -} - -/*------------------------------------------------- - - Bootleg Board by Kay (for Panda Prince) - - Games: The Panda Prince, Sonic 3d Blast 6, SFZ2 '97, YuYu '97 - (and its title hack MK6), UMK3, Super Lion King 2 - - MMC3 clone. This is basically KOF96 board + protection - - iNES: mapper 121 - - In MESS: Most game works, with some graphical issues. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_kay_device::write_l) -{ - LOG_MMC(("kay write_l, offset: %04x, data: %02x\n", offset, data)); - offset += 0x100; - - if (offset >= 0x1000) - { - switch (data & 0x03) - { - case 0x00: - case 0x01: - m_low_reg = 0x83; - break; - case 0x02: - m_low_reg = 0x42; - break; - case 0x03: - m_low_reg = 0x00; - break; - } - } -} - -READ8_MEMBER(nes_kay_device::read_l) -{ - LOG_MMC(("kay read_l, offset: %04x\n", offset)); - offset += 0x100; - - if (offset >= 0x1000) - return m_low_reg; - else - return 0xff; -} - -void nes_kay_device::update_regs() -{ - switch (m_reg[5] & 0x3f) - { - case 0x20: - case 0x29: - case 0x2b: - case 0x3f: - m_reg[7] = 1; - m_reg[1] = m_reg[6]; - break; - case 0x26: - m_reg[7] = 0; - m_reg[1] = m_reg[6]; - break; - case 0x2c: - m_reg[7] = 1; - if (m_reg[6]) - m_reg[1] = m_reg[6]; - break; - - case 0x28: - m_reg[7] = 0; - m_reg[2] = m_reg[6]; - break; - - case 0x2a: - m_reg[7] = 0; - m_reg[3] = m_reg[6]; - break; - - case 0x2f: - break; - - default: - m_reg[5] = 0; - break; - } -} - -void nes_kay_device::prg_cb(int start, int bank) -{ - if (m_reg[5] & 0x3f) - { - prg8_x(start, bank & 0x3f); - prg8_ef(m_reg[1]); - prg8_cd(m_reg[2]); - prg8_ab(m_reg[3]); - } - else - prg8_x(start, bank & 0x3f); -} - -void nes_kay_device::chr_cb(int start, int bank, int source) -{ - UINT8 chr_page = (m_latch & 0x80) >> 5; - - if ((start & 0x04) == chr_page) - bank |= 0x100; - - chr1_x(start, bank, source); -} - -WRITE8_MEMBER(nes_kay_device::write_h) -{ - LOG_MMC(("kay write_h, offset: %04x, data: %02x\n", offset, data)); - - switch (offset & 0x6003) - { - case 0x0000: - txrom_write(space, offset, data, mem_mask); - set_prg(m_prg_base, m_prg_mask); - break; - - case 0x0001: - m_reg[6] = (BIT(data, 0) << 5) | (BIT(data, 1) << 4) | (BIT(data, 2) << 3) - | (BIT(data, 3) << 2) | (BIT(data, 4) << 1) | BIT(data, 5); - if (!m_reg[7]) - update_regs(); - txrom_write(space, offset, data, mem_mask); - set_prg(m_prg_base, m_prg_mask); - break; - - case 0x0003: - m_reg[5] = data; - update_regs(); - txrom_write(space, 0x0000, data, mem_mask); - set_prg(m_prg_base, m_prg_mask); - break; - - default: - txrom_write(space, offset, data, mem_mask); - break; - } -} - -/*------------------------------------------------- - - UNL-H2288 - - -------------------------------------------------*/ - -void nes_h2288_device::prg_cb(int start, int bank) -{ - if (!(m_reg[0] & 0x40)) - prg8_x(start, bank); -} - -WRITE8_MEMBER(nes_h2288_device::write_l) -{ - LOG_MMC(("h2288 write_l, offset: %04x, data: %02x\n", offset, data)); - offset += 0x100; - - if (offset >= 0x1800) - { - m_reg[offset & 1] = data; - if (m_reg[0] & 0x40) - { - UINT8 helper1 = (m_reg[0] & 0x05) | ((m_reg[0] >> 2) & 0x0a); - UINT8 helper2 = BIT(m_reg[0], 1); - prg16_89ab(helper1 & ~helper2); - prg16_cdef(helper1 | helper2); - } - else - set_prg(m_prg_base, m_prg_mask); - } -} - -READ8_MEMBER(nes_h2288_device::read_l) -{ - LOG_MMC(("h2288 read_l, offset: %04x\n", offset)); - offset += 0x100; - - if (offset >= 0x1000) - { - int helper = offset >> 8; - if (offset & 1) - return helper | 0x01; - else - return helper ^ 0x01; - } - - return 0; -} - -WRITE8_MEMBER(nes_h2288_device::write_h) -{ - static const UINT8 conv_table[8] = {0, 3, 1, 5, 6, 7, 2, 4}; - LOG_MMC(("h2288 write_h, offset: %04x, data: %02x\n", offset, data)); - - switch (offset & 0x6001) - { - case 0x0000: - txrom_write(space, 0x0000, (data & 0xc0) | conv_table[data & 0x07], mem_mask); - break; - - default: - txrom_write(space, offset, data, mem_mask); - break; - } -} - -/*------------------------------------------------- - - UNL-603-5052 - - MMC3 + protection access in 0x4020 - 0x7fff - - in MESS: Partial support - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_6035052_device::write_ex) -{ - LOG_MMC(("6035052 write_ex, offset: %04x, data: %02x\n", offset, data)); - m_prot = data & 0x03; - if (m_prot == 1) - m_prot = 2; -} - -READ8_MEMBER(nes_6035052_device::read_ex) -{ - LOG_MMC(("6035052 read_ex, offset: %04x\n", offset)); - return m_prot; -} - -/*------------------------------------------------- - - Bootleg Board 'Thunder Warrior' by TXC - - Games: Master Fighter II, Master Fighter 3, Thunder Warrior - - MMC3 clone - - iNES: mapper 189 - - In MESS: Supported. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_txc_tw_device::write_l) -{ - LOG_MMC(("txc_tw write_l, offset: %04x, data: %02x\n", offset, data)); - - prg32((data >> 4) | data); -} - -/* writes to 0x8000-0xffff are like MMC3 but no PRG bankswitch (beacuse it is handled by low writes) */ -void nes_txc_tw_device::prg_cb(int start, int bank) -{ - return; -} - -/*------------------------------------------------- - - Board UNL-KOF97 - - Games: King of Fighters 97 (Rex Soft) - - MMC3 clone - - In MESS: Not working - - -------------------------------------------------*/ - -inline UINT8 kof97_unscramble( UINT8 data ) -{ - return ((data >> 1) & 0x01) | ((data >> 4) & 0x02) | ((data << 2) & 0x04) | ((data >> 0) & 0xd8) | ((data << 3) & 0x20); -} - -WRITE8_MEMBER(nes_kof97_device::write_h) -{ - LOG_MMC(("kof97 write_h, offset: %04x, data: %02x\n", offset, data)); - - /* Addresses 0x9000, 0xa000, 0xd000 & 0xf000 behaves differently than MMC3 */ - if (offset == 0x1000) - txrom_write(space, 0x0001, kof97_unscramble(data), mem_mask); - else if (offset == 0x2000) - txrom_write(space, 0x0000, kof97_unscramble(data), mem_mask); - else if (offset == 0x5000) - txrom_write(space, 0x4001, kof97_unscramble(data), mem_mask); - else if (offset == 0x7000) - txrom_write(space, 0x6001, kof97_unscramble(data), mem_mask); - /* Other addresses behaves like MMC3, up to unscrambling data */ - else - txrom_write(space, offset, kof97_unscramble(data), mem_mask); -} - -/*------------------------------------------------- - - Bootleg Board for KOF96 - - Games: The King of Fighters 96, Sonic 3D Blast 6, Street - Fighter Zero 2 - - MMC3 clone - - iNES: mapper 187 - - In MESS: Preliminary Support. - - -------------------------------------------------*/ - -void nes_kof96_device::prg_cb(int start, int bank) -{ - if (!(m_reg[0] & 0x80)) - prg8_x(start, bank); -} - -void nes_kof96_device::chr_cb(int start, int bank, int source) -{ - UINT8 chr_page = (m_latch & 0x80) >> 5; - - if ((start & 0x04) == chr_page) - bank |= 0x100; - - chr1_x(start, bank, source); -} - -WRITE8_MEMBER(nes_kof96_device::write_l) -{ - UINT8 new_bank; - LOG_MMC(("kof96 write_l, offset: %04x, data: %02x\n", offset, data)); - offset += 0x100; - - if (offset == 0x1000) - { - m_reg[0] = data; - - if (m_reg[0] & 0x80) - { - new_bank = (m_reg[0] & 0x1f); - - if (m_reg[0] & 0x20) - prg32(new_bank >> 2); - else - { - prg16_89ab(new_bank); - prg16_cdef(new_bank); - } - } - else - set_prg(m_prg_base, m_prg_mask); - } - - if (offset >= 0x1000) - { - switch (data & 0x03) - { - case 0x00: - case 0x01: - m_reg[1] = 0x83; - break; - case 0x02: - m_reg[1] = 0x42; - break; - case 0x03: - m_reg[1] = 0x00; - break; - } - - } - - if (!m_reg[3] && offset > 0x1000) - { - m_reg[3] = 1; - space.write_byte(0x4017, 0x40); - } -} - -READ8_MEMBER(nes_kof96_device::read_l) -{ - LOG_MMC(("kof96 read_l, offset: %04x\n", offset)); - offset += 0x100; - - if (!(offset < 0x1000)) - return m_reg[1]; - else - return 0; -} - -WRITE8_MEMBER(nes_kof96_device::write_h) -{ - LOG_MMC(("kof96 write_h, offset: %04x, data: %02x\n", offset, data)); - - switch (offset & 0x6003) - { - case 0x0000: - m_reg[2] = 1; - txrom_write(space, 0x0000, data, mem_mask); - break; - - case 0x0001: - if (m_reg[2]) - txrom_write(space, 0x0001, data, mem_mask); - break; - - case 0x0002: - break; - - case 0x0003: - m_reg[2] = 0; - - if (data == 0x28) - prg8_cd(0x17); - else if (data == 0x2a) - prg8_ab(0x0f); - break; - - default: - txrom_write(space, offset, data, mem_mask); - break; - } -} - -/*------------------------------------------------- - - Bootleg Board for Super Fighter III - - MMC3 clone - - iNES: mapper 197 - - In MESS: Supported. - - -------------------------------------------------*/ - -void nes_sf3_device::set_chr(UINT8 chr_source, int chr_base, int chr_mask) -{ - chr4_0(chr_base | ((m_mmc_vrom_bank[0] >> 1) & chr_mask), chr_source); - chr2_4(chr_base | (m_mmc_vrom_bank[1] & chr_mask), chr_source); - chr2_6(chr_base | (m_mmc_vrom_bank[2] & chr_mask), chr_source); -} - -WRITE8_MEMBER(nes_sf3_device::write_h) -{ - UINT8 cmd; - LOG_MMC(("sf3 write_h, offset: %04x, data: %02x\n", offset, data)); - - switch (offset & 0x6001) - { - case 0x0001: - cmd = m_latch & 0x07; - switch (cmd) - { - case 0: case 2: case 4: - m_mmc_vrom_bank[cmd >> 1] = data; - set_chr(m_chr_source, m_chr_base, m_chr_mask); - break; - case 6: - case 7: - m_mmc_prg_bank[cmd - 6] = data; - set_prg(m_prg_base, m_prg_mask); - break; - } - break; - - default: - txrom_write(space, offset, data, mem_mask); - break; - } -} - -/*------------------------------------------------- - - Bootleg Board 37017 (?) by Gouder - - Games: Street Fighter IV - - MMC3 clone. It also requires reads from 0x5000-0x7fff. - - iNES: mapper 208 - - In MESS: Preliminary Support. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_gouder_device::write_l) -{ - static const UINT8 conv_table[256] = - { - 0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x49,0x19,0x09,0x59,0x49,0x19,0x09, - 0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x51,0x41,0x11,0x01,0x51,0x41,0x11,0x01, - 0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x49,0x19,0x09,0x59,0x49,0x19,0x09, - 0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x51,0x41,0x11,0x01,0x51,0x41,0x11,0x01, - 0x00,0x10,0x40,0x50,0x00,0x10,0x40,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x08,0x18,0x48,0x58,0x08,0x18,0x48,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x10,0x40,0x50,0x00,0x10,0x40,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x08,0x18,0x48,0x58,0x08,0x18,0x48,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x58,0x48,0x18,0x08,0x58,0x48,0x18,0x08, - 0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x50,0x40,0x10,0x00,0x50,0x40,0x10,0x00, - 0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x58,0x48,0x18,0x08,0x58,0x48,0x18,0x08, - 0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x50,0x40,0x10,0x00,0x50,0x40,0x10,0x00, - 0x01,0x11,0x41,0x51,0x01,0x11,0x41,0x51,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x09,0x19,0x49,0x59,0x09,0x19,0x49,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x01,0x11,0x41,0x51,0x01,0x11,0x41,0x51,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x09,0x19,0x49,0x59,0x09,0x19,0x49,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 - }; - - LOG_MMC(("gouder write_l, offset: %04x, data: %02x\n", offset, data)); - - if (!(offset < 0x1700)) - m_reg[offset & 0x03] = data ^ conv_table[m_reg[4]]; - else if (!(offset < 0xf00)) - m_reg[4] = data; - else if (!(offset < 0x700)) - prg32(((data >> 3) & 0x02) | (data & 0x01)); -} - -READ8_MEMBER(nes_gouder_device::read_l) -{ - LOG_MMC(("gouder read_l, offset: %04x\n", offset)); - - if (!(offset < 0x1700)) - return m_reg[offset & 0x03]; - - return 0x00; -} - -/* writes to 0x8000-0xffff are like MMC3 but no PRG bankswitch (beacuse it is handled by low writes) */ -void nes_gouder_device::prg_cb(int start, int bank) -{ - return; -} - - -/*------------------------------------------------- - - UNL-SA-9602B - - Sachen boards used for a chinese port of Princess Maker (?) - - in MESS: Very Preliminary support, based on Cah4e3 - code in FCEUMM - - -------------------------------------------------*/ - -void nes_sa9602b_device::prg_cb(int start, int bank) -{ - if (m_prg_chip == 3) - { - printf("Accessing PRG beyond end of ROM!\n"); - m_prg_chip = 2; // assume that the higher PRG chip is mirrored twice - } - prg8_x(start, (m_prg_chip * 0x40) | (bank & 0x3f)); - - if (m_latch & 0x40) - prg8_89(0x3e); - else - prg8_cd(0x3e); - - prg8_ef(0x3f); -// printf("start %d, bank %d\n", start, bank); -} - - -WRITE8_MEMBER( nes_sa9602b_device::write_h ) -{ - LOG_MMC(("sa9602b write_h, offset: %04x, data: %02x\n", offset, data)); - - switch (offset & 0x6001) - { - case 0x0000: - m_reg = data; - break; - case 0x0001: - if ((m_reg & 7) < 6) - m_prg_chip = (data & 0xc0) >> 6; - set_prg(0, m_prg_mask); - break; - } - - txrom_write(space, offset, data, mem_mask); -} - -/*------------------------------------------------- - - UNL-SHERO - - Sachen boards used for Street Heroes - - in MESS: Very Preliminary support - - -------------------------------------------------*/ - - -void nes_sachen_shero_device::chr_cb( int start, int bank, int source ) -{ - int shift = start < 2 ? 5 : - start < 4 ? 6 : - start < 6 ? 8 : 7; - if (!BIT(m_reg, 6)) - chr1_x(start, ((m_reg << shift) & 0x100) | bank, source); -} - - -WRITE8_MEMBER( nes_sachen_shero_device::write_l ) -{ - LOG_MMC(("shero write_l, offset: %04x, data: %02x\n", offset, data)); - offset += 0x4100; - - if (offset == 0x4100) - { - m_reg = data; - if (BIT(m_reg, 6)) - chr8(0, CHRRAM); - else - set_chr(m_chr_source, m_chr_base, m_chr_mask); - } -} - -READ8_MEMBER( nes_sachen_shero_device::read_l ) -{ - LOG_MMC(("shero read_l, offset: %04x\n", offset)); - offset += 0x4100; - - if (offset == 0x4100) - { - // DSW read! - } - return m_open_bus; // open bus -} - - - -/*------------------------------------------------- - - MULTIGAME CARTS BASED ON MMC3 - - -------------------------------------------------*/ - - /*------------------------------------------------- - - Board BMC-FK23C - - MMC3 clone - - In MESS: partially supported (still to sort initial banking - for many games) - - -------------------------------------------------*/ - -#if 0 -// alt version... -void nes_fk23c_device::prg_cb(int start, int bank) -{ - if (((m_reg[0] & 0x07) - 3) > 1 && (!(m_reg[3] & 0x02) || start < 2)) - { - if (m_reg[0] & 0x03) - bank = (bank & (0x3f >> (m_reg[0] & 0x03))) | (m_reg[1] << 1); - - prg8_x(start, bank); - } -} - -void nes_fk23c_device::chr_cb(int start, int bank, int source) -{ - if (!(m_reg[0] & 0x40) && (!(m_reg[3] & 0x02) || (start != 1 && start != 3))) - chr1_x(start, ((m_reg[2] & 0x7f) << 3) | bank, source); -} - -#endif - -void nes_fk23c_device::prg_cb(int start, int bank) -{ - UINT8 mask = (0x3f >> (m_reg[0] & 0x03)); - - if ((m_reg[0] & 0x07) < 3) - { - if (!(m_reg[0] & 0x03)) - bank = (bank & mask) | ((m_reg[1] & (0x7f ^ mask)) << 1); - - prg8_x(start, bank); - } -} - -void nes_fk23c_device::chr_cb(int start, int bank, int source) -{ - if (!(m_reg[0] & 0x40) && (!(m_reg[3] & 0x02) || (start != 1 && start != 3))) - chr1_x(start, ((m_reg[2] & 0x7f) << 3) | bank, source); -} - -void nes_fk23c_device::fk23c_set_prg() -{ - if ((m_reg[0] & 0x07) == 4) - prg32((m_reg[1] & 0x7f) >> 1); - else if ((m_reg[0] & 0x07) == 3) - { - prg16_89ab(m_reg[1] & 0x7f); - prg16_cdef(m_reg[1] & 0x7f); - } - else - { - if (m_reg[3] & 0x02) - { - prg8_cd(m_reg[4]); - prg8_ef(m_reg[5]); - } - else - set_prg(m_prg_base, m_prg_mask); - } -} - -void nes_fk23c_device::fk23c_set_chr() -{ - if (m_reg[0] & 0x40) - chr8(m_reg[2] | m_mmc_cmd1, m_chr_source); - else - { - if (m_reg[3] & 0x02) - { - int base = (m_reg[2] & 0x7f) << 3; - chr1_x(1, base | m_reg[6], m_chr_source); - chr1_x(3, base | m_reg[7], m_chr_source); - } - else - set_chr(m_chr_source, m_chr_base, m_chr_mask); - } -} - -WRITE8_MEMBER(nes_fk23c_device::write_l) -{ - LOG_MMC(("fk23c write_l, offset: %04x, data: %02x\n", offset, data)); - offset += 0x100; - - if (offset >= 0x1000) - { - if (offset & (1 << 4)) // here it should be (4 + m_mmc_dipsetting) - { - m_reg[offset & 0x03] = data; - - fk23c_set_prg(); - fk23c_set_chr(); - } - } -} - -WRITE8_MEMBER(nes_fk23c_device::write_h) -{ - LOG_MMC(("fk23c write_h, offset: %04x, data: %02x\n", offset, data)); - - if (m_reg[0] & 0x40) - { - if (m_reg[0] & 0x30) - m_mmc_cmd1 = 0; - else - { - m_mmc_cmd1 = data & 0x03; - fk23c_set_chr(); - } - } - else - { - switch (offset & 0x6001) - { - case 0x0001: - if ((m_reg[3] & 0x02) && (m_latch & 0x08)) - { - m_reg[4 | (m_latch & 0x03)] = data; - fk23c_set_prg(); - fk23c_set_chr(); - } - else - txrom_write(space, offset, data, mem_mask); - break; - - case 0x2000: - set_nt_mirroring(data ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); - break; - - default: - txrom_write(space, offset, data, mem_mask); - break; - } - } -} - -/*------------------------------------------------- - - Board BMC-SUPER24IN1SC03 - - Games: Super 24-in-1 - - In MESS: Partially Supported - - -------------------------------------------------*/ - -void nes_s24in1sc03_device::prg_cb(int start, int bank) -{ - static const UINT8 masks[8] = {0x3f, 0x1f, 0x0f, 0x01, 0x03, 0x00, 0x00, 0x00}; - int prg_base = m_reg[1] << 1; - int prg_mask = masks[m_reg[0] & 0x07]; - - bank = prg_base | (bank & prg_mask); - prg8_x(start, bank); -} - -void nes_s24in1sc03_device::chr_cb(int start, int bank, int source) -{ - UINT8 chr = BIT(m_reg[0], 5) ? CHRRAM : CHRROM; - int chr_base = (m_reg[2] << 3) & 0xf00; - - chr1_x(start, chr_base | bank, chr); -} - -WRITE8_MEMBER(nes_s24in1sc03_device::write_l) -{ - LOG_MMC(("s24in1sc03 write_l, offset: %04x, data: %02x\n", offset, data)); - offset += 0x100; - - if (offset == 0x1ff0) - { - m_reg[0] = data; - set_chr(m_chr_source, m_chr_base, m_chr_mask); - set_prg(m_prg_base, m_prg_mask); - } - - if (offset == 0x1ff1) - { - m_reg[1] = data; - set_prg(m_prg_base, m_prg_mask); - } - - if (offset == 0x1ff2) - { - m_reg[2] = data; - set_chr(m_chr_source, m_chr_base, m_chr_mask); - } -} - -/*------------------------------------------------- - - BMC-15IN1 - - Unknown Bootleg Multigame Board - Games: 3 in 1, 15 in 1 - - iNES: mapper 205, MMC3 clone - - In MESS: Supported. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_bmc_15in1_device::write_m) -{ - LOG_MMC(("bmc_15in1 write_m, offset: %04x, data: %02x\n", offset, data)); - - if (offset & 0x0800) - { - m_prg_base = (data & 0x03) << 4; - m_prg_mask = (data & 0x02) ? 0x0f : 0x1f; - m_chr_base = (data & 0x03) << 7; - m_chr_mask = (data & 0x02) ? 0x7f : 0xff; - set_prg(m_prg_base, m_prg_mask); - set_chr(m_chr_source, m_chr_base, m_chr_mask); - } -} - -/*------------------------------------------------- - - BMC-SUPERBIG-7IN1 - - Known Boards: Unknown Multigame Bootleg Board - Games: Kunio 8 in 1, Super Big 7 in 1 - - iNES: mapper 44 - - In MESS: Supported. It also uses mmc3_irq. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_bmc_sbig7_device::write_h) -{ - UINT8 page; - LOG_MMC(("bmc_sbig7 write_h, offset: %04x, data: %02x\n", offset, data)); - - switch (offset & 0x6001) - { - case 0x2001: /* $a001 - Select 128K ROM/VROM base (0..5) or last 256K ROM/VRAM base (6) */ - page = (data & 0x07); - if (page > 6) - page = 6; - - m_prg_base = page << 4; - m_prg_mask = (page > 5) ? 0x1f : 0x0f; - m_chr_base = page << 7; - m_chr_mask = (page > 5) ? 0xff : 0x7f; - set_prg(m_prg_base, m_prg_mask); - set_chr(m_chr_source, m_chr_base, m_chr_mask); - break; - - default: - txrom_write(space, offset, data, mem_mask); - break; - } -} - -/*------------------------------------------------- - - BMC-HIK8IN1 - - Known Boards: Unknown Multigame Bootleg Board - Games: Street Fighter V, various multigame carts - - iNES: mapper 45 - - In MESS: Supported. It also uses mmc3_irq. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_bmc_hik8_device::write_m) -{ - LOG_MMC(("bmc_hik8 write_m, offset: %04x, data: %02x\n", offset, data)); - - /* This bit is the "register lock". Once register are locked, writes go to WRAM - and there is no way to unlock them (except by resetting the machine) */ - if ((m_reg[3] & 0x40) && !m_prgram.empty()) - m_prgram[offset] = data; - else - { - m_reg[m_count] = data; - m_count = (m_count + 1) & 0x03; - - if (!m_count) - { - LOG_MMC(("bmc_hik8 write_m, command completed %02x %02x %02x %02x\n", m_reg[3], - m_reg[2], m_reg[1], m_reg[0])); - - m_prg_base = m_reg[1]; - m_prg_mask = 0x3f ^ (m_reg[3] & 0x3f); - m_chr_base = ((m_reg[2] & 0xf0) << 4) | m_reg[0]; - if (BIT(m_reg[2], 3)) - m_chr_mask = (1 << ((m_reg[2] & 7) + 1)) - 1; - else if (m_reg[2]) - m_chr_mask = 0; - else - m_chr_mask = 0xff; // i.e. we use the vrom_bank with no masking - - set_prg(m_prg_base, m_prg_mask); - set_chr(m_chr_source, m_chr_base, m_chr_mask); - } - } -} - -/*------------------------------------------------- - - BMC-SUPERHIK-4IN1 - - Known Boards: Unknown Multigame Bootleg Board - Games: Super HIK 4 in 1 - - iNES: mapper 49 - - In MESS: Supported. It also uses mmc3_irq. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_bmc_hik4_device::write_m) -{ - LOG_MMC(("bmc_hik4 write_m, offset: %04x, data: %02x\n", offset, data)); - - /* mid writes only work when WRAM is enabled. not sure if I should - change the condition to m_mmc_latch2==0x80 (i.e. what is the effect of - the read-only bit?) */ - if (m_wram_protect & 0x80) - { - if (data & 0x01) /* if this is 0, then we have 32k PRG blocks */ - { - m_prg_base = (data & 0xc0) >> 2; - m_prg_mask = 0x0f; - set_prg(m_prg_base, m_prg_mask); - } - else - prg32((data & 0x30) >> 4); - - m_chr_base = (data & 0xc0) << 1; - m_chr_mask = 0x7f; - set_chr(m_chr_source, m_chr_base, m_chr_mask); - } -} - -/*------------------------------------------------- - - BMC-MARIOPARTY-7IN1 - - Known Boards: Unknown Multigame Bootleg Board - Games: Mario 7 in 1 - - MMC3 clone - - iNES: mapper 52 - - In MESS: Supported. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_bmc_mario7in1_device::write_m) -{ - UINT8 helper1, helper2; - LOG_MMC(("bmc_mario7in1 write_m, offset: %04x, data: %02x\n", offset, data)); - - /* mid writes only work when WRAM is enabled. not sure if I should - change the condition to m_map52_reg_written == 0x80 (i.e. what is the effect of - the read-only bit?) and it only can happen once! */ - if ((m_wram_protect & 0x80) && !m_reg_written) - { - helper1 = (data & 0x08); - helper2 = (data & 0x40); - - m_prg_base = helper1 ? ((data & 0x07) << 4) : ((data & 0x06) << 4); - m_prg_mask = helper1 ? 0x0f : 0x1f; - m_chr_base = ((data & 0x20) << 4) | ((data & 0x04) << 6) | (helper2 ? ((data & 0x10) << 3) : 0); - m_chr_mask = helper2 ? 0x7f : 0xff; - set_prg(m_prg_base, m_prg_mask); - set_chr(m_chr_source, m_chr_base, m_chr_mask); - - m_reg_written = 1; - } - else - m_prgram[offset] = data; -} - -/*------------------------------------------------- - - BMC-GOLD-7IN1 - - Known Boards: Unknown Multigame Bootleg Board - Games: Super HIK Gold 7 in 1, Golden 7 in 1 and many more - - MMC3 clone, same as BMC-MARIOPARTY-7IN1 but with switched CHR - bank lines - - iNES: mapper 52 - - In MESS: Supported. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_bmc_gold7in1_device::write_m) -{ - UINT8 helper1, helper2; - LOG_MMC(("bmc_gold7in1 write_m, offset: %04x, data: %02x\n", offset, data)); - - if ((m_wram_protect & 0x80) && !m_reg_written) - { - helper1 = (data & 0x08); - helper2 = (data & 0x40); - - m_prg_base = helper1 ? ((data & 0x07) << 4) : ((data & 0x06) << 4); - m_prg_mask = helper1 ? 0x0f : 0x1f; - m_chr_base = ((data & 0x20) << 3) | ((data & 0x04) << 7) | (helper2 ? ((data & 0x10) << 3) : 0); - m_chr_mask = helper2 ? 0x7f : 0xff; - set_prg(m_prg_base, m_prg_mask); - set_chr(m_chr_source, m_chr_base, m_chr_mask); - - m_reg_written = BIT(data, 7); // mc_2hikg & mc_s3nt3 write here multiple time - } - else - m_prgram[offset] = data; -} - -/*------------------------------------------------- - - BMC-GOLDENCARD-6IN1 - - Known Boards: Unknown Bootleg Multigame Board - Games: Golden Card 6 in 1 - - MMC3 clone - - iNES: mapper 217 - - In MESS: Supported. - - -------------------------------------------------*/ - -void nes_bmc_gc6in1_device::prg_cb(int start, int bank) -{ - if (m_reg[1] & 0x08) - bank &= 0x1f; - else - { - bank &= 0x0f; - bank |= m_reg[1] & 0x10; - } - - prg8_x(start, bank | ((m_reg[1] & 0x03) << 5)); -} - -void nes_bmc_gc6in1_device::chr_cb(int start, int bank, int source) -{ - if (!(m_reg[1] & 0x08)) - bank = ((m_reg[1] & 0x10) << 3) | (bank & 0x7f); - - - bank |= ((m_reg[1] << 6) & 0x100); - chr1_x(start, ((m_reg[1] & 0x03) << 8) | bank, source); -} - -WRITE8_MEMBER(nes_bmc_gc6in1_device::write_l) -{ - UINT8 bank; - LOG_MMC(("bmc_gc6in1 write_l, offset: %04x, data: %02x\n", offset, data)); - offset += 0x100; - - if (offset == 0x1000) - { - m_reg[0] = data; - if (data & 0x80) - { - bank = (data & 0x0f) | ((m_reg[1] & 0x03) << 4); - prg16_89ab(bank); - prg16_cdef(bank); - } - else - set_prg(m_prg_base, m_prg_mask); - } - else if (offset == 0x1001) - { - m_reg[1] = data; - set_prg(m_prg_base, m_prg_mask); - } - else if (offset == 0x1007) - { - m_reg[2] = data; - } -} - -WRITE8_MEMBER(nes_bmc_gc6in1_device::write_h) -{ - UINT8 cmd; - static const UINT8 conv_table[8] = {0, 6, 3, 7, 5, 2, 4, 1}; - LOG_MMC(("bmc_gc6in1 write_h, offset: %04x, data: %02x\n", offset, data)); - - if (!m_reg[2]) - { - // in this case we act like MMC3, only with alt prg/chr handlers - txrom_write(space, offset, data, mem_mask); - } - else - { - switch (offset & 0x6001) - { - case 0x0000: - txrom_write(space, 0x4000, data, mem_mask); - break; - - case 0x0001: - data = (data & 0xc0) | conv_table[data & 0x07]; - m_reg[3] = 1; - txrom_write(space, 0x0000, data, mem_mask); - break; - - case 0x2000: - cmd = m_latch & 0x07; - if (m_reg[3]) - { - m_reg[3] = 0; - switch (cmd) - { - case 0: case 1: // these do not need to be separated: we take care of them in set_chr! - case 2: case 3: case 4: case 5: - m_mmc_vrom_bank[cmd] = data; - set_chr(m_chr_source, m_chr_base, m_chr_mask); - break; - case 6: - case 7: - m_mmc_prg_bank[cmd - 6] = data; - set_prg(m_prg_base, m_prg_mask); - break; - } - } - break; - - - case 0x2001: - set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); - break; - - default: - txrom_write(space, offset, data, mem_mask); - break; - } - } -} - -/*------------------------------------------------- - - BMC-411120C - - - MMC3 clone - - - In MESS: Very Preliminary Support - - -------------------------------------------------*/ - -void nes_bmc_411120c_device::prg_cb(int start, int bank) -{ - if (m_reg & 8) // & 0xc when DSW change (diff menu?) - prg32(((m_reg >> 4) & 3) | 0x0c); - else - prg8_x(start, (bank & 0x0f) | ((m_reg & 0x03) << 4)); -} - -void nes_bmc_411120c_device::chr_cb(int start, int bank, int source) -{ - chr1_x(start, bank | ((m_reg & 3) << 7), source); -} - -WRITE8_MEMBER(nes_bmc_411120c_device::write_m) -{ - LOG_MMC(("bmc_411120c write_m, offset: %04x, data: %02x\n", offset, data)); - - m_reg = data; - set_prg(m_prg_base, m_prg_mask); - set_chr(m_chr_source, m_chr_base, m_chr_mask); -} - -/*------------------------------------------------- - - BMC-830118C - - - MMC3 clone - - - In MESS: Very Preliminary Support - - -------------------------------------------------*/ - -void nes_bmc_830118c_device::prg_cb(int start, int bank) -{ - if ((m_reg & 0x0c) != 0x0c) - prg8_x(start, (bank & 0x0f) | ((m_reg & 0x0c) << 2)); - else - { - if (start == 0) - { - prg8_89((bank & 0x0f) | ((m_reg & 0x0c) << 2)); - prg8_ab((bank & 0x0f) | 0x20); - } - else if (start == 2) - { - prg8_cd((bank & 0x0f) | ((m_reg & 0x0c) << 2)); - prg8_ef((bank & 0x0f) | 0x20); - } - } -} - -void nes_bmc_830118c_device::chr_cb(int start, int bank, int source) -{ - chr1_x(start, (bank & 0x7f) | ((m_reg & 0x0c) << 5), source); -} - -WRITE8_MEMBER(nes_bmc_830118c_device::write_m) -{ - LOG_MMC(("bmc_830118c write_m, offset: %04x, data: %02x\n", offset, data)); - - if (offset >= 0x800 && offset < 0x900) - { - m_reg = data; - set_prg(m_prg_base, m_prg_mask); - set_chr(m_chr_source, m_chr_base, m_chr_mask); - } -} - -/*------------------------------------------------- - - BMC-POWERJOY - - -------------------------------------------------*/ - -void nes_pjoy84_device::prg_cb(int start, int bank) -{ - UINT8 flip = (m_latch & 0x40) ? 2 : 0; - - if (!(m_reg[3] & 0x03)) - prg8_x(start, bank); - else if (start == flip) - { - if ((m_reg[3] & 0x03) == 0x03) - prg32(bank >> 2); - else - { - prg16_89ab(bank >> 1); - prg16_cdef(bank >> 1); - } - } -} - -void nes_pjoy84_device::chr_cb(int start, int bank, int source) -{ - if (!(m_reg[3] & 0x10)) - chr1_x(start, bank, source); -} - -inline void nes_pjoy84_device::set_base_mask() -{ - m_prg_base = ((m_reg[0] & (0x06 | BIT(m_reg[0], 6))) << 4) | - (BIT(m_reg[0], 4) << 7); - - m_chr_base = ((~m_reg[0] << 0) & 0x080 & m_reg[2]) | - ((m_reg[0] << 4) & 0x080 & m_reg[0]) | - ((m_reg[0] << 3) & 0x100) | - ((m_reg[0] << 5) & 0x200); - - m_prg_mask = BIT(m_reg[0], 6) ? 0x0f : 0x1f; - m_chr_mask = BIT(m_reg[0], 7) ? 0x7f : 0xff; -} - -WRITE8_MEMBER(nes_pjoy84_device::write_m) -{ - LOG_MMC(("pjoy84 write_m, offset: %04x, data: %02x\n", offset, data)); - - switch (offset & 0x03) - { - case 0x00: - case 0x03: - if (m_reg[3] & 0x80) - return; // else we act as if offset & 3 = 1,2 - case 0x01: - case 0x02: - m_reg[offset & 0x03] = data; - set_base_mask(); - if (m_reg[3] & 0x10) - chr8((m_chr_base >> 3) | (m_reg[2] & 0x0f), m_chr_source); - else - set_chr(m_chr_source, m_chr_base, m_chr_mask); - set_prg(m_prg_base, m_prg_mask); - break; - } -} - -#ifdef UNUSED_FUNCTION -/*------------------------------------------------- - - UNL-A9746 - - - MMC3 clone - - - Preliminary emulation based on Cah4e3's code - No dump is available (yet) for this. - - -------------------------------------------------*/ - -void nes_a9746_device::device_start() -{ - mmc3_start(); - save_item(NAME(m_reg)); -} - -void nes_a9746_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - - m_reg[0] = 0; - m_reg[1] = 0; - m_reg[2] = 0; - mmc3_common_initialize(0x7f, 0xff, 0); -} - -void nes_a9746_device::update_banks(UINT8 value) -{ - UINT8 bank = BITSWAP8(value & 0x3c,7,6,0,1,2,3,4,5); - - switch (m_reg[0]) - { - case 0x26: prg8_89(bank); break; - case 0x25: prg8_ab(bank); break; - case 0x24: prg8_cd(bank); break; - case 0x23: prg8_ef(bank); break; - } - - switch (m_reg[1]) - { - case 0x08: case 0x0a: case 0x0c: case 0x0e: - case 0x10: case 0x12: case 0x14: case 0x16: - case 0x18: case 0x1a: case 0x1c: case 0x1e: - m_reg[2] = (value << 4); - break; - case 0x09: chr1_0(m_reg[2] | (value >> 1), m_chr_source); break; - case 0x0b: chr1_1(m_reg[2] | (value >> 1) | 1, m_chr_source); break; - case 0x0d: chr1_2(m_reg[2] | (value >> 1), m_chr_source); break; - case 0x0f: chr1_3(m_reg[2] | (value >> 1) | 1, m_chr_source); break; - case 0x11: chr1_4(m_reg[2] | (value >> 1), m_chr_source); break; - case 0x15: chr1_5(m_reg[2] | (value >> 1), m_chr_source); break; - case 0x19: chr1_6(m_reg[2] | (value >> 1), m_chr_source); break; - case 0x1d: chr1_7(m_reg[2] | (value >> 1), m_chr_source); break; - } -} - -WRITE8_MEMBER(nes_a9746_device::write_h) -{ - LOG_MMC(("unl_a9746 write_h, offset: %04x, data: %02x\n", offset, data)); - - switch (offset & 0x6003) - { - case 0x0000: - m_reg[1] = data; - m_reg[0] = 0; - break; - case 0x0001: - update_banks(data); - break; - case 0x0002: - m_reg[0] = data; - m_reg[1] = 0; - break; - - case 0x0003: - case 0x2000: - case 0x2001: - case 0x2002: - case 0x2003: - break; - - default: - txrom_write(space, offset, data, mem_mask); - break; - } -} -#endif diff --git a/src/devices/bus/nes/mmc3_clones.cpp b/src/devices/bus/nes/mmc3_clones.cpp new file mode 100644 index 00000000000..4a806d0fde2 --- /dev/null +++ b/src/devices/bus/nes/mmc3_clones.cpp @@ -0,0 +1,2588 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for MMC-3 clone PCBs + + + Here we emulate several pirate PCBs based on MMC-3 boards + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "mmc3_clones.h" + + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_NITRA = &device_creator; +const device_type NES_KS7057 = &device_creator; +const device_type NES_SBROS11 = &device_creator; +const device_type NES_MALISB = &device_creator; +const device_type NES_FAMILY4646 = &device_creator; +const device_type NES_PIKAY2K = &device_creator; +const device_type NES_8237 = &device_creator; +const device_type NES_SG_LIONK = &device_creator; +const device_type NES_SG_BOOG = &device_creator; +const device_type NES_KASING = &device_creator; +const device_type NES_KAY = &device_creator; +const device_type NES_H2288 = &device_creator; +const device_type NES_6035052 = &device_creator; +const device_type NES_TXC_TW = &device_creator; +const device_type NES_KOF97 = &device_creator; +const device_type NES_KOF96 = &device_creator; +const device_type NES_SF3 = &device_creator; +const device_type NES_GOUDER = &device_creator; +const device_type NES_SA9602B = &device_creator; +const device_type NES_SACHEN_SHERO = &device_creator; +//const device_type NES_A9746 = &device_creator; + +const device_type NES_FK23C = &device_creator; +const device_type NES_FK23CA = &device_creator; +const device_type NES_S24IN1SC03 = &device_creator; +const device_type NES_BMC_15IN1 = &device_creator; +const device_type NES_BMC_SBIG7 = &device_creator; +const device_type NES_BMC_HIK8 = &device_creator; +const device_type NES_BMC_HIK4 = &device_creator; +const device_type NES_BMC_MARIO7IN1 = &device_creator; +const device_type NES_BMC_GOLD7IN1 = &device_creator; +const device_type NES_BMC_GC6IN1 = &device_creator; +const device_type NES_BMC_411120C = &device_creator; +const device_type NES_BMC_830118C = &device_creator; +const device_type NES_PJOY84 = &device_creator; + + +nes_nitra_device::nes_nitra_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_NITRA, "NES Cart Nitra PCB", tag, owner, clock, "nes_nitra", __FILE__) +{ +} + +nes_ks7057_device::nes_ks7057_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_KS7057, "NES Cart KS-7057 PCB", tag, owner, clock, "nes_ks7057", __FILE__) +{ +} + +nes_sbros11_device::nes_sbros11_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_SBROS11, "NES Cart SMB 11 PCB", tag, owner, clock, "nes_smb11", __FILE__) +{ +} + +nes_malisb_device::nes_malisb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_MALISB, "NES Cart Mali Spash Bomb PCB", tag, owner, clock, "nes_malisb", __FILE__) +{ +} + +nes_family4646_device::nes_family4646_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_FAMILY4646, "NES Cart BMC-FAMILY-4646 PCB", tag, owner, clock, "nes_family4646", __FILE__) +{ +} + +nes_pikay2k_device::nes_pikay2k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_PIKAY2K, "NES Cart PIKACHU Y2K PCB", tag, owner, clock, "nes_pikay2k", __FILE__) +{ +} + +nes_8237_device::nes_8237_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_8237, "NES Cart UNL-8237 PCB", tag, owner, clock, "nes_8237", __FILE__) +{ +} + +nes_sglionk_device::nes_sglionk_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_SG_LIONK, "NES Cart SuperGame Lion King PCB", tag, owner, clock, "nes_sglionk", __FILE__) +{ +} + +nes_sgboog_device::nes_sgboog_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_SG_BOOG, "NES Cart SuperGame BoogerMan PCB", tag, owner, clock, "nes_sgbooger", __FILE__) +{ +} + +nes_kasing_device::nes_kasing_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_KASING, "NES Cart Kasing PCB", tag, owner, clock, "nes_kasing", __FILE__) +{ +} + +nes_kay_device::nes_kay_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_KAY, "NES Cart KAY PCB", tag, owner, clock, "nes_kay", __FILE__) +{ +} + +nes_h2288_device::nes_h2288_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_H2288, "NES Cart H-2288 PCB", tag, owner, clock, "nes_h2288", __FILE__) +{ +} + +nes_6035052_device::nes_6035052_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_6035052, "NES Cart UNL-603-5052 PCB", tag, owner, clock, "nes_6035052", __FILE__) +{ +} + +nes_txc_tw_device::nes_txc_tw_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_TXC_TW, "NES Cart TXC Thunder Warrior PCB", tag, owner, clock, "nes_txc_tw", __FILE__) +{ +} + +nes_kof97_device::nes_kof97_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_KOF97, "NES Cart KOF 97 PCB", tag, owner, clock, "nes_kof97", __FILE__) +{ +} + +nes_kof96_device::nes_kof96_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_KOF96, "NES Cart KOF 96 PCB", tag, owner, clock, "nes_kof96", __FILE__) +{ +} + +nes_sf3_device::nes_sf3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_SF3, "NES Cart Super Fighter III PCB", tag, owner, clock, "nes_sf3", __FILE__) +{ +} + +nes_gouder_device::nes_gouder_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_GOUDER, "NES Cart Gouder PCB", tag, owner, clock, "nes_gouder", __FILE__) +{ +} + +nes_sa9602b_device::nes_sa9602b_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_SA9602B, "NES Cart SA-9602B PCB", tag, owner, clock, "nes_sa9602b", __FILE__) +{ +} + +nes_sachen_shero_device::nes_sachen_shero_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_SACHEN_SHERO, "NES Cart Street Hero PCB", tag, owner, clock, "nes_shero", __FILE__) +{ +} + +//nes_a9746_device::nes_a9746_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) +// : nes_txrom_device(mconfig, NES_A9746, "NES Cart A-9746 PCB", tag, owner, clock, "nes_bmc_a9746", __FILE__) +//{ +//} + +nes_fk23c_device::nes_fk23c_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : nes_txrom_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +nes_fk23c_device::nes_fk23c_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_FK23C, "NES Cart FK23C PCB", tag, owner, clock, "nes_fk23c", __FILE__) +{ +} + +nes_fk23ca_device::nes_fk23ca_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_fk23c_device(mconfig, NES_FK23CA, "NES Cart FK23CA PCB", tag, owner, clock, "nes_fk23ca", __FILE__) +{ +} + +nes_s24in1sc03_device::nes_s24in1sc03_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_S24IN1SC03, "NES Cart Super 24 in 1 SC-03 PCB", tag, owner, clock, "nes_s24in1c03", __FILE__) +{ +} + +nes_bmc_15in1_device::nes_bmc_15in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_BMC_15IN1, "NES Cart BMC 15 in 1 PCB", tag, owner, clock, "nes_bmc_15in1", __FILE__) +{ +} + +nes_bmc_sbig7_device::nes_bmc_sbig7_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_BMC_SBIG7, "NES Cart BMC Super BIG 7 in 1 PCB", tag, owner, clock, "nes_bmc_sbit7", __FILE__) +{ +} + +nes_bmc_hik8_device::nes_bmc_hik8_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_BMC_HIK8, "NES Cart BMC Super HIK 8 in 1 PCB", tag, owner, clock, "nes_bmc_hik8", __FILE__) +{ +} + +nes_bmc_hik4_device::nes_bmc_hik4_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_BMC_HIK4, "NES Cart BMC Super HIK 4 in 1 PCB", tag, owner, clock, "nes_bmc_hik4", __FILE__) +{ +} + +nes_bmc_mario7in1_device::nes_bmc_mario7in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_BMC_MARIO7IN1, "NES Cart BMC Mario 7 in 1 PCB", tag, owner, clock, "nes_bmc_mario7in1", __FILE__) +{ +} + +nes_bmc_gold7in1_device::nes_bmc_gold7in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_BMC_GOLD7IN1, "NES Cart BMC Golden 7 in 1 PCB", tag, owner, clock, "nes_bmc_gold7in1", __FILE__) +{ +} + +nes_bmc_gc6in1_device::nes_bmc_gc6in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_BMC_GC6IN1, "NES Cart BMC Golden Card 6 in 1 PCB", tag, owner, clock, "nes_bmc_gc6in1", __FILE__) +{ +} + +nes_bmc_411120c_device::nes_bmc_411120c_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_BMC_411120C, "NES Cart BMC 411120C PCB", tag, owner, clock, "nes_bmc_411120c", __FILE__) +{ +} + +nes_bmc_830118c_device::nes_bmc_830118c_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_BMC_830118C, "NES Cart BMC 830118C PCB", tag, owner, clock, "nes_bmc_830118c", __FILE__) +{ +} + +nes_pjoy84_device::nes_pjoy84_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_PJOY84, "NES Cart Powerjoy 84 PCB", tag, owner, clock, "nes_pjoy84", __FILE__) +{ +} + + + +void nes_family4646_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + mmc3_common_initialize(0x1f, 0xff, 0); +} + +void nes_pikay2k_device::device_start() +{ + mmc3_start(); + save_item(NAME(m_reg)); +} + +void nes_pikay2k_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + + m_reg[0] = 0xff; + m_reg[1] = 0; + mmc3_common_initialize(0xff, 0xff, 0); +} + +void nes_8237_device::device_start() +{ + mmc3_start(); + save_item(NAME(m_reg)); + save_item(NAME(m_cd_enable)); +} + +void nes_8237_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + + m_reg[0] = 0; + m_reg[1] = 0; + m_reg[2] = 0; + m_cd_enable = 0; + mmc3_common_initialize(0xff, 0xff, 0); +} + +void nes_sglionk_device::device_start() +{ + mmc3_start(); + save_item(NAME(m_reg)); + save_item(NAME(m_reg_enabled)); +} + +void nes_sglionk_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + + m_reg = m_reg_enabled = 0; + mmc3_common_initialize(0xff, 0xff, 0); +} + +void nes_sgboog_device::device_start() +{ + mmc3_start(); + save_item(NAME(m_reg)); + save_item(NAME(m_mode)); +} + +void nes_sgboog_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + + m_mode = 0x04; + m_reg[0] = 0x00; + m_reg[1] = 0xff; + m_reg[2] = 0; + mmc3_common_initialize(0x1f, 0xff, 0); + set_prg(m_prg_base, m_prg_mask); + set_chr(m_chr_source, m_chr_base, m_chr_mask); +} + +void nes_kasing_device::device_start() +{ + mmc3_start(); + save_item(NAME(m_reg)); +} + +void nes_kasing_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + + m_reg = 0; + mmc3_common_initialize(0xff, 0xff, 0); +} + + +void nes_kay_device::device_start() +{ + mmc3_start(); + save_item(NAME(m_low_reg)); + save_item(NAME(m_reg)); +} + +void nes_kay_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + + memset(m_reg, 0, sizeof(m_reg)); + m_low_reg = 0; + mmc3_common_initialize(0xff, 0xff, 0); +} + + +void nes_h2288_device::device_start() +{ + mmc3_start(); + save_item(NAME(m_reg)); +} + +void nes_h2288_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + + m_reg[0] = 0; + m_reg[1] = 0; + mmc3_common_initialize(0xff, 0xff, 0); +} + +void nes_6035052_device::device_start() +{ + mmc3_start(); + save_item(NAME(m_prot)); +} + +void nes_6035052_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + mmc3_common_initialize(0xff, 0xff, 0); + + m_prot = 0; +} + +void nes_kof96_device::device_start() +{ + mmc3_start(); + save_item(NAME(m_reg)); +} + +void nes_kof96_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + memset(m_reg, 0, sizeof(m_reg)); + mmc3_common_initialize(0xff, 0xff, 0); +} + +void nes_gouder_device::device_start() +{ + mmc3_start(); + save_item(NAME(m_reg)); +} + +void nes_gouder_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + memset(m_reg, 0, sizeof(m_reg)); + mmc3_common_initialize(0xff, 0xff, 0); +} + +void nes_sa9602b_device::device_start() +{ + mmc3_start(); + save_item(NAME(m_reg)); + save_item(NAME(m_prg_chip)); +} + +void nes_sa9602b_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + + m_reg = 0; + m_prg_chip = 0; + mmc3_common_initialize(0x1ff, 0xff, 0); // 1.5MB of PRG-ROM, no CHR-ROM but 32K CHR-RAM +} + +void nes_sachen_shero_device::device_start() +{ + mmc3_start(); + save_item(NAME(m_reg)); +} + +void nes_sachen_shero_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + + m_reg = 0; + mmc3_common_initialize(0xff, 0x1ff, 0); +} + +void nes_fk23c_device::device_start() +{ + mmc3_start(); + save_item(NAME(m_reg)); + save_item(NAME(m_mmc_cmd1)); +} + +void nes_fk23c_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + + m_mmc_cmd1 = 0; + m_reg[0] = 4; + m_reg[1] = 0xff; + m_reg[2] = m_reg[3] = 0; + m_reg[4] = m_reg[5] = m_reg[6] = m_reg[7] = 0xff; + mmc3_common_initialize(0xff, 0xff, 0); + fk23c_set_prg(); + fk23c_set_chr(); + +} + +void nes_fk23ca_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + + m_mmc_cmd1 = 0; + m_reg[0] = m_reg[1] = m_reg[2] = m_reg[3] = 0; + m_reg[4] = m_reg[5] = m_reg[6] = m_reg[7] = 0xff; + mmc3_common_initialize(0xff, 0xff, 0); + fk23c_set_prg(); + fk23c_set_chr(); +} + +void nes_s24in1sc03_device::device_start() +{ + mmc3_start(); + save_item(NAME(m_reg)); +} + +void nes_s24in1sc03_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + + m_reg[0] = 0x24; + m_reg[1] = 0x9f; + m_reg[2] = 0; + mmc3_common_initialize(0xff, 0xff, 0); +} + +void nes_bmc_15in1_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + + mmc3_common_initialize(0x1f, 0xff, 0); + m_prg_base = 0x10; // this board has a diff prg_base + set_prg(m_prg_base, m_prg_mask); +} + +void nes_bmc_sbig7_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + mmc3_common_initialize(0x0f, 0x7f, 0); +} + +void nes_bmc_hik8_device::device_start() +{ + mmc3_start(); + save_item(NAME(m_reg)); + save_item(NAME(m_count)); +} + +void nes_bmc_hik8_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + + m_count = 0; + memset(m_reg, 0, sizeof(m_reg)); + mmc3_common_initialize(0x3f, 0xff, 0); +} + +void nes_bmc_hik4_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + mmc3_common_initialize(0x0f, 0x7f, 0); +} + +void nes_bmc_mario7in1_device::device_start() +{ + mmc3_start(); + save_item(NAME(m_reg_written)); +} + +void nes_bmc_mario7in1_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + + m_reg_written = 0; + mmc3_common_initialize(0x1f, 0xff, 0); +} + +void nes_bmc_gold7in1_device::device_start() +{ + mmc3_start(); + save_item(NAME(m_reg_written)); +} + +void nes_bmc_gold7in1_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + + m_reg_written = 0; + mmc3_common_initialize(0x1f, 0xff, 0); +} + +void nes_bmc_gc6in1_device::device_start() +{ + mmc3_start(); + save_item(NAME(m_reg)); +} + +void nes_bmc_gc6in1_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + + m_reg[0] = 0x00; + m_reg[1] = 0xff; + m_reg[2] = 0x03; + m_reg[3] = 0; + mmc3_common_initialize(0xff, 0xff, 0); + set_prg(m_prg_base, m_prg_mask); + set_chr(m_chr_source, m_chr_base, m_chr_mask); +} + +void nes_bmc_411120c_device::device_start() +{ + mmc3_start(); + save_item(NAME(m_reg)); +} + +void nes_bmc_411120c_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + + m_reg = 0; + mmc3_common_initialize(0x7f, 0x7f, 0); +} + +void nes_bmc_830118c_device::device_start() +{ + mmc3_start(); + save_item(NAME(m_reg)); +} + +void nes_bmc_830118c_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + + m_reg = 0; + mmc3_common_initialize(0x7f, 0x7f, 0); +} + +void nes_pjoy84_device::device_start() +{ + mmc3_start(); + save_item(NAME(m_reg)); +} + +void nes_pjoy84_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + + memset(m_reg, 0, sizeof(m_reg)); + set_base_mask(); + mmc3_common_initialize(m_prg_mask, m_chr_mask, 0); +} + + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + Bootleg Board by Nitra + + Games: Time Diver Avenger + + This acts basically like a MMC3 with different use of write + address. + + iNES: mapper 250 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_nitra_device::write_h) +{ + LOG_MMC(("nitra write_h, offset: %04x, data: %02x\n", offset, data)); + + txrom_write(space, (offset & 0x6000) | ((offset & 0x400) >> 10), offset & 0xff, mem_mask); +} + +/*------------------------------------------------- + + Board UNL-KS7057 + + Games: Street Fighter VI / Fight Street VI + + MMC3 clone (identical, but for switched address lines) + + In MESS: Supported + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_ks7057_device::write_h) +{ + LOG_MMC(("ks7057 write_h, offset: %04x, data: %02x\n", offset, data)); + + offset = (BIT(offset, 0) << 1) | BIT(offset, 1) | (offset & ~0x03); + txrom_write(space, offset, data, mem_mask); +} + +/*------------------------------------------------- + + BTL-SUPERBROS11 + + Games: Super Mario Bros. 11, Super Mario Bros. 17 + + This acts basically like a MMC3 with different use of write + address. + + iNES: mapper 196 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_sbros11_device::write_h) +{ + LOG_MMC(("smb11 write_h, offset: %04x, data: %02x\n", offset, data)); + + txrom_write(space, (offset & 0x6000) | ((offset & 0x04) >> 2), data, mem_mask); +} + +/*------------------------------------------------- + + UNL-MALISB + + Games: Super Mali Bros Splash Bomb + + This is very similar to mapper 196, but with additional + data bit swap. + + In MESS: Supported. + + -------------------------------------------------*/ + +void nes_malisb_device::prg_cb(int start, int bank) +{ + bank = (bank & 3) | ((bank & 8) >> 1) | ((bank & 4) << 1); + prg8_x(start, bank); +} + +void nes_malisb_device::chr_cb(int start, int bank, int source) +{ + bank = (bank & 0xdd) | ((bank & 0x20) >> 4) | ((bank & 2) << 4); + chr1_x(start, bank, source); +} + +WRITE8_MEMBER(nes_malisb_device::write_h) +{ + LOG_MMC(("malisb write_h, offset: %04x, data: %02x\n", offset, data)); + + if (offset > 0x4000) + txrom_write(space, (offset & 0xfffe) | ((offset & 0x04) >> 2) | ((offset & 0x08) >> 3), data, mem_mask); + else + txrom_write(space, (offset & 0xfffe) | ((offset & 0x08) >> 3), data, mem_mask); +} + +/*------------------------------------------------- + + BMC-FAMILY-4646B + + Known Boards: Unknown Multigame Bootleg Board (4646B) + Games: 2 in 1 - Family Kid & Aladdin 4 + + MMC3 clone + + iNES: mapper 134 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_family4646_device::write_m) +{ + LOG_MMC(("family4646 write_m, offset: %04x, data: %02x\n", offset, data)); + + if (offset == 0x01) + { + m_prg_base = (data & 0x02) << 4; + m_prg_mask = 0x1f; + m_chr_base = (data & 0x20) << 3; + m_chr_mask = 0xff; + set_prg(m_prg_base, m_prg_mask); + set_chr(m_chr_source, m_chr_base, m_chr_mask); + } +} + +/*------------------------------------------------- + + BTL-PIKACHUY2K + + Games: Pikachu Y2k + + iNES: mapper 254 + + In MESS: + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_pikay2k_device::write_h) +{ + LOG_MMC(("pikay2k write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x6001) + { + case 0x2001: + m_reg[1] = data; + break; + + case 0x2000: + m_reg[0] = 0; + default: + txrom_write(space, offset, data, mem_mask); + break; + } +} + +// strange WRAM usage: it is protected at start, and gets unprotected after the first write to 0xa000 +WRITE8_MEMBER(nes_pikay2k_device::write_m) +{ + LOG_MMC(("pikay2k write_m, offset: %04x, data: %02x\n", offset, data)); + + m_prgram[offset & 0x1fff] = data; +} + +READ8_MEMBER(nes_pikay2k_device::read_m) +{ + LOG_MMC(("pikay2k read_m, offset: %04x\n", offset)); + + return m_prgram[offset & 0x1fff] ^ (m_reg[0] & m_reg[1]); +} + +/*------------------------------------------------- + + Board UNL-8237 + + Games: Pocahontas 2 + + MMC3 clone + + In MESS: Supported + + -------------------------------------------------*/ + +void nes_8237_device::prg_cb(int start, int bank) +{ + if (!(m_reg[0] & 0x80)) + prg8_x(start, bank); +} + +void nes_8237_device::chr_cb(int start, int bank, int source) +{ + bank |= ((m_reg[1] << 6) & 0x100); + chr1_x(start, bank, source); +} + +WRITE8_MEMBER(nes_8237_device::write_l) +{ + LOG_MMC(("unl_8237 write_l, offset: %04x, data: %02x\n", offset, data)); + offset += 0x100; + + if (offset == 0x1000) + { + m_reg[0] = data; + if (m_reg[0] & 0x80) + { + if (m_reg[0] & 0x20) + prg32((m_reg[0] & 0x0f) >> 1); + else + { + prg16_89ab(m_reg[0] & 0x1f); + prg16_cdef(m_reg[0] & 0x1f); + } + } + else + set_prg(m_prg_base, m_prg_mask); + } + + if (offset == 0x1001) + { + m_reg[1] = data; + set_chr(m_chr_source, m_chr_base, m_chr_mask); + } + + if (offset == 0x1007) + { + m_reg[2] = data & 0x07; // this selects different permutations for addresses and regs (to be implemented) + } +} + +WRITE8_MEMBER(nes_8237_device::write_h) +{ + static const UINT8 conv_table[8] = {0, 2, 6, 1, 7, 3, 4, 5}; + LOG_MMC(("unl_8237 write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x7000) + { + case 0x0000: + case 0x1000: + set_nt_mirroring((data | (data >> 7)) & 0x01 ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + break; + + case 0x2000: + case 0x3000: + m_cd_enable = 1; + data = (data & 0xc0) | conv_table[data & 0x07]; + txrom_write(space, 0x0000, data, mem_mask); + break; + + case 0x4000: + case 0x5000: + if (m_cd_enable) + { + m_cd_enable = 0; + txrom_write(space, 0x0001, data, mem_mask); + } + break; + + case 0x6000: + break; + + case 0x7000: + txrom_write(space, 0x6001, data, mem_mask); + txrom_write(space, 0x4000, data, mem_mask); + txrom_write(space, 0x4001, data, mem_mask); + break; + } +} + +/*------------------------------------------------- + + Bootleg Board by Super Game + + Games: The Lion King + + MMC3 clone. + + iNES: mapper 114 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_sglionk_device::write_m) +{ + LOG_MMC(("sglionk write_m, offset: %04x, data: %02x\n", offset, data)); + + m_reg = data; + + if (m_reg & 0x80) + { + prg16_89ab(data & 0x1f); + prg16_cdef(data & 0x1f); + } + else + set_prg(m_prg_base, m_prg_mask); + +} + +WRITE8_MEMBER(nes_sglionk_device::write_h) +{ + static const UINT8 conv_table[8] = {0, 3, 1, 5, 6, 7, 2, 4}; + LOG_MMC(("sglionk write_h, offset: %04x, data: %02x\n", offset, data)); + + if (offset < 0x6000) + { + switch (offset & 0x6000) + { + case 0x0000: + set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + break; + case 0x2000: + m_reg_enabled = 1; + data = (data & 0xc0) | conv_table[data & 0x07]; + txrom_write(space, 0x0000, data, mem_mask); + break; + case 0x4000: + if (m_reg_enabled && (m_reg & 0x80) == 0) + { + m_reg_enabled = 0; + txrom_write(space, 0x0001, data, mem_mask); + } + break; + } + } + else + { + switch (offset & 0x03) + { + case 0x02: + txrom_write(space, 0x6000, data, mem_mask); + break; + case 0x03: + txrom_write(space, 0x6001, data, mem_mask); + txrom_write(space, 0x4000, data, mem_mask); + txrom_write(space, 0x4001, data, mem_mask); + break; + } + } +} + +/*------------------------------------------------- + + Bootleg Board by Super Game + + Games: Boogerman, Mortal Kombat III + + MMC3 clone. Also, it probably needs a hack to support both + variants (Boogerman & MK3). + + iNES: mapper 215 + + In MESS: Preliminary support. + + -------------------------------------------------*/ + +void nes_sgboog_device::prg_cb(int start, int bank) +{ + if (!(m_reg[0] & 0x80)) // if this is != 0 we should never even arrive here + { + if (m_reg[1] & 0x08) + bank = (bank & 0x1f) | 0x20; + else + bank = (bank & 0x0f) | (m_reg[1] & 0x10); + + prg8_x(start, bank); + } +} + +void nes_sgboog_device::chr_cb(int start, int bank, int source) +{ + if ((m_reg[1] & 0x04)) + bank |= 0x100; + else + bank = (bank & 0x7f) | ((m_reg[1] & 0x10) << 3); + + chr1_x(start, bank, source); +} + +void nes_sgboog_device::set_prg(int prg_base, int prg_mask) +{ + if (m_reg[0] & 0x80) + { + prg16_89ab((m_reg[0] & 0xf0) | (m_reg[1] & 0x10)); + prg16_cdef((m_reg[0] & 0xf0) | (m_reg[1] & 0x10)); + } + else + { + // here standard MMC3 bankswitch + UINT8 prg_flip = (m_latch & 0x40) ? 2 : 0; + + prg_cb(0, prg_base | (m_mmc_prg_bank[0 ^ prg_flip] & prg_mask)); + prg_cb(1, prg_base | (m_mmc_prg_bank[1] & prg_mask)); + prg_cb(2, prg_base | (m_mmc_prg_bank[2 ^ prg_flip] & prg_mask)); + prg_cb(3, prg_base | (m_mmc_prg_bank[3] & prg_mask)); + } +} + +WRITE8_MEMBER(nes_sgboog_device::write_l) +{ + LOG_MMC(("sgboog write_l, offset: %04x, data: %02x\n", offset, data)); + offset += 0x100; + + if (offset == 0x1000) + { + m_reg[0] = data; + set_prg(m_prg_base, m_prg_mask); + } + else if (offset == 0x1001) + { + m_reg[1] = data; + set_chr(m_chr_source, m_chr_base, m_chr_mask); + } + else if (offset == 0x1007) + { + m_latch = 0; + m_mode = data; + set_prg(m_prg_base, m_prg_mask); + set_chr(m_chr_source, m_chr_base, m_chr_mask); + } +} + +WRITE8_MEMBER(nes_sgboog_device::write_m) +{ + LOG_MMC(("sgboog write_m, offset: %04x, data: %02x\n", offset, data)); + + if (offset == 0x0000) + { + m_reg[0] = data; + set_prg(m_prg_base, m_prg_mask); + } + else if (offset == 0x0001) + { + m_reg[1] = data; + set_chr(m_chr_source, m_chr_base, m_chr_mask); + } + else if (offset == 0x0007) + { + m_latch = 0; + m_mode = data; + set_prg(m_prg_base, m_prg_mask); + set_chr(m_chr_source, m_chr_base, m_chr_mask); + } +} + +WRITE8_MEMBER(nes_sgboog_device::write_h) +{ + static const UINT8 conv_table[8] = {0,2,5,3,6,1,7,4}; + LOG_MMC(("sgboog write_h, offset: %04x, data: %02x\n", offset, data)); + + if (m_mode) + { + switch (offset & 0x6001) + { + case 0x0000: + break; + + case 0x0001: + if (m_reg[2] && ((m_reg[0] & 0x80) == 0 || (m_latch & 0x07) < 6)) // if we use the prg16 banks and cmd=6,7 DON'T enter! + { + m_reg[2] = 0; + txrom_write(space, 0x0001, data, mem_mask); + } + break; + + case 0x2000: + data = (data & 0xc0) | conv_table[data & 0x07]; + m_reg[2] = 1; + txrom_write(space, 0x0000, data, mem_mask); + break; + + case 0x4000: + set_nt_mirroring(((data >> 7) | data) & 0x01 ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + break; + + case 0x4001: + txrom_write(space, 0x6001, data, mem_mask); + break; + + case 0x6001: + txrom_write(space, 0x4000, data, mem_mask); + txrom_write(space, 0x4001, data, mem_mask); + break; + + default: + txrom_write(space, offset, data, mem_mask); + break; + } + } + else + txrom_write(space, offset, data, mem_mask); +} + +/*------------------------------------------------- + + Bootleg Board by Kasing + + Games: AV Jiu Ji Mahjong, Bao Qing Tian, Thunderbolt 2, + Shisen Mahjong 2 + + MMC3 clone + + iNES: mapper 115 + + In MESS: Supported + + -------------------------------------------------*/ + +void nes_kasing_device::prg_cb(int start, int bank) +{ + if (BIT(m_reg, 7)) + prg32(m_reg >> 1); + else + prg8_x(start, bank); +} + +WRITE8_MEMBER(nes_kasing_device::write_m) +{ + LOG_MMC(("kasing write_m, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x01) + { + case 0x00: + m_reg = data; + set_prg(m_prg_base, m_prg_mask); + break; + case 0x01: + m_chr_base = (data & 0x01) ? 0x100 : 0x000; + set_chr(m_chr_source, m_chr_base, m_chr_mask); + break; + } +} + +/*------------------------------------------------- + + Bootleg Board by Kay (for Panda Prince) + + Games: The Panda Prince, Sonic 3d Blast 6, SFZ2 '97, YuYu '97 + (and its title hack MK6), UMK3, Super Lion King 2 + + MMC3 clone. This is basically KOF96 board + protection + + iNES: mapper 121 + + In MESS: Most game works, with some graphical issues. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_kay_device::write_l) +{ + LOG_MMC(("kay write_l, offset: %04x, data: %02x\n", offset, data)); + offset += 0x100; + + if (offset >= 0x1000) + { + switch (data & 0x03) + { + case 0x00: + case 0x01: + m_low_reg = 0x83; + break; + case 0x02: + m_low_reg = 0x42; + break; + case 0x03: + m_low_reg = 0x00; + break; + } + } +} + +READ8_MEMBER(nes_kay_device::read_l) +{ + LOG_MMC(("kay read_l, offset: %04x\n", offset)); + offset += 0x100; + + if (offset >= 0x1000) + return m_low_reg; + else + return 0xff; +} + +void nes_kay_device::update_regs() +{ + switch (m_reg[5] & 0x3f) + { + case 0x20: + case 0x29: + case 0x2b: + case 0x3f: + m_reg[7] = 1; + m_reg[1] = m_reg[6]; + break; + case 0x26: + m_reg[7] = 0; + m_reg[1] = m_reg[6]; + break; + case 0x2c: + m_reg[7] = 1; + if (m_reg[6]) + m_reg[1] = m_reg[6]; + break; + + case 0x28: + m_reg[7] = 0; + m_reg[2] = m_reg[6]; + break; + + case 0x2a: + m_reg[7] = 0; + m_reg[3] = m_reg[6]; + break; + + case 0x2f: + break; + + default: + m_reg[5] = 0; + break; + } +} + +void nes_kay_device::prg_cb(int start, int bank) +{ + if (m_reg[5] & 0x3f) + { + prg8_x(start, bank & 0x3f); + prg8_ef(m_reg[1]); + prg8_cd(m_reg[2]); + prg8_ab(m_reg[3]); + } + else + prg8_x(start, bank & 0x3f); +} + +void nes_kay_device::chr_cb(int start, int bank, int source) +{ + UINT8 chr_page = (m_latch & 0x80) >> 5; + + if ((start & 0x04) == chr_page) + bank |= 0x100; + + chr1_x(start, bank, source); +} + +WRITE8_MEMBER(nes_kay_device::write_h) +{ + LOG_MMC(("kay write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x6003) + { + case 0x0000: + txrom_write(space, offset, data, mem_mask); + set_prg(m_prg_base, m_prg_mask); + break; + + case 0x0001: + m_reg[6] = (BIT(data, 0) << 5) | (BIT(data, 1) << 4) | (BIT(data, 2) << 3) + | (BIT(data, 3) << 2) | (BIT(data, 4) << 1) | BIT(data, 5); + if (!m_reg[7]) + update_regs(); + txrom_write(space, offset, data, mem_mask); + set_prg(m_prg_base, m_prg_mask); + break; + + case 0x0003: + m_reg[5] = data; + update_regs(); + txrom_write(space, 0x0000, data, mem_mask); + set_prg(m_prg_base, m_prg_mask); + break; + + default: + txrom_write(space, offset, data, mem_mask); + break; + } +} + +/*------------------------------------------------- + + UNL-H2288 + + -------------------------------------------------*/ + +void nes_h2288_device::prg_cb(int start, int bank) +{ + if (!(m_reg[0] & 0x40)) + prg8_x(start, bank); +} + +WRITE8_MEMBER(nes_h2288_device::write_l) +{ + LOG_MMC(("h2288 write_l, offset: %04x, data: %02x\n", offset, data)); + offset += 0x100; + + if (offset >= 0x1800) + { + m_reg[offset & 1] = data; + if (m_reg[0] & 0x40) + { + UINT8 helper1 = (m_reg[0] & 0x05) | ((m_reg[0] >> 2) & 0x0a); + UINT8 helper2 = BIT(m_reg[0], 1); + prg16_89ab(helper1 & ~helper2); + prg16_cdef(helper1 | helper2); + } + else + set_prg(m_prg_base, m_prg_mask); + } +} + +READ8_MEMBER(nes_h2288_device::read_l) +{ + LOG_MMC(("h2288 read_l, offset: %04x\n", offset)); + offset += 0x100; + + if (offset >= 0x1000) + { + int helper = offset >> 8; + if (offset & 1) + return helper | 0x01; + else + return helper ^ 0x01; + } + + return 0; +} + +WRITE8_MEMBER(nes_h2288_device::write_h) +{ + static const UINT8 conv_table[8] = {0, 3, 1, 5, 6, 7, 2, 4}; + LOG_MMC(("h2288 write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x6001) + { + case 0x0000: + txrom_write(space, 0x0000, (data & 0xc0) | conv_table[data & 0x07], mem_mask); + break; + + default: + txrom_write(space, offset, data, mem_mask); + break; + } +} + +/*------------------------------------------------- + + UNL-603-5052 + + MMC3 + protection access in 0x4020 - 0x7fff + + in MESS: Partial support + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_6035052_device::write_ex) +{ + LOG_MMC(("6035052 write_ex, offset: %04x, data: %02x\n", offset, data)); + m_prot = data & 0x03; + if (m_prot == 1) + m_prot = 2; +} + +READ8_MEMBER(nes_6035052_device::read_ex) +{ + LOG_MMC(("6035052 read_ex, offset: %04x\n", offset)); + return m_prot; +} + +/*------------------------------------------------- + + Bootleg Board 'Thunder Warrior' by TXC + + Games: Master Fighter II, Master Fighter 3, Thunder Warrior + + MMC3 clone + + iNES: mapper 189 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_txc_tw_device::write_l) +{ + LOG_MMC(("txc_tw write_l, offset: %04x, data: %02x\n", offset, data)); + + prg32((data >> 4) | data); +} + +/* writes to 0x8000-0xffff are like MMC3 but no PRG bankswitch (beacuse it is handled by low writes) */ +void nes_txc_tw_device::prg_cb(int start, int bank) +{ + return; +} + +/*------------------------------------------------- + + Board UNL-KOF97 + + Games: King of Fighters 97 (Rex Soft) + + MMC3 clone + + In MESS: Not working + + -------------------------------------------------*/ + +inline UINT8 kof97_unscramble( UINT8 data ) +{ + return ((data >> 1) & 0x01) | ((data >> 4) & 0x02) | ((data << 2) & 0x04) | ((data >> 0) & 0xd8) | ((data << 3) & 0x20); +} + +WRITE8_MEMBER(nes_kof97_device::write_h) +{ + LOG_MMC(("kof97 write_h, offset: %04x, data: %02x\n", offset, data)); + + /* Addresses 0x9000, 0xa000, 0xd000 & 0xf000 behaves differently than MMC3 */ + if (offset == 0x1000) + txrom_write(space, 0x0001, kof97_unscramble(data), mem_mask); + else if (offset == 0x2000) + txrom_write(space, 0x0000, kof97_unscramble(data), mem_mask); + else if (offset == 0x5000) + txrom_write(space, 0x4001, kof97_unscramble(data), mem_mask); + else if (offset == 0x7000) + txrom_write(space, 0x6001, kof97_unscramble(data), mem_mask); + /* Other addresses behaves like MMC3, up to unscrambling data */ + else + txrom_write(space, offset, kof97_unscramble(data), mem_mask); +} + +/*------------------------------------------------- + + Bootleg Board for KOF96 + + Games: The King of Fighters 96, Sonic 3D Blast 6, Street + Fighter Zero 2 + + MMC3 clone + + iNES: mapper 187 + + In MESS: Preliminary Support. + + -------------------------------------------------*/ + +void nes_kof96_device::prg_cb(int start, int bank) +{ + if (!(m_reg[0] & 0x80)) + prg8_x(start, bank); +} + +void nes_kof96_device::chr_cb(int start, int bank, int source) +{ + UINT8 chr_page = (m_latch & 0x80) >> 5; + + if ((start & 0x04) == chr_page) + bank |= 0x100; + + chr1_x(start, bank, source); +} + +WRITE8_MEMBER(nes_kof96_device::write_l) +{ + UINT8 new_bank; + LOG_MMC(("kof96 write_l, offset: %04x, data: %02x\n", offset, data)); + offset += 0x100; + + if (offset == 0x1000) + { + m_reg[0] = data; + + if (m_reg[0] & 0x80) + { + new_bank = (m_reg[0] & 0x1f); + + if (m_reg[0] & 0x20) + prg32(new_bank >> 2); + else + { + prg16_89ab(new_bank); + prg16_cdef(new_bank); + } + } + else + set_prg(m_prg_base, m_prg_mask); + } + + if (offset >= 0x1000) + { + switch (data & 0x03) + { + case 0x00: + case 0x01: + m_reg[1] = 0x83; + break; + case 0x02: + m_reg[1] = 0x42; + break; + case 0x03: + m_reg[1] = 0x00; + break; + } + + } + + if (!m_reg[3] && offset > 0x1000) + { + m_reg[3] = 1; + space.write_byte(0x4017, 0x40); + } +} + +READ8_MEMBER(nes_kof96_device::read_l) +{ + LOG_MMC(("kof96 read_l, offset: %04x\n", offset)); + offset += 0x100; + + if (!(offset < 0x1000)) + return m_reg[1]; + else + return 0; +} + +WRITE8_MEMBER(nes_kof96_device::write_h) +{ + LOG_MMC(("kof96 write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x6003) + { + case 0x0000: + m_reg[2] = 1; + txrom_write(space, 0x0000, data, mem_mask); + break; + + case 0x0001: + if (m_reg[2]) + txrom_write(space, 0x0001, data, mem_mask); + break; + + case 0x0002: + break; + + case 0x0003: + m_reg[2] = 0; + + if (data == 0x28) + prg8_cd(0x17); + else if (data == 0x2a) + prg8_ab(0x0f); + break; + + default: + txrom_write(space, offset, data, mem_mask); + break; + } +} + +/*------------------------------------------------- + + Bootleg Board for Super Fighter III + + MMC3 clone + + iNES: mapper 197 + + In MESS: Supported. + + -------------------------------------------------*/ + +void nes_sf3_device::set_chr(UINT8 chr_source, int chr_base, int chr_mask) +{ + chr4_0(chr_base | ((m_mmc_vrom_bank[0] >> 1) & chr_mask), chr_source); + chr2_4(chr_base | (m_mmc_vrom_bank[1] & chr_mask), chr_source); + chr2_6(chr_base | (m_mmc_vrom_bank[2] & chr_mask), chr_source); +} + +WRITE8_MEMBER(nes_sf3_device::write_h) +{ + UINT8 cmd; + LOG_MMC(("sf3 write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x6001) + { + case 0x0001: + cmd = m_latch & 0x07; + switch (cmd) + { + case 0: case 2: case 4: + m_mmc_vrom_bank[cmd >> 1] = data; + set_chr(m_chr_source, m_chr_base, m_chr_mask); + break; + case 6: + case 7: + m_mmc_prg_bank[cmd - 6] = data; + set_prg(m_prg_base, m_prg_mask); + break; + } + break; + + default: + txrom_write(space, offset, data, mem_mask); + break; + } +} + +/*------------------------------------------------- + + Bootleg Board 37017 (?) by Gouder + + Games: Street Fighter IV + + MMC3 clone. It also requires reads from 0x5000-0x7fff. + + iNES: mapper 208 + + In MESS: Preliminary Support. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_gouder_device::write_l) +{ + static const UINT8 conv_table[256] = + { + 0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x49,0x19,0x09,0x59,0x49,0x19,0x09, + 0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x51,0x41,0x11,0x01,0x51,0x41,0x11,0x01, + 0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x49,0x19,0x09,0x59,0x49,0x19,0x09, + 0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x51,0x41,0x11,0x01,0x51,0x41,0x11,0x01, + 0x00,0x10,0x40,0x50,0x00,0x10,0x40,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x08,0x18,0x48,0x58,0x08,0x18,0x48,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x10,0x40,0x50,0x00,0x10,0x40,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x08,0x18,0x48,0x58,0x08,0x18,0x48,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x58,0x48,0x18,0x08,0x58,0x48,0x18,0x08, + 0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x50,0x40,0x10,0x00,0x50,0x40,0x10,0x00, + 0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x58,0x48,0x18,0x08,0x58,0x48,0x18,0x08, + 0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x50,0x40,0x10,0x00,0x50,0x40,0x10,0x00, + 0x01,0x11,0x41,0x51,0x01,0x11,0x41,0x51,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x09,0x19,0x49,0x59,0x09,0x19,0x49,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x11,0x41,0x51,0x01,0x11,0x41,0x51,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x09,0x19,0x49,0x59,0x09,0x19,0x49,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 + }; + + LOG_MMC(("gouder write_l, offset: %04x, data: %02x\n", offset, data)); + + if (!(offset < 0x1700)) + m_reg[offset & 0x03] = data ^ conv_table[m_reg[4]]; + else if (!(offset < 0xf00)) + m_reg[4] = data; + else if (!(offset < 0x700)) + prg32(((data >> 3) & 0x02) | (data & 0x01)); +} + +READ8_MEMBER(nes_gouder_device::read_l) +{ + LOG_MMC(("gouder read_l, offset: %04x\n", offset)); + + if (!(offset < 0x1700)) + return m_reg[offset & 0x03]; + + return 0x00; +} + +/* writes to 0x8000-0xffff are like MMC3 but no PRG bankswitch (beacuse it is handled by low writes) */ +void nes_gouder_device::prg_cb(int start, int bank) +{ + return; +} + + +/*------------------------------------------------- + + UNL-SA-9602B + + Sachen boards used for a chinese port of Princess Maker (?) + + in MESS: Very Preliminary support, based on Cah4e3 + code in FCEUMM + + -------------------------------------------------*/ + +void nes_sa9602b_device::prg_cb(int start, int bank) +{ + if (m_prg_chip == 3) + { + printf("Accessing PRG beyond end of ROM!\n"); + m_prg_chip = 2; // assume that the higher PRG chip is mirrored twice + } + prg8_x(start, (m_prg_chip * 0x40) | (bank & 0x3f)); + + if (m_latch & 0x40) + prg8_89(0x3e); + else + prg8_cd(0x3e); + + prg8_ef(0x3f); +// printf("start %d, bank %d\n", start, bank); +} + + +WRITE8_MEMBER( nes_sa9602b_device::write_h ) +{ + LOG_MMC(("sa9602b write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x6001) + { + case 0x0000: + m_reg = data; + break; + case 0x0001: + if ((m_reg & 7) < 6) + m_prg_chip = (data & 0xc0) >> 6; + set_prg(0, m_prg_mask); + break; + } + + txrom_write(space, offset, data, mem_mask); +} + +/*------------------------------------------------- + + UNL-SHERO + + Sachen boards used for Street Heroes + + in MESS: Very Preliminary support + + -------------------------------------------------*/ + + +void nes_sachen_shero_device::chr_cb( int start, int bank, int source ) +{ + int shift = start < 2 ? 5 : + start < 4 ? 6 : + start < 6 ? 8 : 7; + if (!BIT(m_reg, 6)) + chr1_x(start, ((m_reg << shift) & 0x100) | bank, source); +} + + +WRITE8_MEMBER( nes_sachen_shero_device::write_l ) +{ + LOG_MMC(("shero write_l, offset: %04x, data: %02x\n", offset, data)); + offset += 0x4100; + + if (offset == 0x4100) + { + m_reg = data; + if (BIT(m_reg, 6)) + chr8(0, CHRRAM); + else + set_chr(m_chr_source, m_chr_base, m_chr_mask); + } +} + +READ8_MEMBER( nes_sachen_shero_device::read_l ) +{ + LOG_MMC(("shero read_l, offset: %04x\n", offset)); + offset += 0x4100; + + if (offset == 0x4100) + { + // DSW read! + } + return m_open_bus; // open bus +} + + + +/*------------------------------------------------- + + MULTIGAME CARTS BASED ON MMC3 + + -------------------------------------------------*/ + + /*------------------------------------------------- + + Board BMC-FK23C + + MMC3 clone + + In MESS: partially supported (still to sort initial banking + for many games) + + -------------------------------------------------*/ + +#if 0 +// alt version... +void nes_fk23c_device::prg_cb(int start, int bank) +{ + if (((m_reg[0] & 0x07) - 3) > 1 && (!(m_reg[3] & 0x02) || start < 2)) + { + if (m_reg[0] & 0x03) + bank = (bank & (0x3f >> (m_reg[0] & 0x03))) | (m_reg[1] << 1); + + prg8_x(start, bank); + } +} + +void nes_fk23c_device::chr_cb(int start, int bank, int source) +{ + if (!(m_reg[0] & 0x40) && (!(m_reg[3] & 0x02) || (start != 1 && start != 3))) + chr1_x(start, ((m_reg[2] & 0x7f) << 3) | bank, source); +} + +#endif + +void nes_fk23c_device::prg_cb(int start, int bank) +{ + UINT8 mask = (0x3f >> (m_reg[0] & 0x03)); + + if ((m_reg[0] & 0x07) < 3) + { + if (!(m_reg[0] & 0x03)) + bank = (bank & mask) | ((m_reg[1] & (0x7f ^ mask)) << 1); + + prg8_x(start, bank); + } +} + +void nes_fk23c_device::chr_cb(int start, int bank, int source) +{ + if (!(m_reg[0] & 0x40) && (!(m_reg[3] & 0x02) || (start != 1 && start != 3))) + chr1_x(start, ((m_reg[2] & 0x7f) << 3) | bank, source); +} + +void nes_fk23c_device::fk23c_set_prg() +{ + if ((m_reg[0] & 0x07) == 4) + prg32((m_reg[1] & 0x7f) >> 1); + else if ((m_reg[0] & 0x07) == 3) + { + prg16_89ab(m_reg[1] & 0x7f); + prg16_cdef(m_reg[1] & 0x7f); + } + else + { + if (m_reg[3] & 0x02) + { + prg8_cd(m_reg[4]); + prg8_ef(m_reg[5]); + } + else + set_prg(m_prg_base, m_prg_mask); + } +} + +void nes_fk23c_device::fk23c_set_chr() +{ + if (m_reg[0] & 0x40) + chr8(m_reg[2] | m_mmc_cmd1, m_chr_source); + else + { + if (m_reg[3] & 0x02) + { + int base = (m_reg[2] & 0x7f) << 3; + chr1_x(1, base | m_reg[6], m_chr_source); + chr1_x(3, base | m_reg[7], m_chr_source); + } + else + set_chr(m_chr_source, m_chr_base, m_chr_mask); + } +} + +WRITE8_MEMBER(nes_fk23c_device::write_l) +{ + LOG_MMC(("fk23c write_l, offset: %04x, data: %02x\n", offset, data)); + offset += 0x100; + + if (offset >= 0x1000) + { + if (offset & (1 << 4)) // here it should be (4 + m_mmc_dipsetting) + { + m_reg[offset & 0x03] = data; + + fk23c_set_prg(); + fk23c_set_chr(); + } + } +} + +WRITE8_MEMBER(nes_fk23c_device::write_h) +{ + LOG_MMC(("fk23c write_h, offset: %04x, data: %02x\n", offset, data)); + + if (m_reg[0] & 0x40) + { + if (m_reg[0] & 0x30) + m_mmc_cmd1 = 0; + else + { + m_mmc_cmd1 = data & 0x03; + fk23c_set_chr(); + } + } + else + { + switch (offset & 0x6001) + { + case 0x0001: + if ((m_reg[3] & 0x02) && (m_latch & 0x08)) + { + m_reg[4 | (m_latch & 0x03)] = data; + fk23c_set_prg(); + fk23c_set_chr(); + } + else + txrom_write(space, offset, data, mem_mask); + break; + + case 0x2000: + set_nt_mirroring(data ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + break; + + default: + txrom_write(space, offset, data, mem_mask); + break; + } + } +} + +/*------------------------------------------------- + + Board BMC-SUPER24IN1SC03 + + Games: Super 24-in-1 + + In MESS: Partially Supported + + -------------------------------------------------*/ + +void nes_s24in1sc03_device::prg_cb(int start, int bank) +{ + static const UINT8 masks[8] = {0x3f, 0x1f, 0x0f, 0x01, 0x03, 0x00, 0x00, 0x00}; + int prg_base = m_reg[1] << 1; + int prg_mask = masks[m_reg[0] & 0x07]; + + bank = prg_base | (bank & prg_mask); + prg8_x(start, bank); +} + +void nes_s24in1sc03_device::chr_cb(int start, int bank, int source) +{ + UINT8 chr = BIT(m_reg[0], 5) ? CHRRAM : CHRROM; + int chr_base = (m_reg[2] << 3) & 0xf00; + + chr1_x(start, chr_base | bank, chr); +} + +WRITE8_MEMBER(nes_s24in1sc03_device::write_l) +{ + LOG_MMC(("s24in1sc03 write_l, offset: %04x, data: %02x\n", offset, data)); + offset += 0x100; + + if (offset == 0x1ff0) + { + m_reg[0] = data; + set_chr(m_chr_source, m_chr_base, m_chr_mask); + set_prg(m_prg_base, m_prg_mask); + } + + if (offset == 0x1ff1) + { + m_reg[1] = data; + set_prg(m_prg_base, m_prg_mask); + } + + if (offset == 0x1ff2) + { + m_reg[2] = data; + set_chr(m_chr_source, m_chr_base, m_chr_mask); + } +} + +/*------------------------------------------------- + + BMC-15IN1 + + Unknown Bootleg Multigame Board + Games: 3 in 1, 15 in 1 + + iNES: mapper 205, MMC3 clone + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_bmc_15in1_device::write_m) +{ + LOG_MMC(("bmc_15in1 write_m, offset: %04x, data: %02x\n", offset, data)); + + if (offset & 0x0800) + { + m_prg_base = (data & 0x03) << 4; + m_prg_mask = (data & 0x02) ? 0x0f : 0x1f; + m_chr_base = (data & 0x03) << 7; + m_chr_mask = (data & 0x02) ? 0x7f : 0xff; + set_prg(m_prg_base, m_prg_mask); + set_chr(m_chr_source, m_chr_base, m_chr_mask); + } +} + +/*------------------------------------------------- + + BMC-SUPERBIG-7IN1 + + Known Boards: Unknown Multigame Bootleg Board + Games: Kunio 8 in 1, Super Big 7 in 1 + + iNES: mapper 44 + + In MESS: Supported. It also uses mmc3_irq. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_bmc_sbig7_device::write_h) +{ + UINT8 page; + LOG_MMC(("bmc_sbig7 write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x6001) + { + case 0x2001: /* $a001 - Select 128K ROM/VROM base (0..5) or last 256K ROM/VRAM base (6) */ + page = (data & 0x07); + if (page > 6) + page = 6; + + m_prg_base = page << 4; + m_prg_mask = (page > 5) ? 0x1f : 0x0f; + m_chr_base = page << 7; + m_chr_mask = (page > 5) ? 0xff : 0x7f; + set_prg(m_prg_base, m_prg_mask); + set_chr(m_chr_source, m_chr_base, m_chr_mask); + break; + + default: + txrom_write(space, offset, data, mem_mask); + break; + } +} + +/*------------------------------------------------- + + BMC-HIK8IN1 + + Known Boards: Unknown Multigame Bootleg Board + Games: Street Fighter V, various multigame carts + + iNES: mapper 45 + + In MESS: Supported. It also uses mmc3_irq. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_bmc_hik8_device::write_m) +{ + LOG_MMC(("bmc_hik8 write_m, offset: %04x, data: %02x\n", offset, data)); + + /* This bit is the "register lock". Once register are locked, writes go to WRAM + and there is no way to unlock them (except by resetting the machine) */ + if ((m_reg[3] & 0x40) && !m_prgram.empty()) + m_prgram[offset] = data; + else + { + m_reg[m_count] = data; + m_count = (m_count + 1) & 0x03; + + if (!m_count) + { + LOG_MMC(("bmc_hik8 write_m, command completed %02x %02x %02x %02x\n", m_reg[3], + m_reg[2], m_reg[1], m_reg[0])); + + m_prg_base = m_reg[1]; + m_prg_mask = 0x3f ^ (m_reg[3] & 0x3f); + m_chr_base = ((m_reg[2] & 0xf0) << 4) | m_reg[0]; + if (BIT(m_reg[2], 3)) + m_chr_mask = (1 << ((m_reg[2] & 7) + 1)) - 1; + else if (m_reg[2]) + m_chr_mask = 0; + else + m_chr_mask = 0xff; // i.e. we use the vrom_bank with no masking + + set_prg(m_prg_base, m_prg_mask); + set_chr(m_chr_source, m_chr_base, m_chr_mask); + } + } +} + +/*------------------------------------------------- + + BMC-SUPERHIK-4IN1 + + Known Boards: Unknown Multigame Bootleg Board + Games: Super HIK 4 in 1 + + iNES: mapper 49 + + In MESS: Supported. It also uses mmc3_irq. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_bmc_hik4_device::write_m) +{ + LOG_MMC(("bmc_hik4 write_m, offset: %04x, data: %02x\n", offset, data)); + + /* mid writes only work when WRAM is enabled. not sure if I should + change the condition to m_mmc_latch2==0x80 (i.e. what is the effect of + the read-only bit?) */ + if (m_wram_protect & 0x80) + { + if (data & 0x01) /* if this is 0, then we have 32k PRG blocks */ + { + m_prg_base = (data & 0xc0) >> 2; + m_prg_mask = 0x0f; + set_prg(m_prg_base, m_prg_mask); + } + else + prg32((data & 0x30) >> 4); + + m_chr_base = (data & 0xc0) << 1; + m_chr_mask = 0x7f; + set_chr(m_chr_source, m_chr_base, m_chr_mask); + } +} + +/*------------------------------------------------- + + BMC-MARIOPARTY-7IN1 + + Known Boards: Unknown Multigame Bootleg Board + Games: Mario 7 in 1 + + MMC3 clone + + iNES: mapper 52 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_bmc_mario7in1_device::write_m) +{ + UINT8 helper1, helper2; + LOG_MMC(("bmc_mario7in1 write_m, offset: %04x, data: %02x\n", offset, data)); + + /* mid writes only work when WRAM is enabled. not sure if I should + change the condition to m_map52_reg_written == 0x80 (i.e. what is the effect of + the read-only bit?) and it only can happen once! */ + if ((m_wram_protect & 0x80) && !m_reg_written) + { + helper1 = (data & 0x08); + helper2 = (data & 0x40); + + m_prg_base = helper1 ? ((data & 0x07) << 4) : ((data & 0x06) << 4); + m_prg_mask = helper1 ? 0x0f : 0x1f; + m_chr_base = ((data & 0x20) << 4) | ((data & 0x04) << 6) | (helper2 ? ((data & 0x10) << 3) : 0); + m_chr_mask = helper2 ? 0x7f : 0xff; + set_prg(m_prg_base, m_prg_mask); + set_chr(m_chr_source, m_chr_base, m_chr_mask); + + m_reg_written = 1; + } + else + m_prgram[offset] = data; +} + +/*------------------------------------------------- + + BMC-GOLD-7IN1 + + Known Boards: Unknown Multigame Bootleg Board + Games: Super HIK Gold 7 in 1, Golden 7 in 1 and many more + + MMC3 clone, same as BMC-MARIOPARTY-7IN1 but with switched CHR + bank lines + + iNES: mapper 52 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_bmc_gold7in1_device::write_m) +{ + UINT8 helper1, helper2; + LOG_MMC(("bmc_gold7in1 write_m, offset: %04x, data: %02x\n", offset, data)); + + if ((m_wram_protect & 0x80) && !m_reg_written) + { + helper1 = (data & 0x08); + helper2 = (data & 0x40); + + m_prg_base = helper1 ? ((data & 0x07) << 4) : ((data & 0x06) << 4); + m_prg_mask = helper1 ? 0x0f : 0x1f; + m_chr_base = ((data & 0x20) << 3) | ((data & 0x04) << 7) | (helper2 ? ((data & 0x10) << 3) : 0); + m_chr_mask = helper2 ? 0x7f : 0xff; + set_prg(m_prg_base, m_prg_mask); + set_chr(m_chr_source, m_chr_base, m_chr_mask); + + m_reg_written = BIT(data, 7); // mc_2hikg & mc_s3nt3 write here multiple time + } + else + m_prgram[offset] = data; +} + +/*------------------------------------------------- + + BMC-GOLDENCARD-6IN1 + + Known Boards: Unknown Bootleg Multigame Board + Games: Golden Card 6 in 1 + + MMC3 clone + + iNES: mapper 217 + + In MESS: Supported. + + -------------------------------------------------*/ + +void nes_bmc_gc6in1_device::prg_cb(int start, int bank) +{ + if (m_reg[1] & 0x08) + bank &= 0x1f; + else + { + bank &= 0x0f; + bank |= m_reg[1] & 0x10; + } + + prg8_x(start, bank | ((m_reg[1] & 0x03) << 5)); +} + +void nes_bmc_gc6in1_device::chr_cb(int start, int bank, int source) +{ + if (!(m_reg[1] & 0x08)) + bank = ((m_reg[1] & 0x10) << 3) | (bank & 0x7f); + + + bank |= ((m_reg[1] << 6) & 0x100); + chr1_x(start, ((m_reg[1] & 0x03) << 8) | bank, source); +} + +WRITE8_MEMBER(nes_bmc_gc6in1_device::write_l) +{ + UINT8 bank; + LOG_MMC(("bmc_gc6in1 write_l, offset: %04x, data: %02x\n", offset, data)); + offset += 0x100; + + if (offset == 0x1000) + { + m_reg[0] = data; + if (data & 0x80) + { + bank = (data & 0x0f) | ((m_reg[1] & 0x03) << 4); + prg16_89ab(bank); + prg16_cdef(bank); + } + else + set_prg(m_prg_base, m_prg_mask); + } + else if (offset == 0x1001) + { + m_reg[1] = data; + set_prg(m_prg_base, m_prg_mask); + } + else if (offset == 0x1007) + { + m_reg[2] = data; + } +} + +WRITE8_MEMBER(nes_bmc_gc6in1_device::write_h) +{ + UINT8 cmd; + static const UINT8 conv_table[8] = {0, 6, 3, 7, 5, 2, 4, 1}; + LOG_MMC(("bmc_gc6in1 write_h, offset: %04x, data: %02x\n", offset, data)); + + if (!m_reg[2]) + { + // in this case we act like MMC3, only with alt prg/chr handlers + txrom_write(space, offset, data, mem_mask); + } + else + { + switch (offset & 0x6001) + { + case 0x0000: + txrom_write(space, 0x4000, data, mem_mask); + break; + + case 0x0001: + data = (data & 0xc0) | conv_table[data & 0x07]; + m_reg[3] = 1; + txrom_write(space, 0x0000, data, mem_mask); + break; + + case 0x2000: + cmd = m_latch & 0x07; + if (m_reg[3]) + { + m_reg[3] = 0; + switch (cmd) + { + case 0: case 1: // these do not need to be separated: we take care of them in set_chr! + case 2: case 3: case 4: case 5: + m_mmc_vrom_bank[cmd] = data; + set_chr(m_chr_source, m_chr_base, m_chr_mask); + break; + case 6: + case 7: + m_mmc_prg_bank[cmd - 6] = data; + set_prg(m_prg_base, m_prg_mask); + break; + } + } + break; + + + case 0x2001: + set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + break; + + default: + txrom_write(space, offset, data, mem_mask); + break; + } + } +} + +/*------------------------------------------------- + + BMC-411120C + + + MMC3 clone + + + In MESS: Very Preliminary Support + + -------------------------------------------------*/ + +void nes_bmc_411120c_device::prg_cb(int start, int bank) +{ + if (m_reg & 8) // & 0xc when DSW change (diff menu?) + prg32(((m_reg >> 4) & 3) | 0x0c); + else + prg8_x(start, (bank & 0x0f) | ((m_reg & 0x03) << 4)); +} + +void nes_bmc_411120c_device::chr_cb(int start, int bank, int source) +{ + chr1_x(start, bank | ((m_reg & 3) << 7), source); +} + +WRITE8_MEMBER(nes_bmc_411120c_device::write_m) +{ + LOG_MMC(("bmc_411120c write_m, offset: %04x, data: %02x\n", offset, data)); + + m_reg = data; + set_prg(m_prg_base, m_prg_mask); + set_chr(m_chr_source, m_chr_base, m_chr_mask); +} + +/*------------------------------------------------- + + BMC-830118C + + + MMC3 clone + + + In MESS: Very Preliminary Support + + -------------------------------------------------*/ + +void nes_bmc_830118c_device::prg_cb(int start, int bank) +{ + if ((m_reg & 0x0c) != 0x0c) + prg8_x(start, (bank & 0x0f) | ((m_reg & 0x0c) << 2)); + else + { + if (start == 0) + { + prg8_89((bank & 0x0f) | ((m_reg & 0x0c) << 2)); + prg8_ab((bank & 0x0f) | 0x20); + } + else if (start == 2) + { + prg8_cd((bank & 0x0f) | ((m_reg & 0x0c) << 2)); + prg8_ef((bank & 0x0f) | 0x20); + } + } +} + +void nes_bmc_830118c_device::chr_cb(int start, int bank, int source) +{ + chr1_x(start, (bank & 0x7f) | ((m_reg & 0x0c) << 5), source); +} + +WRITE8_MEMBER(nes_bmc_830118c_device::write_m) +{ + LOG_MMC(("bmc_830118c write_m, offset: %04x, data: %02x\n", offset, data)); + + if (offset >= 0x800 && offset < 0x900) + { + m_reg = data; + set_prg(m_prg_base, m_prg_mask); + set_chr(m_chr_source, m_chr_base, m_chr_mask); + } +} + +/*------------------------------------------------- + + BMC-POWERJOY + + -------------------------------------------------*/ + +void nes_pjoy84_device::prg_cb(int start, int bank) +{ + UINT8 flip = (m_latch & 0x40) ? 2 : 0; + + if (!(m_reg[3] & 0x03)) + prg8_x(start, bank); + else if (start == flip) + { + if ((m_reg[3] & 0x03) == 0x03) + prg32(bank >> 2); + else + { + prg16_89ab(bank >> 1); + prg16_cdef(bank >> 1); + } + } +} + +void nes_pjoy84_device::chr_cb(int start, int bank, int source) +{ + if (!(m_reg[3] & 0x10)) + chr1_x(start, bank, source); +} + +inline void nes_pjoy84_device::set_base_mask() +{ + m_prg_base = ((m_reg[0] & (0x06 | BIT(m_reg[0], 6))) << 4) | + (BIT(m_reg[0], 4) << 7); + + m_chr_base = ((~m_reg[0] << 0) & 0x080 & m_reg[2]) | + ((m_reg[0] << 4) & 0x080 & m_reg[0]) | + ((m_reg[0] << 3) & 0x100) | + ((m_reg[0] << 5) & 0x200); + + m_prg_mask = BIT(m_reg[0], 6) ? 0x0f : 0x1f; + m_chr_mask = BIT(m_reg[0], 7) ? 0x7f : 0xff; +} + +WRITE8_MEMBER(nes_pjoy84_device::write_m) +{ + LOG_MMC(("pjoy84 write_m, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x03) + { + case 0x00: + case 0x03: + if (m_reg[3] & 0x80) + return; // else we act as if offset & 3 = 1,2 + case 0x01: + case 0x02: + m_reg[offset & 0x03] = data; + set_base_mask(); + if (m_reg[3] & 0x10) + chr8((m_chr_base >> 3) | (m_reg[2] & 0x0f), m_chr_source); + else + set_chr(m_chr_source, m_chr_base, m_chr_mask); + set_prg(m_prg_base, m_prg_mask); + break; + } +} + +#ifdef UNUSED_FUNCTION +/*------------------------------------------------- + + UNL-A9746 + + + MMC3 clone + + + Preliminary emulation based on Cah4e3's code + No dump is available (yet) for this. + + -------------------------------------------------*/ + +void nes_a9746_device::device_start() +{ + mmc3_start(); + save_item(NAME(m_reg)); +} + +void nes_a9746_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + + m_reg[0] = 0; + m_reg[1] = 0; + m_reg[2] = 0; + mmc3_common_initialize(0x7f, 0xff, 0); +} + +void nes_a9746_device::update_banks(UINT8 value) +{ + UINT8 bank = BITSWAP8(value & 0x3c,7,6,0,1,2,3,4,5); + + switch (m_reg[0]) + { + case 0x26: prg8_89(bank); break; + case 0x25: prg8_ab(bank); break; + case 0x24: prg8_cd(bank); break; + case 0x23: prg8_ef(bank); break; + } + + switch (m_reg[1]) + { + case 0x08: case 0x0a: case 0x0c: case 0x0e: + case 0x10: case 0x12: case 0x14: case 0x16: + case 0x18: case 0x1a: case 0x1c: case 0x1e: + m_reg[2] = (value << 4); + break; + case 0x09: chr1_0(m_reg[2] | (value >> 1), m_chr_source); break; + case 0x0b: chr1_1(m_reg[2] | (value >> 1) | 1, m_chr_source); break; + case 0x0d: chr1_2(m_reg[2] | (value >> 1), m_chr_source); break; + case 0x0f: chr1_3(m_reg[2] | (value >> 1) | 1, m_chr_source); break; + case 0x11: chr1_4(m_reg[2] | (value >> 1), m_chr_source); break; + case 0x15: chr1_5(m_reg[2] | (value >> 1), m_chr_source); break; + case 0x19: chr1_6(m_reg[2] | (value >> 1), m_chr_source); break; + case 0x1d: chr1_7(m_reg[2] | (value >> 1), m_chr_source); break; + } +} + +WRITE8_MEMBER(nes_a9746_device::write_h) +{ + LOG_MMC(("unl_a9746 write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x6003) + { + case 0x0000: + m_reg[1] = data; + m_reg[0] = 0; + break; + case 0x0001: + update_banks(data); + break; + case 0x0002: + m_reg[0] = data; + m_reg[1] = 0; + break; + + case 0x0003: + case 0x2000: + case 0x2001: + case 0x2002: + case 0x2003: + break; + + default: + txrom_write(space, offset, data, mem_mask); + break; + } +} +#endif diff --git a/src/devices/bus/nes/mmc5.c b/src/devices/bus/nes/mmc5.c deleted file mode 100644 index 995b71080a7..00000000000 --- a/src/devices/bus/nes/mmc5.c +++ /dev/null @@ -1,679 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Fabio Priuli -/*********************************************************************************************************** - - - NES/Famicom cartridge emulation for Nintendo MMC-5 / ExROM - - - Here we emulate the Nintendo MMC-5 / ExROM PCBs [mapper 5] - - - TODO: - - improve PPU code in order to support the two sets of registers used by MMC5 - - ***********************************************************************************************************/ - - -#include "emu.h" -#include "mmc5.h" - -#include "cpu/m6502/m6502.h" -#include "video/ppu2c0x.h" // this has to be included so that IRQ functions can access PPU_BOTTOM_VISIBLE_SCANLINE -#include "sound/nes_apu.h" // temp hack to pass the additional sound regs to APU... - - -#ifdef NES_PCB_DEBUG -#define VERBOSE 1 -#else -#define VERBOSE 0 -#endif - -#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) - - -#define LAST_CHR_REG_A 0 -#define LAST_CHR_REG_B 1 - -static const int m_mmc5_attrib[4] = {0x00, 0x55, 0xaa, 0xff}; - -//------------------------------------------------- -// constructor -//------------------------------------------------- - -const device_type NES_EXROM = &device_creator; - - -nes_exrom_device::nes_exrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_EXROM, "NES Cart ExROM (MMC-5) PCB", tag, owner, clock, "nes_exrom", __FILE__) -{ -} - - -void nes_exrom_device::device_start() -{ - common_start(); - save_item(NAME(m_irq_count)); - save_item(NAME(m_irq_status)); - save_item(NAME(m_irq_enable)); - save_item(NAME(m_mult1)); - save_item(NAME(m_mult2)); - save_item(NAME(m_vrom_page_a)); - save_item(NAME(m_vrom_page_b)); - save_item(NAME(m_floodtile)); - save_item(NAME(m_floodattr)); - save_item(NAME(m_prg_mode)); - save_item(NAME(m_chr_mode)); - save_item(NAME(m_wram_base)); - save_item(NAME(m_wram_protect_1)); - save_item(NAME(m_wram_protect_2)); - save_item(NAME(m_vrom_bank)); - save_item(NAME(m_last_chr)); - save_item(NAME(m_ex1_chr)); - save_item(NAME(m_split_chr)); - save_item(NAME(m_prg_regs)); - save_item(NAME(m_prg_ram_mapped)); - save_item(NAME(m_ex1_bank)); - save_item(NAME(m_high_chr)); - save_item(NAME(m_split_scr)); - save_item(NAME(m_split_rev)); - save_item(NAME(m_split_ctrl)); - save_item(NAME(m_split_yst)); - save_item(NAME(m_split_bank)); - save_item(NAME(m_vcount)); - save_item(NAME(m_exram)); - save_item(NAME(m_ram_hi_banks)); - -} - -void nes_exrom_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(m_prg_chunks - 2); - prg16_cdef(m_prg_chunks - 1); - chr8(0, m_chr_source); - - m_irq_count = 0; - m_irq_status = 0; - m_irq_enable = 0; - - m_mult1 = m_mult2 = 0; - m_vrom_page_a = m_vrom_page_b = 0; - - m_floodtile = m_floodattr = 0; - - m_prg_mode = 3; - m_chr_mode = 0; - m_wram_base = 0; - m_wram_protect_1 = 0; - m_wram_protect_2 = 0; - m_high_chr = 0; - m_split_scr = 0; - m_split_rev = 0; - m_split_ctrl = 0; - m_split_yst = 0; - m_split_bank = 0; - m_last_chr = LAST_CHR_REG_A; - m_ex1_chr = 0; - m_split_chr = 0; - m_ex1_bank = 0; - m_vcount = 0; - - for (int i = 0; i < 12; i++) - m_vrom_bank[i] = 0x3ff; - - m_prg_regs[0] = 0xfc; - m_prg_regs[1] = 0xfd; - m_prg_regs[2] = 0xfe; - m_prg_regs[3] = 0xff; - m_prg_ram_mapped[0] = 0; - m_prg_ram_mapped[1] = 0; - m_prg_ram_mapped[2] = 0; - m_prg_ram_mapped[3] = 0; - - m_ram_hi_banks[0] = 0; - m_ram_hi_banks[1] = 0; - m_ram_hi_banks[2] = 0; - m_ram_hi_banks[3] = 0; -} - - -/*------------------------------------------------- - mapper specific handlers - -------------------------------------------------*/ - -/*------------------------------------------------- - - ExROM (MMC5 based) board emulation - - Games: Castlevania III, Just Breed, many Koei titles - - iNES: mapper 5 - - MESS status: Partially supported - - -------------------------------------------------*/ - -void nes_exrom_device::update_prg() -{ - int bank0, bank1, bank2, bank3; - - switch (m_prg_mode) - { - case 0: // 32k banks - bank3 = m_prg_regs[3] >> 2; - prg32(bank3); - break; - - case 1: // 16k banks - bank1 = m_prg_regs[1] >> 1; - bank3 = m_prg_regs[3] >> 1; - - if (m_prg_ram_mapped[1]) - { - m_ram_hi_banks[0] = ((bank1 << 1) & 0x07); - m_ram_hi_banks[1] = ((bank1 << 1) & 0x07) | 1; - } - else - prg16_89ab(bank1); - - prg16_cdef(bank3); - break; - - case 2: // 16k-8k banks - bank1 = m_prg_regs[1] >> 1; - bank2 = m_prg_regs[2]; - bank3 = m_prg_regs[3]; - - if (m_prg_ram_mapped[1]) - { - m_ram_hi_banks[0] = ((bank1 << 1) & 0x07); - m_ram_hi_banks[1] = ((bank1 << 1) & 0x07) | 1; - } - else - prg16_89ab(bank1); - - if (m_prg_ram_mapped[2]) - m_ram_hi_banks[2] = (bank2 & 0x07); - else - prg8_cd(bank2); - - prg8_ef(bank3); - break; - - case 3: // 8k banks - bank0 = m_prg_regs[0]; - bank1 = m_prg_regs[1]; - bank2 = m_prg_regs[2]; - bank3 = m_prg_regs[3]; - - if (m_prg_ram_mapped[0]) - m_ram_hi_banks[0] = (bank0 & 0x07); - else - prg8_89(bank0); - - if (m_prg_ram_mapped[1]) - m_ram_hi_banks[1] = (bank1 & 0x07); - else - prg8_ab(bank1); - - if (m_prg_ram_mapped[2]) - m_ram_hi_banks[2] = (bank2 & 0x07); - else - prg8_cd(bank2); - - prg8_ef(bank3); - break; - } -} - -void nes_exrom_device::hblank_irq(int scanline, int vblank, int blanked ) -{ - m_vcount = scanline; - - if (scanline == m_irq_count) - { - if (m_irq_enable) - m_maincpu->set_input_line(M6502_IRQ_LINE, ASSERT_LINE); - - m_irq_status = 0xff; - } - - // "In Frame" flag - if (scanline == 0) - m_irq_status |= 0x40; - else if (scanline > PPU_BOTTOM_VISIBLE_SCANLINE) - m_irq_status &= ~0x40; -} - - -void nes_exrom_device::set_mirror(int page, int src) -{ - switch (src) - { - case 0: - set_nt_page(page, CIRAM, 0, 1); - break; - case 1: - set_nt_page(page, CIRAM, 1, 1); - break; - case 2: - set_nt_page(page, EXRAM, 0, 1); - break; - case 3: - set_nt_page(page, MMC5FILL, 0, 0); - break; - default: - fatalerror("This should never happen\n"); - } -} - -inline bool nes_exrom_device::in_split() -{ - ppu2c0x_device *ppu = machine().device("ppu"); - int tile = ppu->get_tilenum(); - - if (tile < 34) - { - if (!m_split_rev && tile < m_split_ctrl) - return TRUE; - if (m_split_rev && tile >= m_split_ctrl) - return TRUE; - } - return FALSE; -} - -READ8_MEMBER(nes_exrom_device::nt_r) -{ - int page = ((offset & 0xc00) >> 10); - - switch (m_nt_src[page]) - { - case MMC5FILL: - if ((offset & 0x3ff) >= 0x3c0) - return m_floodattr; - return m_floodtile; - - case EXRAM: - // to investigate: can split screen affect this too? - if (!BIT(m_exram_control, 1)) - return m_exram[offset & 0x3ff]; - else - return 0x00; - - case CIRAM: - default: - // Uchuu Keibitai SDF uses extensively split screen for its intro, - // but it does not work yet - if (m_split_scr && !(m_exram_control & 0x02) && in_split()) - { - ppu2c0x_device *ppu = machine().device("ppu"); - int tile = ppu->get_tilenum(); - - if ((offset & 0x3ff) >= 0x3c0) - { - int pos = (((m_split_yst + m_vcount) & ~0x1f) | (tile & 0x1f)) >> 2; - return m_exram[0x3c0 | pos]; - } - else - { - int pos = (((m_split_yst + m_vcount) & 0xf8) << 2) | (tile & 0x1f); - return m_exram[pos]; - } - } - - if (m_exram_control == 1) - { - if ((offset & 0x3ff) >= 0x3c0) - return m_mmc5_attrib[(m_exram[offset & 0x3ff] >> 6) & 0x03]; - else // in this case, we write Ex1 CHR bank, but then access NT normally! - { - m_ex1_chr = 1; - m_ex1_bank = (m_exram[offset & 0x3ff] & 0x3f) | (m_high_chr << 6); - } - } - return m_nt_access[page][offset & 0x3ff]; - } -} - -WRITE8_MEMBER(nes_exrom_device::nt_w) -{ - int page = ((offset & 0xc00) >> 10); - - if (!m_nt_writable[page]) - return; - - switch (m_nt_src[page]) - { - case EXRAM: - m_exram[offset & 0x3ff] = data; - break; - - case CIRAM: - default: - m_nt_access[page][offset & 0x3ff] = data; - break; - } -} - -inline UINT8 nes_exrom_device::base_chr_r(int bank, UINT32 offset) -{ - UINT32 helper = 0; - - switch (m_chr_mode) - { - case 0: - if (bank < 8) - helper = ((m_vrom_bank[bank | 7] & 0xff) * 0x2000) + (offset & 0x1fff); - else - helper = ((m_vrom_bank[bank | 3] & 0xff) * 0x2000) + (offset & 0xfff); - break; - case 1: - helper = ((m_vrom_bank[bank | 3] & 0xff) * 0x1000) + (offset & 0xfff); - break; - case 2: - helper = (m_vrom_bank[bank | 1] * 0x800) + (offset & 0x7ff); - break; - case 3: - helper = (m_vrom_bank[bank] * 0x400) + (offset & 0x3ff); - break; - } - - return m_vrom[helper & (m_vrom_size - 1)]; -} - -inline UINT8 nes_exrom_device::split_chr_r(UINT32 offset) -{ - UINT32 helper = (m_split_bank * 0x1000) + (offset & 0x3f8) + (m_split_yst & 7); - return m_vrom[helper & (m_vrom_size - 1)]; -} - -inline UINT8 nes_exrom_device::bg_ex1_chr_r(UINT32 offset) -{ - UINT32 helper = (m_ex1_bank * 0x1000) + (offset & 0xfff); - return m_vrom[helper & (m_vrom_size - 1)]; -} - -READ8_MEMBER(nes_exrom_device::chr_r) -{ - int bank = offset >> 10; - ppu2c0x_device *ppu = machine().device("ppu"); - - // Extended Attribute Mode (Ex1) does affect BG drawing even for 8x16 sprites (JustBreed uses it extensively!) - // However, if a game enables Ex1 but does not write a new m_ex1_bank, I'm not sure here we get the correct behavior - if (m_exram_control == 1 && ppu->get_draw_phase() == PPU_DRAW_BG && m_ex1_chr) - return bg_ex1_chr_r(offset & 0xfff); - - if (m_split_scr && !(m_exram_control & 0x02) && in_split() && ppu->get_draw_phase() == PPU_DRAW_BG && m_split_chr) - return split_chr_r(offset & 0xfff); - - if (ppu->is_sprite_8x16()) - { - if (ppu->get_draw_phase() == PPU_DRAW_OAM) - return base_chr_r(bank & 7, offset & 0x1fff); - - if (ppu->get_draw_phase() == PPU_DRAW_BG) - return base_chr_r((bank & 3) + 8, offset & 0x1fff); - } - - if (m_last_chr == LAST_CHR_REG_A) - return base_chr_r(bank & 7, offset & 0x1fff); - else - return base_chr_r((bank & 3) + 8, offset & 0x1fff); -} - - -READ8_MEMBER(nes_exrom_device::read_l) -{ - int value; - LOG_MMC(("exrom read_l, offset: %04x\n", offset)); - offset += 0x100; - - if ((offset >= 0x1c00) && (offset <= 0x1fff)) - { - // EXRAM - if (BIT(m_exram_control, 1)) // Modes 2,3 = read - return m_exram[offset - 0x1c00]; - else - return m_open_bus; // Modes 0,1 = open bus - } - - switch (offset) - { - case 0x1204: - value = m_irq_status; - m_irq_status &= ~0x80; - m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); - return value; - - case 0x1205: - return (m_mult1 * m_mult2) & 0xff; - case 0x1206: - return ((m_mult1 * m_mult2) & 0xff00) >> 8; - - default: - logerror("MMC5 uncaught read, offset: %04x\n", offset + 0x4100); - return m_open_bus; - } -} - - -WRITE8_MEMBER(nes_exrom_device::write_l) -{ - LOG_MMC(("exrom write_l, offset: %04x, data: %02x\n", offset, data)); - offset += 0x100; - - if ((offset >= 0x1000) && (offset <= 0x1015)) - { - // SOUND - nesapu_device *m_sound = machine().device("maincpu::nessound"); - m_sound->write(space, offset & 0x1f, data); - return; - } - - if ((offset >= 0x1c00) && (offset <= 0x1fff)) - { - // EXRAM - if (m_exram_control == 0x02) // Mode 2 = write data - m_exram[offset - 0x1c00] = data; - else if (m_exram_control != 0x03) // Modes 0,1 = write data in frame / write 0 otherwise - { - if (m_irq_status & 0x40) - m_exram[offset - 0x1c00] = data; - else - m_exram[offset - 0x1c00] = 0x00; - } - // Mode 3 = read only - return; - } - - switch (offset) - { - case 0x1100: - m_prg_mode = data & 0x03; - update_prg(); - //LOG_MMC(("MMC5 rom bank mode: %02x\n", data)); - break; - - case 0x1101: - m_chr_mode = data & 0x03; - m_ex1_chr = 0; - m_split_chr = 0; - //LOG_MMC(("MMC5 vrom bank mode: %02x\n", data)); - break; - - case 0x1102: - m_wram_protect_1 = data & 0x03; - LOG_MMC(("MMC5 vram protect 1: %02x\n", data)); - break; - case 0x1103: - m_wram_protect_2 = data & 0x03; - LOG_MMC(("MMC5 vram protect 2: %02x\n", data)); - break; - - case 0x1104: // Extra VRAM (EXRAM) - m_exram_control = data & 0x03; - LOG_MMC(("MMC5 exram control: %02x\n", data)); - break; - - case 0x1105: - set_mirror(0, (data & 0x03) >> 0); - set_mirror(1, (data & 0x0c) >> 2); - set_mirror(2, (data & 0x30) >> 4); - set_mirror(3, (data & 0xc0) >> 6); - break; - - case 0x1106: - m_floodtile = data; - break; - - case 0x1107: - m_floodattr = m_mmc5_attrib[data & 3]; - break; - - case 0x1113: - LOG_MMC(("MMC5 mid RAM bank select: %02x\n", data & 0x07)); - m_wram_base = data & 0x07; - break; - - - case 0x1114: - case 0x1115: - case 0x1116: - case 0x1117: - m_prg_regs[offset & 3] = data & 0x7f; - m_prg_ram_mapped[offset & 3] = !BIT(data, 7); // m_prg_ram_mapped[3] is not used, in fact! - update_prg(); - break; - - case 0x1120: - case 0x1121: - case 0x1122: - case 0x1123: - case 0x1124: - case 0x1125: - case 0x1126: - case 0x1127: - m_vrom_bank[offset & 0x07] = data | (m_high_chr << 8); - m_last_chr = LAST_CHR_REG_A; - m_ex1_chr = 0; - m_split_chr = 0; - break; - - case 0x1128: - case 0x1129: - case 0x112a: - case 0x112b: - m_vrom_bank[offset & 0x0f] = data | (m_high_chr << 8); - m_last_chr = LAST_CHR_REG_B; - m_ex1_chr = 0; - m_split_chr = 0; - break; - - case 0x1130: - m_high_chr = data & 0x03; - m_ex1_chr = 0; - m_split_chr = 0; - break; - - - case 0x1200: - // in EX2 and EX3 modes, no split screen - m_split_scr = BIT(data, 7); - m_split_rev = BIT(data, 6); - m_split_ctrl = data & 0x1f; - break; - - case 0x1201: - m_split_yst = (data >= 240) ? data - 16 : data; - break; - - case 0x1202: - m_split_bank = data; - m_split_chr = 1; - break; - - case 0x1203: - m_irq_count = data; - LOG_MMC(("MMC5 irq scanline: %d\n", m_irq_count)); - break; - case 0x1204: - m_irq_enable = data & 0x80; - LOG_MMC(("MMC5 irq enable: %02x\n", data)); - break; - case 0x1205: - m_mult1 = data; - break; - case 0x1206: - m_mult2 = data; - break; - - default: - logerror("MMC5 uncaught write, offset: %04x, data: %02x\n", offset + 0x4100, data); - break; - } -} - -// 3bits are used to access the "WRAM" banks -// bit3 select the chip (2 of them can be accessed, each up to 32KB) -// bit1 & bit2 select the 8KB banks inside the chip -// same mechanism is used also when "WRAM" is mapped in higher banks -READ8_MEMBER(nes_exrom_device::read_m) -{ - LOG_MMC(("exrom read_m, offset: %04x\n", offset)); - if (!m_battery.empty() && !m_prgram.empty()) // 2 chips present: first is BWRAM, second is WRAM - { - if (m_wram_base & 0x04) - return m_prgram[(offset + (m_wram_base & 0x03) * 0x2000) & (m_prgram.size() - 1)]; - else - return m_battery[(offset + (m_wram_base & 0x03) * 0x2000) & (m_battery.size() - 1)]; - } - else if (!m_prgram.empty()) // 1 chip, WRAM - return m_prgram[(offset + (m_wram_base & 0x03) * 0x2000) & (m_prgram.size() - 1)]; - else if (!m_battery.empty()) // 1 chip, BWRAM - return m_battery[(offset + (m_wram_base & 0x03) * 0x2000) & (m_battery.size() - 1)]; - else - return m_open_bus; -} - -WRITE8_MEMBER(nes_exrom_device::write_m) -{ - LOG_MMC(("exrom write_m, offset: %04x, data: %02x\n", offset, data)); - if (m_wram_protect_1 != 0x02 || m_wram_protect_2 != 0x01) - return; - - if (!m_battery.empty() && m_wram_base < 4) - m_battery[(offset + m_wram_base * 0x2000) & (m_battery.size() - 1)] = data; - else if (!m_prgram.empty()) - m_prgram[(offset + (m_wram_base & 0x03) * 0x2000) & (m_prgram.size() - 1)] = data; -} - -// some games (e.g. Bandit Kings of Ancient China) write to PRG-RAM through 0x8000-0xdfff -READ8_MEMBER(nes_exrom_device::read_h) -{ - LOG_MMC(("exrom read_h, offset: %04x\n", offset)); - int bank = offset / 0x2000; - - if (bank < 3 && offset >= bank * 0x2000 && offset < (bank + 1) * 0x2000 && m_prg_ram_mapped[bank]) - { - if (!m_battery.empty() && m_ram_hi_banks[bank] < 4) - return m_battery[((m_ram_hi_banks[bank] * 0x2000) + (offset & 0x1fff)) & (m_battery.size() - 1)]; - else if (!m_prgram.empty()) - return m_prgram[(((m_ram_hi_banks[bank] & 3) * 0x2000) + (offset & 0x1fff)) & (m_prgram.size() - 1)]; - } - - return hi_access_rom(offset); -} - -WRITE8_MEMBER(nes_exrom_device::write_h) -{ - LOG_MMC(("exrom write_h, offset: %04x, data: %02x\n", offset, data)); - int bank = offset / 0x2000; - if (m_wram_protect_1 != 0x02 || m_wram_protect_2 != 0x01 || bank == 3 || !m_prg_ram_mapped[bank]) - return; - - if (!m_battery.empty() && m_ram_hi_banks[bank] < 4) - m_battery[((m_ram_hi_banks[bank] * 0x2000) + (offset & 0x1fff)) & (m_battery.size() - 1)] = data; - else if (!m_prgram.empty()) - m_prgram[(((m_ram_hi_banks[bank] & 3) * 0x2000) + (offset & 0x1fff)) & (m_prgram.size() - 1)] = data; -} diff --git a/src/devices/bus/nes/mmc5.cpp b/src/devices/bus/nes/mmc5.cpp new file mode 100644 index 00000000000..995b71080a7 --- /dev/null +++ b/src/devices/bus/nes/mmc5.cpp @@ -0,0 +1,679 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for Nintendo MMC-5 / ExROM + + + Here we emulate the Nintendo MMC-5 / ExROM PCBs [mapper 5] + + + TODO: + - improve PPU code in order to support the two sets of registers used by MMC5 + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "mmc5.h" + +#include "cpu/m6502/m6502.h" +#include "video/ppu2c0x.h" // this has to be included so that IRQ functions can access PPU_BOTTOM_VISIBLE_SCANLINE +#include "sound/nes_apu.h" // temp hack to pass the additional sound regs to APU... + + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +#define LAST_CHR_REG_A 0 +#define LAST_CHR_REG_B 1 + +static const int m_mmc5_attrib[4] = {0x00, 0x55, 0xaa, 0xff}; + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_EXROM = &device_creator; + + +nes_exrom_device::nes_exrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_EXROM, "NES Cart ExROM (MMC-5) PCB", tag, owner, clock, "nes_exrom", __FILE__) +{ +} + + +void nes_exrom_device::device_start() +{ + common_start(); + save_item(NAME(m_irq_count)); + save_item(NAME(m_irq_status)); + save_item(NAME(m_irq_enable)); + save_item(NAME(m_mult1)); + save_item(NAME(m_mult2)); + save_item(NAME(m_vrom_page_a)); + save_item(NAME(m_vrom_page_b)); + save_item(NAME(m_floodtile)); + save_item(NAME(m_floodattr)); + save_item(NAME(m_prg_mode)); + save_item(NAME(m_chr_mode)); + save_item(NAME(m_wram_base)); + save_item(NAME(m_wram_protect_1)); + save_item(NAME(m_wram_protect_2)); + save_item(NAME(m_vrom_bank)); + save_item(NAME(m_last_chr)); + save_item(NAME(m_ex1_chr)); + save_item(NAME(m_split_chr)); + save_item(NAME(m_prg_regs)); + save_item(NAME(m_prg_ram_mapped)); + save_item(NAME(m_ex1_bank)); + save_item(NAME(m_high_chr)); + save_item(NAME(m_split_scr)); + save_item(NAME(m_split_rev)); + save_item(NAME(m_split_ctrl)); + save_item(NAME(m_split_yst)); + save_item(NAME(m_split_bank)); + save_item(NAME(m_vcount)); + save_item(NAME(m_exram)); + save_item(NAME(m_ram_hi_banks)); + +} + +void nes_exrom_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(m_prg_chunks - 2); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + + m_irq_count = 0; + m_irq_status = 0; + m_irq_enable = 0; + + m_mult1 = m_mult2 = 0; + m_vrom_page_a = m_vrom_page_b = 0; + + m_floodtile = m_floodattr = 0; + + m_prg_mode = 3; + m_chr_mode = 0; + m_wram_base = 0; + m_wram_protect_1 = 0; + m_wram_protect_2 = 0; + m_high_chr = 0; + m_split_scr = 0; + m_split_rev = 0; + m_split_ctrl = 0; + m_split_yst = 0; + m_split_bank = 0; + m_last_chr = LAST_CHR_REG_A; + m_ex1_chr = 0; + m_split_chr = 0; + m_ex1_bank = 0; + m_vcount = 0; + + for (int i = 0; i < 12; i++) + m_vrom_bank[i] = 0x3ff; + + m_prg_regs[0] = 0xfc; + m_prg_regs[1] = 0xfd; + m_prg_regs[2] = 0xfe; + m_prg_regs[3] = 0xff; + m_prg_ram_mapped[0] = 0; + m_prg_ram_mapped[1] = 0; + m_prg_ram_mapped[2] = 0; + m_prg_ram_mapped[3] = 0; + + m_ram_hi_banks[0] = 0; + m_ram_hi_banks[1] = 0; + m_ram_hi_banks[2] = 0; + m_ram_hi_banks[3] = 0; +} + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + ExROM (MMC5 based) board emulation + + Games: Castlevania III, Just Breed, many Koei titles + + iNES: mapper 5 + + MESS status: Partially supported + + -------------------------------------------------*/ + +void nes_exrom_device::update_prg() +{ + int bank0, bank1, bank2, bank3; + + switch (m_prg_mode) + { + case 0: // 32k banks + bank3 = m_prg_regs[3] >> 2; + prg32(bank3); + break; + + case 1: // 16k banks + bank1 = m_prg_regs[1] >> 1; + bank3 = m_prg_regs[3] >> 1; + + if (m_prg_ram_mapped[1]) + { + m_ram_hi_banks[0] = ((bank1 << 1) & 0x07); + m_ram_hi_banks[1] = ((bank1 << 1) & 0x07) | 1; + } + else + prg16_89ab(bank1); + + prg16_cdef(bank3); + break; + + case 2: // 16k-8k banks + bank1 = m_prg_regs[1] >> 1; + bank2 = m_prg_regs[2]; + bank3 = m_prg_regs[3]; + + if (m_prg_ram_mapped[1]) + { + m_ram_hi_banks[0] = ((bank1 << 1) & 0x07); + m_ram_hi_banks[1] = ((bank1 << 1) & 0x07) | 1; + } + else + prg16_89ab(bank1); + + if (m_prg_ram_mapped[2]) + m_ram_hi_banks[2] = (bank2 & 0x07); + else + prg8_cd(bank2); + + prg8_ef(bank3); + break; + + case 3: // 8k banks + bank0 = m_prg_regs[0]; + bank1 = m_prg_regs[1]; + bank2 = m_prg_regs[2]; + bank3 = m_prg_regs[3]; + + if (m_prg_ram_mapped[0]) + m_ram_hi_banks[0] = (bank0 & 0x07); + else + prg8_89(bank0); + + if (m_prg_ram_mapped[1]) + m_ram_hi_banks[1] = (bank1 & 0x07); + else + prg8_ab(bank1); + + if (m_prg_ram_mapped[2]) + m_ram_hi_banks[2] = (bank2 & 0x07); + else + prg8_cd(bank2); + + prg8_ef(bank3); + break; + } +} + +void nes_exrom_device::hblank_irq(int scanline, int vblank, int blanked ) +{ + m_vcount = scanline; + + if (scanline == m_irq_count) + { + if (m_irq_enable) + m_maincpu->set_input_line(M6502_IRQ_LINE, ASSERT_LINE); + + m_irq_status = 0xff; + } + + // "In Frame" flag + if (scanline == 0) + m_irq_status |= 0x40; + else if (scanline > PPU_BOTTOM_VISIBLE_SCANLINE) + m_irq_status &= ~0x40; +} + + +void nes_exrom_device::set_mirror(int page, int src) +{ + switch (src) + { + case 0: + set_nt_page(page, CIRAM, 0, 1); + break; + case 1: + set_nt_page(page, CIRAM, 1, 1); + break; + case 2: + set_nt_page(page, EXRAM, 0, 1); + break; + case 3: + set_nt_page(page, MMC5FILL, 0, 0); + break; + default: + fatalerror("This should never happen\n"); + } +} + +inline bool nes_exrom_device::in_split() +{ + ppu2c0x_device *ppu = machine().device("ppu"); + int tile = ppu->get_tilenum(); + + if (tile < 34) + { + if (!m_split_rev && tile < m_split_ctrl) + return TRUE; + if (m_split_rev && tile >= m_split_ctrl) + return TRUE; + } + return FALSE; +} + +READ8_MEMBER(nes_exrom_device::nt_r) +{ + int page = ((offset & 0xc00) >> 10); + + switch (m_nt_src[page]) + { + case MMC5FILL: + if ((offset & 0x3ff) >= 0x3c0) + return m_floodattr; + return m_floodtile; + + case EXRAM: + // to investigate: can split screen affect this too? + if (!BIT(m_exram_control, 1)) + return m_exram[offset & 0x3ff]; + else + return 0x00; + + case CIRAM: + default: + // Uchuu Keibitai SDF uses extensively split screen for its intro, + // but it does not work yet + if (m_split_scr && !(m_exram_control & 0x02) && in_split()) + { + ppu2c0x_device *ppu = machine().device("ppu"); + int tile = ppu->get_tilenum(); + + if ((offset & 0x3ff) >= 0x3c0) + { + int pos = (((m_split_yst + m_vcount) & ~0x1f) | (tile & 0x1f)) >> 2; + return m_exram[0x3c0 | pos]; + } + else + { + int pos = (((m_split_yst + m_vcount) & 0xf8) << 2) | (tile & 0x1f); + return m_exram[pos]; + } + } + + if (m_exram_control == 1) + { + if ((offset & 0x3ff) >= 0x3c0) + return m_mmc5_attrib[(m_exram[offset & 0x3ff] >> 6) & 0x03]; + else // in this case, we write Ex1 CHR bank, but then access NT normally! + { + m_ex1_chr = 1; + m_ex1_bank = (m_exram[offset & 0x3ff] & 0x3f) | (m_high_chr << 6); + } + } + return m_nt_access[page][offset & 0x3ff]; + } +} + +WRITE8_MEMBER(nes_exrom_device::nt_w) +{ + int page = ((offset & 0xc00) >> 10); + + if (!m_nt_writable[page]) + return; + + switch (m_nt_src[page]) + { + case EXRAM: + m_exram[offset & 0x3ff] = data; + break; + + case CIRAM: + default: + m_nt_access[page][offset & 0x3ff] = data; + break; + } +} + +inline UINT8 nes_exrom_device::base_chr_r(int bank, UINT32 offset) +{ + UINT32 helper = 0; + + switch (m_chr_mode) + { + case 0: + if (bank < 8) + helper = ((m_vrom_bank[bank | 7] & 0xff) * 0x2000) + (offset & 0x1fff); + else + helper = ((m_vrom_bank[bank | 3] & 0xff) * 0x2000) + (offset & 0xfff); + break; + case 1: + helper = ((m_vrom_bank[bank | 3] & 0xff) * 0x1000) + (offset & 0xfff); + break; + case 2: + helper = (m_vrom_bank[bank | 1] * 0x800) + (offset & 0x7ff); + break; + case 3: + helper = (m_vrom_bank[bank] * 0x400) + (offset & 0x3ff); + break; + } + + return m_vrom[helper & (m_vrom_size - 1)]; +} + +inline UINT8 nes_exrom_device::split_chr_r(UINT32 offset) +{ + UINT32 helper = (m_split_bank * 0x1000) + (offset & 0x3f8) + (m_split_yst & 7); + return m_vrom[helper & (m_vrom_size - 1)]; +} + +inline UINT8 nes_exrom_device::bg_ex1_chr_r(UINT32 offset) +{ + UINT32 helper = (m_ex1_bank * 0x1000) + (offset & 0xfff); + return m_vrom[helper & (m_vrom_size - 1)]; +} + +READ8_MEMBER(nes_exrom_device::chr_r) +{ + int bank = offset >> 10; + ppu2c0x_device *ppu = machine().device("ppu"); + + // Extended Attribute Mode (Ex1) does affect BG drawing even for 8x16 sprites (JustBreed uses it extensively!) + // However, if a game enables Ex1 but does not write a new m_ex1_bank, I'm not sure here we get the correct behavior + if (m_exram_control == 1 && ppu->get_draw_phase() == PPU_DRAW_BG && m_ex1_chr) + return bg_ex1_chr_r(offset & 0xfff); + + if (m_split_scr && !(m_exram_control & 0x02) && in_split() && ppu->get_draw_phase() == PPU_DRAW_BG && m_split_chr) + return split_chr_r(offset & 0xfff); + + if (ppu->is_sprite_8x16()) + { + if (ppu->get_draw_phase() == PPU_DRAW_OAM) + return base_chr_r(bank & 7, offset & 0x1fff); + + if (ppu->get_draw_phase() == PPU_DRAW_BG) + return base_chr_r((bank & 3) + 8, offset & 0x1fff); + } + + if (m_last_chr == LAST_CHR_REG_A) + return base_chr_r(bank & 7, offset & 0x1fff); + else + return base_chr_r((bank & 3) + 8, offset & 0x1fff); +} + + +READ8_MEMBER(nes_exrom_device::read_l) +{ + int value; + LOG_MMC(("exrom read_l, offset: %04x\n", offset)); + offset += 0x100; + + if ((offset >= 0x1c00) && (offset <= 0x1fff)) + { + // EXRAM + if (BIT(m_exram_control, 1)) // Modes 2,3 = read + return m_exram[offset - 0x1c00]; + else + return m_open_bus; // Modes 0,1 = open bus + } + + switch (offset) + { + case 0x1204: + value = m_irq_status; + m_irq_status &= ~0x80; + m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); + return value; + + case 0x1205: + return (m_mult1 * m_mult2) & 0xff; + case 0x1206: + return ((m_mult1 * m_mult2) & 0xff00) >> 8; + + default: + logerror("MMC5 uncaught read, offset: %04x\n", offset + 0x4100); + return m_open_bus; + } +} + + +WRITE8_MEMBER(nes_exrom_device::write_l) +{ + LOG_MMC(("exrom write_l, offset: %04x, data: %02x\n", offset, data)); + offset += 0x100; + + if ((offset >= 0x1000) && (offset <= 0x1015)) + { + // SOUND + nesapu_device *m_sound = machine().device("maincpu::nessound"); + m_sound->write(space, offset & 0x1f, data); + return; + } + + if ((offset >= 0x1c00) && (offset <= 0x1fff)) + { + // EXRAM + if (m_exram_control == 0x02) // Mode 2 = write data + m_exram[offset - 0x1c00] = data; + else if (m_exram_control != 0x03) // Modes 0,1 = write data in frame / write 0 otherwise + { + if (m_irq_status & 0x40) + m_exram[offset - 0x1c00] = data; + else + m_exram[offset - 0x1c00] = 0x00; + } + // Mode 3 = read only + return; + } + + switch (offset) + { + case 0x1100: + m_prg_mode = data & 0x03; + update_prg(); + //LOG_MMC(("MMC5 rom bank mode: %02x\n", data)); + break; + + case 0x1101: + m_chr_mode = data & 0x03; + m_ex1_chr = 0; + m_split_chr = 0; + //LOG_MMC(("MMC5 vrom bank mode: %02x\n", data)); + break; + + case 0x1102: + m_wram_protect_1 = data & 0x03; + LOG_MMC(("MMC5 vram protect 1: %02x\n", data)); + break; + case 0x1103: + m_wram_protect_2 = data & 0x03; + LOG_MMC(("MMC5 vram protect 2: %02x\n", data)); + break; + + case 0x1104: // Extra VRAM (EXRAM) + m_exram_control = data & 0x03; + LOG_MMC(("MMC5 exram control: %02x\n", data)); + break; + + case 0x1105: + set_mirror(0, (data & 0x03) >> 0); + set_mirror(1, (data & 0x0c) >> 2); + set_mirror(2, (data & 0x30) >> 4); + set_mirror(3, (data & 0xc0) >> 6); + break; + + case 0x1106: + m_floodtile = data; + break; + + case 0x1107: + m_floodattr = m_mmc5_attrib[data & 3]; + break; + + case 0x1113: + LOG_MMC(("MMC5 mid RAM bank select: %02x\n", data & 0x07)); + m_wram_base = data & 0x07; + break; + + + case 0x1114: + case 0x1115: + case 0x1116: + case 0x1117: + m_prg_regs[offset & 3] = data & 0x7f; + m_prg_ram_mapped[offset & 3] = !BIT(data, 7); // m_prg_ram_mapped[3] is not used, in fact! + update_prg(); + break; + + case 0x1120: + case 0x1121: + case 0x1122: + case 0x1123: + case 0x1124: + case 0x1125: + case 0x1126: + case 0x1127: + m_vrom_bank[offset & 0x07] = data | (m_high_chr << 8); + m_last_chr = LAST_CHR_REG_A; + m_ex1_chr = 0; + m_split_chr = 0; + break; + + case 0x1128: + case 0x1129: + case 0x112a: + case 0x112b: + m_vrom_bank[offset & 0x0f] = data | (m_high_chr << 8); + m_last_chr = LAST_CHR_REG_B; + m_ex1_chr = 0; + m_split_chr = 0; + break; + + case 0x1130: + m_high_chr = data & 0x03; + m_ex1_chr = 0; + m_split_chr = 0; + break; + + + case 0x1200: + // in EX2 and EX3 modes, no split screen + m_split_scr = BIT(data, 7); + m_split_rev = BIT(data, 6); + m_split_ctrl = data & 0x1f; + break; + + case 0x1201: + m_split_yst = (data >= 240) ? data - 16 : data; + break; + + case 0x1202: + m_split_bank = data; + m_split_chr = 1; + break; + + case 0x1203: + m_irq_count = data; + LOG_MMC(("MMC5 irq scanline: %d\n", m_irq_count)); + break; + case 0x1204: + m_irq_enable = data & 0x80; + LOG_MMC(("MMC5 irq enable: %02x\n", data)); + break; + case 0x1205: + m_mult1 = data; + break; + case 0x1206: + m_mult2 = data; + break; + + default: + logerror("MMC5 uncaught write, offset: %04x, data: %02x\n", offset + 0x4100, data); + break; + } +} + +// 3bits are used to access the "WRAM" banks +// bit3 select the chip (2 of them can be accessed, each up to 32KB) +// bit1 & bit2 select the 8KB banks inside the chip +// same mechanism is used also when "WRAM" is mapped in higher banks +READ8_MEMBER(nes_exrom_device::read_m) +{ + LOG_MMC(("exrom read_m, offset: %04x\n", offset)); + if (!m_battery.empty() && !m_prgram.empty()) // 2 chips present: first is BWRAM, second is WRAM + { + if (m_wram_base & 0x04) + return m_prgram[(offset + (m_wram_base & 0x03) * 0x2000) & (m_prgram.size() - 1)]; + else + return m_battery[(offset + (m_wram_base & 0x03) * 0x2000) & (m_battery.size() - 1)]; + } + else if (!m_prgram.empty()) // 1 chip, WRAM + return m_prgram[(offset + (m_wram_base & 0x03) * 0x2000) & (m_prgram.size() - 1)]; + else if (!m_battery.empty()) // 1 chip, BWRAM + return m_battery[(offset + (m_wram_base & 0x03) * 0x2000) & (m_battery.size() - 1)]; + else + return m_open_bus; +} + +WRITE8_MEMBER(nes_exrom_device::write_m) +{ + LOG_MMC(("exrom write_m, offset: %04x, data: %02x\n", offset, data)); + if (m_wram_protect_1 != 0x02 || m_wram_protect_2 != 0x01) + return; + + if (!m_battery.empty() && m_wram_base < 4) + m_battery[(offset + m_wram_base * 0x2000) & (m_battery.size() - 1)] = data; + else if (!m_prgram.empty()) + m_prgram[(offset + (m_wram_base & 0x03) * 0x2000) & (m_prgram.size() - 1)] = data; +} + +// some games (e.g. Bandit Kings of Ancient China) write to PRG-RAM through 0x8000-0xdfff +READ8_MEMBER(nes_exrom_device::read_h) +{ + LOG_MMC(("exrom read_h, offset: %04x\n", offset)); + int bank = offset / 0x2000; + + if (bank < 3 && offset >= bank * 0x2000 && offset < (bank + 1) * 0x2000 && m_prg_ram_mapped[bank]) + { + if (!m_battery.empty() && m_ram_hi_banks[bank] < 4) + return m_battery[((m_ram_hi_banks[bank] * 0x2000) + (offset & 0x1fff)) & (m_battery.size() - 1)]; + else if (!m_prgram.empty()) + return m_prgram[(((m_ram_hi_banks[bank] & 3) * 0x2000) + (offset & 0x1fff)) & (m_prgram.size() - 1)]; + } + + return hi_access_rom(offset); +} + +WRITE8_MEMBER(nes_exrom_device::write_h) +{ + LOG_MMC(("exrom write_h, offset: %04x, data: %02x\n", offset, data)); + int bank = offset / 0x2000; + if (m_wram_protect_1 != 0x02 || m_wram_protect_2 != 0x01 || bank == 3 || !m_prg_ram_mapped[bank]) + return; + + if (!m_battery.empty() && m_ram_hi_banks[bank] < 4) + m_battery[((m_ram_hi_banks[bank] * 0x2000) + (offset & 0x1fff)) & (m_battery.size() - 1)] = data; + else if (!m_prgram.empty()) + m_prgram[(((m_ram_hi_banks[bank] & 3) * 0x2000) + (offset & 0x1fff)) & (m_prgram.size() - 1)] = data; +} diff --git a/src/devices/bus/nes/multigame.c b/src/devices/bus/nes/multigame.c deleted file mode 100644 index ba65c3d0e7c..00000000000 --- a/src/devices/bus/nes/multigame.c +++ /dev/null @@ -1,2602 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Fabio Priuli -/*********************************************************************************************************** - - - NES/Famicom cartridge emulation for Multigame Carts PCBs - - - Here we emulate several PCBs used in multigame pirate carts (not MMC-3 based) - - ***********************************************************************************************************/ - - -#include "emu.h" -#include "multigame.h" - - -#ifdef NES_PCB_DEBUG -#define VERBOSE 1 -#else -#define VERBOSE 0 -#endif - -#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) - - -//------------------------------------------------- -// constructor -//------------------------------------------------- - -const device_type NES_ACTION52 = &device_creator; -const device_type NES_CALTRON6IN1 = &device_creator; -const device_type NES_RUMBLESTATION = &device_creator; -const device_type NES_SVISION16 = &device_creator; -const device_type NES_N625092 = &device_creator; -const device_type NES_A65AS = &device_creator; -const device_type NES_T262 = &device_creator; -const device_type NES_NOVEL1 = &device_creator; -const device_type NES_NOVEL2 = &device_creator; -const device_type NES_STUDYNGAME = &device_creator; -const device_type NES_SUPERGUN20IN1 = &device_creator; -const device_type NES_VT5201 = &device_creator; -const device_type NES_810544C = &device_creator; -const device_type NES_NTD03 = &device_creator; -const device_type NES_BMC_GB63 = &device_creator; -const device_type NES_BMC_GKA = &device_creator; -const device_type NES_BMC_GKB = &device_creator; -const device_type NES_BMC_WS = &device_creator; -const device_type NES_BMC_11160 = &device_creator; -const device_type NES_BMC_G146 = &device_creator; -const device_type NES_BMC_8157 = &device_creator; -const device_type NES_BMC_HIK300 = &device_creator; -const device_type NES_BMC_S700 = &device_creator; -const device_type NES_BMC_BALL11 = &device_creator; -const device_type NES_BMC_22GAMES = &device_creator; -const device_type NES_BMC_64Y2K = &device_creator; -const device_type NES_BMC_12IN1 = &device_creator; -const device_type NES_BMC_20IN1 = &device_creator; -const device_type NES_BMC_21IN1 = &device_creator; -const device_type NES_BMC_31IN1 = &device_creator; -const device_type NES_BMC_35IN1 = &device_creator; -const device_type NES_BMC_36IN1 = &device_creator; -const device_type NES_BMC_64IN1 = &device_creator; -const device_type NES_BMC_70IN1 = &device_creator; -const device_type NES_BMC_72IN1 = &device_creator; -const device_type NES_BMC_76IN1 = &device_creator; -const device_type NES_BMC_110IN1 = &device_creator; -const device_type NES_BMC_150IN1 = &device_creator; -const device_type NES_BMC_190IN1 = &device_creator; -const device_type NES_BMC_800IN1 = &device_creator; -const device_type NES_BMC_1200IN1 = &device_creator; -const device_type NES_BMC_GOLD150 = &device_creator; -const device_type NES_BMC_GOLD260 = &device_creator; -const device_type NES_BMC_CH001 = &device_creator; -const device_type NES_BMC_SUPER22 = &device_creator; -const device_type NES_BMC_4IN1RESET = &device_creator; -const device_type NES_BMC_42IN1RESET = &device_creator; - - -nes_action52_device::nes_action52_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_ACTION52, "NES Cart Action 52 PCB", tag, owner, clock, "nes_action52", __FILE__) -{ -} - -nes_caltron_device::nes_caltron_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_CALTRON6IN1, "NES Cart Caltron 6 in 1 PCB", tag, owner, clock, "nes_caltron", __FILE__) -{ -} - -nes_rumblestat_device::nes_rumblestat_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_RUMBLESTATION, "NES Cart Rumblestation PCB", tag, owner, clock, "nes_rumblestat", __FILE__) -{ -} - -nes_svision16_device::nes_svision16_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_SVISION16, "NES Cart Supervision 16 in 1 PCB", tag, owner, clock, "nes_svision16", __FILE__) -{ -} - -nes_n625092_device::nes_n625092_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_N625092, "NES Cart N625092 PCB", tag, owner, clock, "nes_n625092", __FILE__) -{ -} - -nes_a65as_device::nes_a65as_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_A65AS, "NES Cart A65AS PCB", tag, owner, clock, "nes_a65as", __FILE__) -{ -} - -nes_t262_device::nes_t262_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_T262, "NES Cart T-262 PCB", tag, owner, clock, "nes_t262", __FILE__) -{ -} - -nes_novel1_device::nes_novel1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_NOVEL1, "NES Cart Novel Diamond Type 1 PCB", tag, owner, clock, "nes_novel1", __FILE__) -{ -} - -nes_novel2_device::nes_novel2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_NOVEL2, "NES Cart Novel Diamond Type 2 PCB", tag, owner, clock, "nes_novel2", __FILE__) -{ -} - -nes_studyngame_device::nes_studyngame_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_STUDYNGAME, "NES Cart Study n Game PCB", tag, owner, clock, "nes_studyngame", __FILE__) -{ -} - -nes_sgun20in1_device::nes_sgun20in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_SUPERGUN20IN1, "NES Cart Supergun 20 in 1 PCB", tag, owner, clock, "nes_sgun20in1", __FILE__) -{ -} - -nes_vt5201_device::nes_vt5201_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_VT5201, "NES Cart VT5201 PCB", tag, owner, clock, "nes_vt5201", __FILE__) -{ -} - -nes_810544c_device::nes_810544c_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_810544C, "NES Cart 810544-C-A1 PCB", tag, owner, clock, "nes_810544c", __FILE__) -{ -} - -nes_ntd03_device::nes_ntd03_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_NTD03, "NES Cart NTD-03 PCB", tag, owner, clock, "nes_ntd03", __FILE__) -{ -} - -nes_bmc_gb63_device::nes_bmc_gb63_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_BMC_GB63, "NES Cart BMC Ghostbusters 63 in 1 PCB", tag, owner, clock, "nes_bmc_gb63", __FILE__) -{ -} - -nes_bmc_gka_device::nes_bmc_gka_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_BMC_GKA, "NES Cart BMC GK-A PCB", tag, owner, clock, "nes_bmc_gka", __FILE__) -{ -} - -nes_bmc_gkb_device::nes_bmc_gkb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_BMC_GKB, "NES Cart BMC GK-B PCB", tag, owner, clock, "nes_bmc_gkb", __FILE__) -{ -} - -nes_bmc_ws_device::nes_bmc_ws_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_BMC_WS, "NES Cart BMC WS PCB", tag, owner, clock, "nes_bmc_ws", __FILE__) -{ -} - -nes_bmc_11160_device::nes_bmc_11160_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_BMC_11160, "NES Cart BMC-11160 PCB", tag, owner, clock, "nes_bmc_11160", __FILE__) -{ -} - -nes_bmc_g146_device::nes_bmc_g146_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_BMC_G146, "NES Cart BMC-G-146 PCB", tag, owner, clock, "nes_bmc_g146", __FILE__) -{ -} - -nes_bmc_8157_device::nes_bmc_8157_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_BMC_8157, "NES Cart BMC-8157 PCB", tag, owner, clock, "nes_bmc_8157", __FILE__) -{ -} - -nes_bmc_hik300_device::nes_bmc_hik300_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_BMC_HIK300, "NES Cart BMC HIK 300 in 1 PCB", tag, owner, clock, "nes_bmc_hik300", __FILE__) -{ -} - -nes_bmc_s700_device::nes_bmc_s700_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_BMC_S700, "NES Cart BMC Super 700 in 1 PCB", tag, owner, clock, "nes_bmc_s700", __FILE__) -{ -} - -nes_bmc_ball11_device::nes_bmc_ball11_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_BMC_BALL11, "NES Cart BMC Ball 11 in 1 PCB", tag, owner, clock, "nes_bmc_ball11", __FILE__) -{ -} - -nes_bmc_22games_device::nes_bmc_22games_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_BMC_22GAMES, "NES Cart BMC 22 Games PCB", tag, owner, clock, "nes_bmc_22games", __FILE__) -{ -} - -nes_bmc_64y2k_device::nes_bmc_64y2k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_BMC_64Y2K, "NES Cart BMC 64 in 1 Y2K PCB", tag, owner, clock, "nes_bmc_64y2k", __FILE__) -{ -} - -nes_bmc_12in1_device::nes_bmc_12in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_BMC_12IN1, "NES Cart BMC 12 in 1 PCB", tag, owner, clock, "nes_bmc_12in1", __FILE__) -{ -} - -nes_bmc_20in1_device::nes_bmc_20in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_BMC_20IN1, "NES Cart BMC 20 in 1 PCB", tag, owner, clock, "nes_bmc_20in1", __FILE__) -{ -} - -nes_bmc_21in1_device::nes_bmc_21in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_BMC_21IN1, "NES Cart BMC 21 in 1 PCB", tag, owner, clock, "nes_bmc_21in1", __FILE__) -{ -} - -nes_bmc_31in1_device::nes_bmc_31in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_BMC_31IN1, "NES Cart BMC 31 in 1 PCB", tag, owner, clock, "nes_bmc_31in1", __FILE__) -{ -} - -nes_bmc_35in1_device::nes_bmc_35in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_BMC_35IN1, "NES Cart BMC 35 in 1 PCB", tag, owner, clock, "nes_bmc_35in1", __FILE__) -{ -} - -nes_bmc_36in1_device::nes_bmc_36in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_BMC_36IN1, "NES Cart BMC 36 in 1 PCB", tag, owner, clock, "nes_bmc_36in1", __FILE__) -{ -} - -nes_bmc_64in1_device::nes_bmc_64in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_BMC_64IN1, "NES Cart BMC 64 in 1 PCB", tag, owner, clock, "nes_bmc_64in1", __FILE__) -{ -} - -nes_bmc_70in1_device::nes_bmc_70in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_BMC_70IN1, "NES Cart BMC 70 in 1 PCB", tag, owner, clock, "nes_bmc_70in1", __FILE__) -{ -} - -nes_bmc_72in1_device::nes_bmc_72in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_BMC_72IN1, "NES Cart BMC 72 in 1 PCB", tag, owner, clock, "nes_bmc_72in1", __FILE__) -{ -} - -nes_bmc_76in1_device::nes_bmc_76in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_BMC_76IN1, "NES Cart BMC 76 in 1 PCB", tag, owner, clock, "nes_bmc_76in1", __FILE__) -{ -} - -nes_bmc_110in1_device::nes_bmc_110in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_BMC_110IN1, "NES Cart BMC 110 in 1 PCB", tag, owner, clock, "nes_bmc_110in1", __FILE__) -{ -} - -nes_bmc_150in1_device::nes_bmc_150in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_BMC_150IN1, "NES Cart BMC 150 in 1 PCB", tag, owner, clock, "nes_bmc_150in1", __FILE__) -{ -} - -nes_bmc_190in1_device::nes_bmc_190in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_BMC_190IN1, "NES Cart BMC 190 in 1 PCB", tag, owner, clock, "nes_bmc_190in1", __FILE__) -{ -} - -nes_bmc_800in1_device::nes_bmc_800in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_BMC_800IN1, "NES Cart BMC 800 in 1 PCB", tag, owner, clock, "nes_bmc_800in1", __FILE__) -{ -} - -nes_bmc_1200in1_device::nes_bmc_1200in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_BMC_1200IN1, "NES Cart BMC 1200 in 1 PCB", tag, owner, clock, "nes_bmc_1200in1", __FILE__) -{ -} - -nes_bmc_gold150_device::nes_bmc_gold150_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_BMC_GOLD150, "NES Cart BMC Golden 150 in 1 PCB", tag, owner, clock, "nes_bmc_gold150", __FILE__) -{ -} - -nes_bmc_gold260_device::nes_bmc_gold260_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_BMC_GOLD260, "NES Cart BMC Golden 260 in 1 PCB", tag, owner, clock, "nes_bmc_gold260", __FILE__) -{ -} - -nes_bmc_ch001_device::nes_bmc_ch001_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_BMC_CH001, "NES Cart BMC CH-001 PCB", tag, owner, clock, "nes_bmc_ch001", __FILE__) -{ -} - -nes_bmc_super22_device::nes_bmc_super22_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_BMC_SUPER22, "NES Cart BMC Super 22 Games PCB", tag, owner, clock, "nes_bmc_super22", __FILE__) -{ -} - -nes_bmc_4in1reset_device::nes_bmc_4in1reset_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_BMC_4IN1RESET, "NES Cart BMC 4 in 1 (Reset Based) PCB", tag, owner, clock, "nes_bmc_4in1reset", __FILE__) -{ -} - -nes_bmc_42in1reset_device::nes_bmc_42in1reset_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_BMC_42IN1RESET, "NES Cart BMC 42 in 1 (Reset Based) PCB", tag, owner, clock, "nes_bmc_42in1reset", __FILE__) -{ -} - - - - -void nes_action52_device::device_start() -{ - common_start(); -} - -void nes_action52_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0); - chr8(0, m_chr_source); -} - -void nes_caltron_device::device_start() -{ - common_start(); - save_item(NAME(m_latch)); -} - -void nes_caltron_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0); - chr8(0, m_chr_source); - - m_latch = 0; -} - -void nes_rumblestat_device::device_start() -{ - common_start(); - save_item(NAME(m_prg)); - save_item(NAME(m_chr)); -} - -void nes_rumblestat_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0); - chr8(0, m_chr_source); - - m_prg = 0; - m_chr = 0; -} - -void nes_svision16_device::device_start() -{ - common_start(); - save_item(NAME(m_latch1)); - save_item(NAME(m_latch2)); -} - -void nes_svision16_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0); - chr8(0, m_chr_source); - - m_latch1 = 0; - m_latch2 = 0; -} - -void nes_n625092_device::device_start() -{ - common_start(); - save_item(NAME(m_latch1)); - save_item(NAME(m_latch2)); -} - -void nes_n625092_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(0); - prg16_cdef(0); - chr8(0, m_chr_source); - - m_latch1 = 0; - m_latch2 = 0; -} - -void nes_a65as_device::device_start() -{ - common_start(); -} - -void nes_a65as_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(0); - prg16_cdef(7); - set_nt_mirroring(PPU_MIRROR_VERT); - chr8(0, m_chr_source); -} - -void nes_t262_device::device_start() -{ - common_start(); - save_item(NAME(m_latch1)); - save_item(NAME(m_latch2)); -} - -void nes_t262_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(0); - prg16_cdef(7); - chr8(0, m_chr_source); - - m_latch1 = 0; - m_latch2 = 0; -} - -void nes_novel1_device::device_start() -{ - common_start(); -} - -void nes_novel1_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0); - chr8(0, m_chr_source); - set_nt_mirroring(PPU_MIRROR_VERT); -} - -void nes_novel2_device::device_start() -{ - common_start(); -} - -void nes_novel2_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0); - chr8(0, m_chr_source); -} - -void nes_studyngame_device::device_start() -{ - common_start(); -} - -void nes_studyngame_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0); - chr8(0, m_chr_source); -} - -void nes_sgun20in1_device::device_start() -{ - common_start(); -} - -void nes_sgun20in1_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(0); - prg16_cdef(0); - chr8(0, m_chr_source); -} - -void nes_vt5201_device::device_start() -{ - common_start(); - save_item(NAME(m_latch)); - save_item(NAME(m_dipsetting)); -} - -void nes_vt5201_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0); - chr8(0, m_chr_source); - - m_latch = 0; - m_dipsetting = 0; -} - -void nes_810544c_device::device_start() -{ - common_start(); -} - -void nes_810544c_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(0); - prg16_cdef(0); - chr8(0, m_chr_source); - set_nt_mirroring(PPU_MIRROR_VERT); -} - -void nes_ntd03_device::device_start() -{ - common_start(); -} - -void nes_ntd03_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0); - chr8(0, m_chr_source); -} - -void nes_bmc_gb63_device::device_start() -{ - common_start(); - save_item(NAME(m_latch)); - save_item(NAME(m_dipsetting)); - save_item(NAME(m_reg)); - save_item(NAME(m_vram_disable)); -} - -void nes_bmc_gb63_device::pcb_reset() -{ - prg16_89ab(0); - prg16_cdef(0xfff); - chr8(0, CHRRAM); - - m_latch = 0; - m_dipsetting = 0; - m_reg[0] = 0; - m_reg[1] = 0; - update_banks(); - m_vram_disable = 0; -} - -void nes_bmc_gka_device::device_start() -{ - common_start(); - save_item(NAME(m_latch1)); - save_item(NAME(m_latch2)); -} - -void nes_bmc_gka_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(0); - prg16_cdef(0); - chr8(0, m_chr_source); - - m_latch1 = 0; - m_latch2 = 0; -} - -void nes_bmc_gkb_device::device_start() -{ - common_start(); -} - -void nes_bmc_gkb_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0); - chr8(0, m_chr_source); -} - -void nes_bmc_ws_device::device_start() -{ - common_start(); - save_item(NAME(m_latch)); -} - -void nes_bmc_ws_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0); - chr8(0, m_chr_source); - - m_latch = 0; -} - -void nes_bmc_11160_device::device_start() -{ - common_start(); -} - -void nes_bmc_11160_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0); - chr8(0, m_chr_source); -} - -void nes_bmc_g146_device::device_start() -{ - common_start(); -} - -void nes_bmc_g146_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0); - chr8(0, m_chr_source); -} - -void nes_bmc_8157_device::device_start() -{ - common_start(); -} - -void nes_bmc_8157_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0); - chr8(0, m_chr_source); -} - -void nes_bmc_hik300_device::device_start() -{ - common_start(); -} - -void nes_bmc_hik300_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0xff); - chr8(0xff, CHRROM); -} - -void nes_bmc_s700_device::device_start() -{ - common_start(); -} - -void nes_bmc_s700_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0); - chr8(0, m_chr_source); -} - -void nes_bmc_ball11_device::device_start() -{ - common_start(); - save_item(NAME(m_reg)); -} - -void nes_bmc_ball11_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0); - chr8(0, m_chr_source); - - m_reg[0] = 1; - m_reg[1] = 0; - set_banks(); -} - -void nes_bmc_22games_device::device_start() -{ - common_start(); -} - -void nes_bmc_22games_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(0); - prg16_cdef(7); - chr8(0, m_chr_source); -} - -void nes_bmc_64y2k_device::device_start() -{ - common_start(); - save_item(NAME(m_reg)); -} - -void nes_bmc_64y2k_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - chr8(0, m_chr_source); - - m_reg[0] = 0x80; - m_reg[1] = 0x43; - m_reg[2] = m_reg[3] = 0; - set_prg(); - set_nt_mirroring(PPU_MIRROR_VERT); -} - -void nes_bmc_12in1_device::device_start() -{ - common_start(); - save_item(NAME(m_reg)); -} - -void nes_bmc_12in1_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0); - chr8(0, m_chr_source); - m_reg[0] = 0; - m_reg[1] = 0; - m_reg[2] = 0; - update_banks(); -} - -void nes_bmc_20in1_device::device_start() -{ - common_start(); -} - -void nes_bmc_20in1_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(0); - prg16_cdef(m_prg_chunks - 1); - chr8(0, m_chr_source); - set_nt_mirroring(PPU_MIRROR_VERT); -} - -void nes_bmc_21in1_device::device_start() -{ - common_start(); -} - -void nes_bmc_21in1_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0); - chr8(0, m_chr_source); -} - -void nes_bmc_31in1_device::device_start() -{ - common_start(); -} - -void nes_bmc_31in1_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(0); - prg16_cdef(1); - chr8(0, m_chr_source); -} - -void nes_bmc_35in1_device::device_start() -{ - common_start(); -} - -void nes_bmc_35in1_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(0); - prg16_cdef(0); - chr8(0, m_chr_source); -} - -void nes_bmc_36in1_device::device_start() -{ - common_start(); -} - -void nes_bmc_36in1_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(m_prg_chunks - 1); - prg16_cdef(m_prg_chunks - 1); - chr8(0, m_chr_source); -} - -void nes_bmc_64in1_device::device_start() -{ - common_start(); -} - -void nes_bmc_64in1_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(0); - prg16_cdef(0); - chr8(0, m_chr_source); -} - -void nes_bmc_70in1_device::device_start() -{ - common_start(); - save_item(NAME(m_reg)); - save_item(NAME(m_mode)); -} - -void nes_bmc_70in1_device::pcb_reset() -{ - prg16_89ab(m_prg_chunks - 1); - prg16_cdef(m_prg_chunks - 1); - chr8(0, CHRROM); - m_reg[0] = 0; - m_reg[1] = 0; - m_mode = 0; -} - -void nes_bmc_72in1_device::device_start() -{ - common_start(); -} - -void nes_bmc_72in1_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0); - chr8(0, m_chr_source); -} - -void nes_bmc_76in1_device::device_start() -{ - common_start(); - save_item(NAME(m_latch1)); - save_item(NAME(m_latch2)); -} - -void nes_bmc_76in1_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0); - chr8(0, m_chr_source); - - m_latch1 = 0; - m_latch2 = 0; -} - -void nes_bmc_110in1_device::device_start() -{ - common_start(); -} - -void nes_bmc_110in1_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(0); - prg16_cdef(1); - chr8(0, m_chr_source); - set_nt_mirroring(PPU_MIRROR_VERT); -} - -void nes_bmc_150in1_device::device_start() -{ - common_start(); -} - -void nes_bmc_150in1_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(0); - prg16_cdef(0); - chr8(0, m_chr_source); -} - -void nes_bmc_190in1_device::device_start() -{ - common_start(); -} - -void nes_bmc_190in1_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(0); - prg16_cdef(0); - chr8(0, m_chr_source); -} - -void nes_bmc_800in1_device::device_start() -{ - common_start(); - save_item(NAME(m_reg)); - save_item(NAME(m_mode)); -} - -void nes_bmc_800in1_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(m_prg_chunks - 1); - prg16_cdef(m_prg_chunks - 1); - chr8(0, m_chr_source); - m_reg[0] = 0; - m_reg[1] = 0; - m_mode = 0; -} - -void nes_bmc_1200in1_device::device_start() -{ - common_start(); - save_item(NAME(m_vram_protect)); -} - -void nes_bmc_1200in1_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(0); - prg16_cdef(0); - chr8(0, m_chr_source); - m_vram_protect = 0; -} - -void nes_bmc_gold150_device::device_start() -{ - common_start(); - save_item(NAME(m_latch)); -} - -void nes_bmc_gold150_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0); - chr8(0, m_chr_source); - - m_latch = 0; -} - -void nes_bmc_gold260_device::device_start() -{ - common_start(); -} - -void nes_bmc_gold260_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0); - chr8(0, m_chr_source); -} - -void nes_bmc_ch001_device::device_start() -{ - common_start(); - save_item(NAME(m_latch)); -} - -void nes_bmc_ch001_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0); - chr8(0, m_chr_source); - - m_latch = 0; -} - -void nes_bmc_super22_device::device_start() -{ - common_start(); -} - -void nes_bmc_super22_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0); - chr8(0, m_chr_source); -} - - -// This PCB is fully emulated here :) -void nes_bmc_4in1reset_device::device_start() -{ - common_start(); - m_latch = -1; - save_item(NAME(m_latch)); -} - -void nes_bmc_4in1reset_device::pcb_reset() -{ - m_latch++; - m_latch &= 3; - chr8(m_latch, CHRROM); - prg16_89ab(m_latch); - prg16_cdef(m_latch); -} - - -void nes_bmc_42in1reset_device::device_start() -{ - common_start(); - m_latch = -1; - save_item(NAME(m_reg)); -} - -void nes_bmc_42in1reset_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - m_latch++; - m_latch &= 1; - chr8(0, m_chr_source); - prg32(m_latch << 4); - - m_reg[0] = 0; - m_reg[1] = 0; -} - - - - -/*------------------------------------------------- - mapper specific handlers - -------------------------------------------------*/ - -/*------------------------------------------------- - - Active Entertainment Action 52 board emulation - - iNES: mapper 228 - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_action52_device::write_h) -{ - UINT8 pmode = offset & 0x20; - int pbank = (offset & 0x1fc0) >> 6; - int cbank = (data & 0x03) | ((offset & 0x0f) << 2); - LOG_MMC(("ae_act52_w, offset: %04x, data: %02x\n", offset, data)); - - set_nt_mirroring(BIT(offset, 13) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); - - chr8(cbank, CHRROM); - - if (pmode) - { - prg16_89ab(pbank); - prg16_cdef(pbank); - } - else - prg32(pbank >> 1); -} - -/*------------------------------------------------- - - Caltron 6 in 1 Board - - Games: 6 in 1 by Caltron - - iNES: mapper 41 - - In MESS: Supported. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_caltron_device::write_m) -{ - LOG_MMC(("caltron write_m, offset: %04x, data: %02x\n", offset, data)); - - m_latch = offset & 0xff; - set_nt_mirroring(BIT(data, 5) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); - prg32(offset & 0x07); -} - -WRITE8_MEMBER(nes_caltron_device::write_h) -{ - LOG_MMC(("caltron write_h, offset: %04x, data: %02x\n", offset, data)); - - if (m_latch & 0x04) - chr8(((m_latch & 0x18) >> 1) | (data & 0x03), CHRROM); -} - -/*------------------------------------------------- - - Rumblestation Board - - Games: Rumblestation 15 in 1 - - iNES: mapper 46 - - In MESS: Supported. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_rumblestat_device::write_m) -{ - LOG_MMC(("rumblestation write_m, offset: %04x, data: %02x\n", offset, data)); - - m_prg = (m_prg & 0x01) | ((data & 0x0f) << 1); - m_chr = (m_chr & 0x07) | ((data & 0xf0) >> 1); - prg32(m_prg); - chr8(m_chr, CHRROM); -} - -WRITE8_MEMBER(nes_rumblestat_device::write_h) -{ - LOG_MMC(("rumblestation write_h, offset: %04x, data: %02x\n", offset, data)); - - // this pcb is subject to bus conflict - data = account_bus_conflict(offset, data); - - m_prg = (m_prg & ~0x01) | (data & 0x01); - m_chr = (m_chr & ~0x07) | ((data & 0x70) >> 4); - prg32(m_prg); - chr8(m_chr, CHRROM); -} - -/*------------------------------------------------- - - Supervision 16 in 1 Board - - Games: Supervision 16 in 1 - - iNES: mapper 53 - - In MESS: Partially Supported. (the dump contains 32KB of - EEPROM which is not currently handled well) - - -------------------------------------------------*/ - -void nes_svision16_device::update_prg() -{ - int base = (m_latch1 & 0x0f) << 3; - if (m_latch1 & 0x10) - { - prg16_89ab((base | (m_latch2 & 7)) + 2); // +2 due to the eeprom - prg16_cdef((base | 0x07) + 2); // +2 due to the eeprom - } - else - { - prg16_89ab(0); - prg16_cdef(1); - } - -} - -READ8_MEMBER(nes_svision16_device::read_m) -{ - int bank = (((m_latch1 & 0x0f) << 4) | 0x0f) + 4 ; // +4 due to the eeprom - LOG_MMC(("svision16 read_m, offset: %04x\n", offset)); - return m_prg[((bank * 0x2000) + (offset & 0x1fff)) & m_prg_mask]; -} - -WRITE8_MEMBER(nes_svision16_device::write_m) -{ - LOG_MMC(("svision16 write_m, offset: %04x, data: %02x\n", offset, data)); - - m_latch1 = data; - update_prg(); - set_nt_mirroring(BIT(data, 5) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); -} - -WRITE8_MEMBER(nes_svision16_device::write_h) -{ - LOG_MMC(("svision16 write_h, offset: %04x, data: %02x\n", offset, data)); - m_latch2 = data; - update_prg(); -} - -/*------------------------------------------------- - - Bootleg Board N625092 - - Games: 400 in 1, 700 in 1, 1000 in 1 - - iNES: mapper 221 - - In MESS: Supported. - - -------------------------------------------------*/ - -void nes_n625092_device::set_prg(UINT8 reg1, UINT8 reg2) -{ - UINT8 helper1, helper2; - - helper1 = !(reg1 & 0x01) ? reg2 : (reg1 & 0x80) ? reg2 : (reg2 & 0x06) | 0x00; - helper2 = !(reg1 & 0x01) ? reg2 : (reg1 & 0x80) ? 0x07 : (reg2 & 0x06) | 0x01; - - prg16_89ab(helper1 | ((reg1 & 0x70) >> 1)); - prg16_cdef(helper2 | ((reg1 & 0x70) >> 1)); -} - -WRITE8_MEMBER(nes_n625092_device::write_h) -{ - LOG_MMC(("n625092 write_h, offset: %04x, data: %02x\n", offset, data)); - - if (offset < 0x4000) - { - set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); - offset = (offset >> 1) & 0xff; - - if (m_latch1 != offset) - { - m_latch1 = offset; - set_prg(m_latch1, m_latch2); - } - } - else - { - offset &= 0x07; - - if (m_latch2 != offset) - { - m_latch2 = offset; - set_prg(m_latch1, m_latch2); - } - } -} - - -/*------------------------------------------------- - - Board BMC-A65AS - - Games: 3-in-1 (N068) - - In MESS: Supported - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_a65as_device::write_h) -{ - UINT8 helper = (data & 0x30) >> 1; - LOG_MMC(("a65as write_h, offset: %04x, data: %02x\n", offset, data)); - - if (data & 0x80) - set_nt_mirroring(BIT(data, 5) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW); - else - set_nt_mirroring(BIT(data, 3) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); - - if (data & 0x40) - prg32(data >> 1); - else - { - prg16_89ab(helper | (data & 0x07)); - prg16_cdef(helper | 0x07); - } -} - -/*------------------------------------------------- - - Board BMC-T-262 - - Games: 4-in-1 (D-010), 8-in-1 (A-020) - - In MESS: Supported - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_t262_device::write_h) -{ - UINT8 mmc_helper; - LOG_MMC(("t262 write_h, offset: %04x, data: %02x\n", offset, data)); - - if (m_latch2 || offset == 0) - { - m_latch1 = (m_latch1 & 0x38) | (data & 0x07); - prg16_89ab(m_latch1); - } - else - { - m_latch2 = 1; - set_nt_mirroring(BIT(data, 1) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); - mmc_helper = ((offset >> 3) & 0x20) | ((offset >> 2) & 0x18); - m_latch1 = mmc_helper | (m_latch1 & 0x07); - prg16_89ab(m_latch1); - prg16_cdef(mmc_helper | 0x07); - } -} - - -/*------------------------------------------------- - - BMC-NOVELDIAMOND and BMC-999999in1 - - Unknown Bootleg Multigame Board - Games: I only found 'Novel Diamond 999999-in-1.unf' using - this mapper (hence the code is used for BMC_NOVELDIAMOND - board). The code is included here in case a mapper 54 - dump arises. - - iNES: mappers 54 and 213 - - In MESS: Partial Support. - - -------------------------------------------------*/ - -// Are this correct or should they work the same? -WRITE8_MEMBER(nes_novel1_device::write_h) -{ - LOG_MMC(("novel1 write_h, offset: %04x, data: %02x\n", offset, data)); - - prg32(offset & 0x03); - chr8(offset & 0x07, CHRROM); -} - -WRITE8_MEMBER(nes_novel2_device::write_h) -{ - LOG_MMC(("novel2 write_h, offset: %04x, data: %02x\n", offset, data)); - - prg32(offset >> 1); - chr8(offset >> 3, CHRROM); -} - - -/*------------------------------------------------- - - Board UNL-STUDYNGAME - - Games: Study n Game 32 in 1 - - iNES: mapper 39 - - In MESS: Partially Supported (problems with PRG bankswitch, - only keyboard exercise work). - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_studyngame_device::write_h) -{ - LOG_MMC(("studyngame write_h, offset: %04x, data: %02x\n", offset, data)); - prg32(data); -} - -/*------------------------------------------------- - - BMC-SUPERGUN-20IN1 - - Unknown Bootleg Multigame Board - Games: Super Gun 20 in 1 - - iNES: mapper 214 - - In MESS: Supported. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_sgun20in1_device::write_h) -{ - LOG_MMC(("supergun20in1 write_h, offset: %04x, data: %02x\n", offset, data)); - - prg16_89ab(offset >> 2); - prg16_cdef(offset >> 2); - chr8(offset, CHRROM); -} - -/*------------------------------------------------- - - BMC-VT5201 - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_vt5201_device::write_h) -{ - LOG_MMC(("vt5201 wirte_h, offset: %04x, data: %02x\n", offset, data)); - - m_latch = BIT(offset, 8); - - // not sure about this mirroring bit!! - // without it TN 95 in 1 has glitches in Lunar Ball; with it TN 95 in 1 has glitches in Galaxian! - set_nt_mirroring(BIT(data, 3) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); - if (BIT(offset, 7)) - { - prg16_89ab((offset >> 4) & 0x07); - prg16_cdef((offset >> 4) & 0x07); - } - else - prg32((offset >> 5) & 0x03); - chr8(offset, CHRROM); -} - -READ8_MEMBER(nes_vt5201_device::read_h) -{ - LOG_MMC(("bmc_vt5201 read_h, offset: %04x\n", offset)); - // m_dipsetting = ioport("CARTDIPS")->read(); - - if (m_latch) - return m_dipsetting; // cart mode, depending on the Dip Switches (always zero atm, given we have no way to add cart-based DIPs) - else - return hi_access_rom(offset); -} - -/*------------------------------------------------- - - BMC-810544-C-A1 - - Games: 200-in-1 Elfland - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_810544c_device::write_h) -{ - UINT8 bank = (offset >> 7); - LOG_MMC(("810544 write_h, offset: %04x, data: %02x\n", offset, data)); - - if (!BIT(offset, 6)) - { - prg16_89ab((bank << 1) | BIT(offset, 5)); - prg16_cdef((bank << 1) | BIT(offset, 5)); - } - else - prg32(bank); - - set_nt_mirroring(BIT(offset, 4) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); - - chr8(offset & 0x0f, CHRROM); -} - -/*------------------------------------------------- - - BMC-NTD-03 - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_ntd03_device::write_h) -{ - UINT8 pbank = (offset >> 10) & 0x1e; - UINT8 cbank = ((offset & 0x300) >> 5) | (offset & 0x07); - LOG_MMC(("ntd03 write_h, offset: %04x, data: %02x\n", offset, data)); - - if (BIT(offset, 7)) - { - prg16_89ab(pbank | BIT(offset, 6)); - prg16_cdef(pbank | BIT(offset, 6)); - } - else - prg32(pbank >> 1); - - set_nt_mirroring(BIT(offset, 10) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); - - chr8(cbank, CHRROM); -} - -/*------------------------------------------------- - - BMC-GHOSTBUSTERS63IN1 - - in MESS: only preliminar support - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_bmc_gb63_device::chr_w) -{ - int bank = offset >> 10; - - if (!m_vram_disable) - m_chr_access[bank][offset & 0x3ff] = data; -} - -void nes_bmc_gb63_device::update_banks() -{ - set_nt_mirroring(BIT(m_reg[0], 6) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ); - - if (BIT(m_reg[0], 5)) - { - prg16_89ab(m_reg[0] & 0x1f); - prg16_cdef(m_reg[0] & 0x1f); - } - else - prg32((m_reg[0] & 0x1f) >> 1); - -// according to FCEUMM source, the game should be able to disable the VRAM, but this stops the game from working -// maybe the VRAM disable does not work at start? -// m_vram_disable = BIT(m_reg[1], 1) ? 0 : 1; -} - -WRITE8_MEMBER(nes_bmc_gb63_device::write_h) -{ - LOG_MMC(("bmc_gb63 write_h, offset: %04x, data: %02x\n", offset, data)); - - m_reg[offset & 1] = data; - m_latch = BIT(m_reg[0], 7) | (BIT(m_reg[1], 0) << 1); - update_banks(); -} - -READ8_MEMBER(nes_bmc_gb63_device::read_h) -{ - LOG_MMC(("bmc_gb63 read_h, offset: %04x\n", offset)); - // m_dipsetting = ioport("CARTDIPS")->read(); - - if (m_latch == 1) - return m_open_bus; // open bus - else - return hi_access_rom(offset); -} - - -/*------------------------------------------------- - - Board BMC-GKA - - Unknown Bootleg Multigame Board - Games: 6 in 1, 54 in 1, 106 in 1 - - iNES: mapper 57 - - In MESS: Supported. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_bmc_gka_device::write_h) -{ - LOG_MMC(("bmc_gka write_h, offset: %04x, data: %02x\n", offset, data)); - - if (offset & 0x0800) - m_latch2 = data; - else - m_latch1 = data; - - if (m_latch2 & 0x80) - prg32(2 | (m_latch2 >> 6)); - else - { - prg16_89ab((m_latch2 >> 5) & 0x03); - prg16_cdef((m_latch2 >> 5) & 0x03); - } - - set_nt_mirroring((m_latch2 & 0x08) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); - - chr8((m_latch1 & 0x03) | (m_latch2 & 0x07) | ((m_latch2 & 0x10) >> 1), CHRROM); -} - - -/*------------------------------------------------- - - Board BMC-GKB - - Unknown Bootleg Multigame Board - Games: 68 in 1, 73 in 1, 98 in 1 - - iNES: mapper 58 - - In MESS: Supported. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_bmc_gkb_device::write_h) -{ - UINT8 bank = (offset & 0x40) ? 0 : 1; - LOG_MMC(("bmc_gkb write_h, offset: %04x, data: %02x\n", offset, data)); - - prg16_89ab(offset & ~bank); - prg16_cdef(offset | bank); - chr8(offset >> 3, m_chr_source); - set_nt_mirroring(BIT(data, 7) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); -} - -/*------------------------------------------------- - - Board BMC-WS - - Games: Super 40-in-1 - - In MESS: Partially Supported (some games, like Galaxian, have - issues) - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_bmc_ws_device::write_m) -{ - UINT8 mmc_helper; - LOG_MMC(("bmc_ws write_m, offset: %04x, data: %02x\n", offset, data)); - - if (offset < 0x1000) - { - switch (offset & 0x01) - { - case 0: - if (!m_latch) - { - m_latch = data & 0x20; - set_nt_mirroring(BIT(data, 4) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); - mmc_helper = (~data & 0x08) >> 3; - prg16_89ab(data & ~mmc_helper); - prg16_cdef(data | mmc_helper); - } - break; - case 1: - if (!m_latch) - chr8(data, CHRROM); - break; - } - } -} - -/*------------------------------------------------- - - Board BMC-11160 (by TXC?) - - Games: 6 in 1 (MGC-023) - - In MESS: Partially Supported - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_bmc_11160_device::write_h) -{ - LOG_MMC(("bmc_11160 write_h, offset: %04x, data: %02x\n", offset, data)); - - prg32((data & 0x70) >> 4); - chr8(((data & 0x70) >> 2) | (data & 3), m_chr_source); - set_nt_mirroring(BIT(data, 7) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); -} - -/*------------------------------------------------- - - Board BMC-G-146 - - Games: 1994 Super HIK 14 in 1 (G-136) - - In MESS: Partially Supported - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_bmc_g146_device::write_h) -{ - LOG_MMC(("bmc_g146 write_h, offset: %04x, data: %02x\n", offset, data)); - - if (offset & 0x800) - { - // UNROM mode - int helper = offset & BIT(offset, 6); - prg16_89ab((offset & 0x1f) | helper); - prg16_cdef((offset & 0x18) | 7); - } - else if (offset & 0x40) - { - // 16KB mode - prg16_89ab(offset & 0x1f); - prg16_cdef(offset & 0x1f); - } - else - prg32((offset & 0x1f) >> 4); - - set_nt_mirroring(!BIT(offset, 7) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); -} - -/*------------------------------------------------- - - Board BMC-8157 - - Games: 4 in 1 1993 (CK-001) - - In MESS: Partially Supported - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_bmc_8157_device::write_h) -{ - LOG_MMC(("bmc_8157 write_h, offset: %04x, data: %02x\n", offset, data)); - - prg16_89ab((offset >> 2) & 0x1f); - if (offset & 0x200) - prg16_cdef(offset & 0x1f); - else - prg16_cdef((offset & 0x18) | 7); - - set_nt_mirroring(!BIT(offset, 1) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); -} - -READ8_MEMBER(nes_bmc_8157_device::read_h) -{ - LOG_MMC(("bmc_8157 read_h, offset: %04x\n", offset)); - // m_dipsetting = ioport("CARTDIPS")->read(); - -// UINT8 val = hi_access_rom(offset); -// return val | m_noise; // the first write_h sets m_noise=0xff or 0 depending on dsw - - return hi_access_rom(offset); -} - - -/*------------------------------------------------- - - BMC-SUPERHIK_300IN1 - - Unknown Bootleg Multigame Board - Games: 100000 in 1, Super HIK 300 in 1, 1997 in 1 - - iNES: mapper 212 - - In MESS: Supported. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_bmc_hik300_device::write_h) -{ - LOG_MMC(("bmc_hik300 write_h, offset: %04x, data: %02x\n", offset, data)); - - set_nt_mirroring(BIT(data, 3) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); - chr8(offset, CHRROM); - - if (offset < 0x4000) - { - prg16_89ab(offset); - prg16_cdef(offset); - } - else - prg32(offset >> 1); -} - -/*------------------------------------------------- - - BMC-SUPER-700IN1 - - Unknown Bootleg Multigame Board - Games: Super 700 in 1 - - iNES: mapper 62 - - In MESS: Supported. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_bmc_s700_device::write_h) -{ - LOG_MMC(("bmc_s700 write_h, offset :%04x, data: %02x\n", offset, data)); - - chr8(((offset & 0x1f) << 2) | (data & 0x03), CHRROM); - - if (offset & 0x20) - { - prg16_89ab((offset & 0x40) | ((offset >> 8) & 0x3f)); - prg16_cdef((offset & 0x40) | ((offset >> 8) & 0x3f)); - } - else - { - prg32(((offset & 0x40) | ((offset >> 8) & 0x3f)) >> 1); - } - - set_nt_mirroring(BIT(data, 7) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); -} - -/*------------------------------------------------- - - BMC-BALLGAMES-11IN1 - - Known Boards: Unknown Multigame Bootleg Board - Games: 11 in 1 Ball Games - - iNES: mapper 51 - - In MESS: Partially Supported. - - -------------------------------------------------*/ - -void nes_bmc_ball11_device::set_banks() -{ - set_nt_mirroring((m_reg[0] == 3) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); - - if (m_reg[0] & 0x01) - { - prg32(m_reg[1]); - } - else - { - prg16_89ab((m_reg[1] << 1) | (m_reg[0] >> 1)); - prg16_cdef((m_reg[1] << 1) | 0x07); - } -} - -WRITE8_MEMBER(nes_bmc_ball11_device::write_m) -{ - LOG_MMC(("bmc_ball11 write_m, offset: %04x, data: %02x\n", offset, data)); - - m_reg[0] = ((data >> 1) & 0x01) | ((data >> 3) & 0x02); - set_banks(); -} - -WRITE8_MEMBER(nes_bmc_ball11_device::write_h) -{ - LOG_MMC(("bmc_ball11 write_h, offset: %04x, data: %02x\n", offset, data)); - - switch (offset & 0x6000) - { - case 0x4000: // here we also update reg[0] upper bit - m_reg[0] = (m_reg[0] & 0x01) | ((data >> 3) & 0x02); - case 0x0000: - case 0x2000: - case 0x6000: - m_reg[1] = data & 0x0f; - set_banks(); - break; - } -} - -/*------------------------------------------------- - - BMC-22GAMES - - Unknown Bootleg Multigame Board - Games: 22 in 1 - - iNES: mapper 230 - - In MESS: Partially Supported. It would need a reset - to work (not possible yet) - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_bmc_22games_device::write_h) -{ - LOG_MMC(("bmc_22games write_h, offset: %04x, data: %02x\n", offset, data)); - - if (1) // this should flip at reset - { - prg16_89ab(data & 0x07); - } - else - { - if (data & 0x20) - { - prg16_89ab((data & 0x1f) + 8); - prg16_cdef((data & 0x1f) + 8); - } - else - { - prg16_89ab((data & 0x1f) + 8); - prg16_cdef((data & 0x1f) + 9); - } - set_nt_mirroring(BIT(data, 6) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ); - } -} - -/*------------------------------------------------- - - Board BMC-64IN1NOREPEAT - - Games: 64-in-1 Y2K - - In MESS: Supported - - -------------------------------------------------*/ - -void nes_bmc_64y2k_device::set_prg() -{ - UINT8 helper1 = (m_reg[1] & 0x1f); - UINT8 helper2 = (helper1 << 1) | ((m_reg[1] & 0x40) >> 6); - - if (m_reg[0] & 0x80) - { - if (m_reg[1] & 0x80) - prg32(helper1); - else - { - prg16_89ab(helper2); - prg16_cdef(helper2); - } - } - else - prg16_cdef(helper2); -} - -WRITE8_MEMBER(nes_bmc_64y2k_device::write_l) -{ - LOG_MMC(("bmc64y2k write_l, offset: %04x, data: %02x\n", offset, data)); - offset += 0x100; - - switch (offset) - { - case 0x1000: - case 0x1001: - case 0x1002: - case 0x1003: - m_reg[offset & 0x03] = data; - set_prg(); - chr8(((m_reg[0] >> 1) & 0x03) | (m_reg[2] << 2), CHRROM); - break; - } - if (offset == 0x1000) /* write to reg[0] also sets mirroring */ - set_nt_mirroring(BIT(data, 5) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); -} - -WRITE8_MEMBER(nes_bmc_64y2k_device::write_h) -{ - LOG_MMC(("bmc64y2k write_h, offset: %04x, data: %02x\n", offset, data)); - - m_reg[3] = data; // reg[3] is currently unused?!? -} - -/*------------------------------------------------- - - BMC-12IN1 - - Unknown Bootleg Multigame Board - Games: - - iNES: - - In MESS: Supported. - - -------------------------------------------------*/ - -void nes_bmc_12in1_device::update_banks() -{ - int bank = (m_reg[2] & 3) << 3; - - chr4_0((m_reg[0] >> 3) | (bank << 2), m_chr_source); - chr4_4((m_reg[1] >> 3) | (bank << 2), m_chr_source); - - if (m_reg[2] & 8) - prg32(((m_reg[0] & 7) >> 1) | bank); - else - { - prg16_89ab((m_reg[0] & 7) | bank); - prg16_cdef(7 | bank); - } - - set_nt_mirroring(BIT(m_reg[2], 2) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); -} - -WRITE8_MEMBER(nes_bmc_12in1_device::write_h) -{ - LOG_MMC(("bmc_12in1 write_h, offset: %04x, data: %02x\n", offset, data)); - - switch (offset & 0x6000) - { - case 0x2000: m_reg[0] = data; break; - case 0x4000: m_reg[1] = data; break; - case 0x6000: m_reg[2] = data; break; - } - update_banks(); -} - -/*------------------------------------------------- - - BMC-20IN1 - - Unknown Bootleg Multigame Board - Games: 20 in 1 - - iNES: mapper 231 - - In MESS: Supported. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_bmc_20in1_device::write_h) -{ - LOG_MMC(("bmc_20in1 write_h, offset: %04x, data: %02x\n", offset, data)); - - set_nt_mirroring(BIT(data, 7) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); - - prg16_89ab((offset & 0x1e)); - prg16_cdef((offset & 0x1e) | ((offset & 0x20) ? 1 : 0)); -} - -/*------------------------------------------------- - - BMC-21IN1 - - Unknown Bootleg Multigame Board - Games: 8 in 1, 21 in 1 - - iNES: mapper 201 - - In MESS: Supported. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_bmc_21in1_device::write_h) -{ - LOG_MMC(("bmc_21in1 write_h, offset: %04x, data: %02x\n", offset, data)); - - prg32(offset & 0x03); - chr8(offset & 0x03, CHRROM); -} - -/*------------------------------------------------- - - BMC-31IN1 - - Unknown Bootleg Multigame Board - Games: 31 in 1 - - iNES: mapper 229 - - In MESS: Supported. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_bmc_31in1_device::write_h) -{ - LOG_MMC(("bmc_31in1 write_h, offset: %04x, data: %02x\n", offset, data)); - - set_nt_mirroring(BIT(data, 5) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); - chr8(offset, CHRROM); - - if ((offset & 0x1e) == 0) - { - prg16_89ab(0); - prg16_89ab(1); - } - else - { - prg16_89ab(offset & 0x1f); - prg16_89ab(offset & 0x1f); - } -} - -/*------------------------------------------------- - - BMC-35IN1 - - Unknown Bootleg Multigame Board - Games: 35 in 1 - - iNES: mapper 203 - - In MESS: Supported. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_bmc_35in1_device::write_h) -{ - LOG_MMC(("bmc_35in1 write_h, offset: %04x, data: %02x\n", offset, data)); - - prg16_89ab((data >> 2) & 0x03); - prg16_cdef((data >> 2) & 0x03); - chr8(data & 0x03, CHRROM); -} - -/*------------------------------------------------- - - BMC-36IN1 - - Unknown Bootleg Multigame Board - Games: 36 in 1, 1200 in 1 - - iNES: mapper 200 - - In MESS: Supported. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_bmc_36in1_device::write_h) -{ - LOG_MMC(("bmc_36in1 write_h, offset: %04x, data: %02x\n", offset, data)); - - prg16_89ab(offset & 0x07); - prg16_cdef(offset & 0x07); - chr8(offset & 0x07, CHRROM); - - set_nt_mirroring(BIT(data, 3) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); -} - -/*------------------------------------------------- - - BMC-64IN1 - - Unknown Bootleg Multigame Board - Games: 64 in 1 - - iNES: mapper 204 - - In MESS: Supported. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_bmc_64in1_device::write_h) -{ - int bank = (offset >> 1) & (offset >> 2) & 0x01; - - LOG_MMC(("bmc_64in1 write_h, offset: %04x, data: %02x\n", offset, data)); - - prg16_89ab(offset & ~bank); - prg16_cdef(offset | bank); - chr8(offset & ~bank, CHRROM); - - set_nt_mirroring(BIT(data, 4) ? PPU_MIRROR_HORZ: PPU_MIRROR_VERT); -} - -/*------------------------------------------------- - - BMC-70IN1 - - Unknown Bootleg Multigame Board - Games: - - iNES: mapper - - This is same hardware as BMC-800IN1 below, but this - cart has CHR and slightly diff bankswitch. - DSW not emulated yet. - - In MESS: Preliminary Supported. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_bmc_70in1_device::write_h) -{ - LOG_MMC(("bmc70in1 write_h, offset: %04x, data: %02x\n", offset, data)); - - if (offset < 0x4000) - { - set_nt_mirroring(BIT(offset, 5) ? PPU_MIRROR_HORZ: PPU_MIRROR_VERT); - chr8(offset & 7, CHRROM); - } - else - { - switch (offset & 0x30) - { - case 0x00: m_mode = 0x0; m_reg[0] = (m_reg[0] & 0x38) | (offset & 0x7); m_reg[1] = m_reg[0] | 0x7; break; - case 0x10: m_mode = 0x1; m_reg[0] = (m_reg[0] & 0x38) | (offset & 0x7); m_reg[1] = m_reg[0] | 0x7; break; - case 0x20: m_mode = 0x0; m_reg[0] = (m_reg[0] & 0x38) | (offset & 0x6); m_reg[1] = m_reg[0] | 0x1; break; - case 0x30: m_mode = 0x0; m_reg[0] = (m_reg[0] & 0x38) | (offset & 0x7); m_reg[1] = m_reg[0] | 0x0; break; - } - prg16_89ab(m_reg[0]); - prg16_cdef(m_reg[1]); - } -} - -READ8_MEMBER(nes_bmc_70in1_device::read_h) -{ - LOG_MMC(("bmc70in1 read_h, offset: %04x\n", offset)); - - if (m_mode) - offset = (offset & 0x7ff0) | m_mode; - - return hi_access_rom(offset); -} - -/*------------------------------------------------- - - BMC-72IN1 - - Unknown Bootleg Multigame Board - Games: 72 in 1, 115 in 1 and other multigame carts - - iNES: mapper 225 - - In MESS: Supported. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_bmc_72in1_device::write_h) -{ - int hi_bank = offset & 0x40; - int size_16 = offset & 0x1000; - int bank = (offset & 0xf80) >> 7; - - LOG_MMC(("bmc_72in1 write_h, offset: %04x, data: %02x\n", offset, data)); - - chr8(offset, CHRROM); - set_nt_mirroring((offset & 0x2000) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); - if (size_16) - { - bank <<= 1; - if (hi_bank) - bank ++; - - prg16_89ab(bank); - prg16_cdef(bank); - } - else - prg32(bank); -} - -/*------------------------------------------------- - - BMC-76IN1 - - Unknown Bootleg Multigame Board - Games: 76 in 1, Super 42 in 1 - - iNES: mapper 226 - - In MESS: Supported. - - -------------------------------------------------*/ - -// does this work for super42in1 as well?!? -WRITE8_MEMBER(nes_bmc_76in1_device::write_h) -{ - int hi_bank; - int size_16; - int bank; - - LOG_MMC(("bmc_76in1 write_h, offset: %04x, data: %02x\n", offset, data)); - - if (offset & 0x01) - m_latch2 = data; - else - m_latch1 = data; - - set_nt_mirroring(BIT(m_latch1, 6) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); - - hi_bank = m_latch1 & 0x01; - size_16 = m_latch1 & 0x20; - bank = ((m_latch1 & 0x1e) >> 1) | ((m_latch1 & 0x80) >> 3) | ((m_latch2 & 0x01) << 5); - - if (size_16) - { - bank <<= 1; - if (hi_bank) - bank ++; - - prg16_89ab(bank); - prg16_cdef(bank); - } - else - prg32(bank); -} - -/*------------------------------------------------- - - BMC-110IN1 - - Known Boards: Unknown Bootleg Board - Games: 110 in 1 - - iNES: mapper 255 - - In MESS: Preliminary support. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_bmc_110in1_device::write_h) -{ - UINT8 helper1 = (offset >> 12) ? 0 : 1; - UINT8 helper2 = ((offset >> 8) & 0x40) | ((offset >> 6) & 0x3f); - - LOG_MMC(("bmc_110in1 write_h, offset: %04x, data: %02x\n", offset, data)); - - set_nt_mirroring((offset & 0x2000) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); - prg16_89ab(helper1 & ~helper2); - prg16_cdef(helper1 | helper2); - chr8(((offset >> 8) & 0x40) | (offset & 0x3f), CHRROM); -} - - -/*------------------------------------------------- - - BMC-150IN1 - - Unknown Bootleg Multigame Board - Games: 150 in 1 - - iNES: mapper 202 - - In MESS: Supported. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_bmc_150in1_device::write_h) -{ - int bank = (offset >> 1) & 0x07; - - LOG_MMC(("bmc_150in1 write_h, offset: %04x, data: %02x\n", offset, data)); - - prg16_89ab(bank); - prg16_cdef(bank + (((bank & 0x06) == 0x06) ? 1 : 0)); - chr8(bank, CHRROM); - - set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ: PPU_MIRROR_VERT); -} - - -/*------------------------------------------------- - - Board BMC-190IN1 - - Games: 190-in-1 - - In MESS: Supported - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_bmc_190in1_device::write_h) -{ - LOG_MMC(("bmc190in1 write_h, offset: %04x, data: %02x\n", offset, data)); - - set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); - offset >>= 2; - prg16_89ab(offset); - prg16_cdef(offset); - chr8(offset, CHRROM); -} - -/*------------------------------------------------- - - BMC-800IN1 - - Unknown Bootleg Multigame Board - Games: - - iNES: mapper - - DSW not emulated yet. - - In MESS: Preliminary Supported. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_bmc_800in1_device::write_h) -{ - LOG_MMC(("bmc800in1 write_h, offset: %04x, data: %02x\n", offset, data)); - - if (offset < 0x4000) - { - set_nt_mirroring(BIT(offset, 5) ? PPU_MIRROR_HORZ: PPU_MIRROR_VERT); - - m_reg[0] = (m_reg[0]) | ((offset << 3) & 0x38); - m_reg[1] = (m_reg[1]) | ((offset << 3) & 0x38); - } - else - { - switch (offset & 0x30) - { - case 0x00: m_mode = 0x0; m_reg[0] = (m_reg[0] & 0x38) | (offset & 0x7); m_reg[1] = m_reg[0] | 0x7; break; - case 0x10: m_mode = 0x1; m_reg[0] = (m_reg[0] & 0x38) | (offset & 0x7); m_reg[1] = m_reg[0] | 0x7; break; - case 0x20: m_mode = 0x0; m_reg[0] = (m_reg[0] & 0x38) | (offset & 0x6); m_reg[1] = m_reg[0] | 0x1; break; - case 0x30: m_mode = 0x0; m_reg[0] = (m_reg[0] & 0x38) | (offset & 0x7); m_reg[1] = m_reg[0] | 0x0; break; - } - } - prg16_89ab(m_reg[0]); - prg16_cdef(m_reg[1]); -} - -READ8_MEMBER(nes_bmc_800in1_device::read_h) -{ - LOG_MMC(("bmc800in1 read_h, offset: %04x\n", offset)); - - if (m_mode) - offset = (offset & 0x7ff0) | m_mode; - - return hi_access_rom(offset); -} - -/*------------------------------------------------- - - BMC-1200IN1 - - Unknown Bootleg Multigame Board - Games: 1200 in 1, 295 in 1, 76 in 1 - - iNES: mapper 227 - - In MESS: Preliminary Supported. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_bmc_1200in1_device::chr_w) -{ - int bank = offset >> 10; - - if (!m_vram_protect) - m_chr_access[bank][offset & 0x3ff] = data; -} - - -WRITE8_MEMBER(nes_bmc_1200in1_device::write_h) -{ - int bank = ((offset >> 2) & 0x1f) | ((offset & 0x0100) >> 3); - - LOG_MMC(("bmc_1200in1 write_h, offset: %04x, data: %02x\n", offset, data)); - - if (offset & 0x80) - { -// m_vram_protect = 1; - prg16_89ab(bank); - prg16_cdef(bank + (offset & 1)); - } - else - { - int low_mask = (offset & 1) ? 0x3e : 0xff; - -// m_vram_protect = 0; - if (!BIT(offset, 9)) - { - prg16_89ab(bank & low_mask); - prg16_cdef(bank & 0x38); - } - else - { - prg16_89ab(bank & low_mask); - prg16_cdef(bank | 0x07); - } - } - - set_nt_mirroring(BIT(offset, 1) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); -} - - -/*------------------------------------------------- - - BMC-GOLDEN260IN1 - - Unknown Bootleg Multigame Board - Games: - - iNES: mapper 235 - - In MESS: Preliminary Supported. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_bmc_gold260_device::write_h) -{ - int bank = (offset & 0x1f) | ((offset & 0x0300) >> 3); - LOG_MMC(("bmc_gold260 write_h, offset: %04x, data: %02x\n", offset, data)); - - if (offset & 0x400) - set_nt_mirroring(PPU_MIRROR_LOW); - else - set_nt_mirroring(BIT(offset, 13) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); - - if (offset & 0x800) - { - bank = (bank << 1) | BIT(offset, 12); - prg16_89ab(bank); - prg16_cdef(bank); - } - else - prg32(bank); -} - - -/*------------------------------------------------- - - BMC-GOLDEN150IN1 - - Unknown Bootleg Multigame Board - Games: - - iNES: mapper 235 - - Same as the above + open bus in 0x8000-0xffff when - enabled - - In MESS: Preliminary Supported. - - -------------------------------------------------*/ - - -WRITE8_MEMBER(nes_bmc_gold150_device::write_h) -{ - int bank = (offset & 0x1f) | ((offset & 0x0200) >> 4); - LOG_MMC(("bmc_gold150 write_h, offset: %04x, data: %02x\n", offset, data)); - - m_latch = (offset & 0x0100); - - if (offset & 0x400) - set_nt_mirroring(PPU_MIRROR_LOW); - else - set_nt_mirroring(BIT(offset, 13) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); - - if (offset & 0x800) - { - bank = (bank << 1) | BIT(offset, 12); - prg16_89ab(bank); - prg16_cdef(bank); - } - else - prg32(bank); -} - -READ8_MEMBER(nes_bmc_gold150_device::read_h) -{ - LOG_MMC(("bmc_gold150 read_h, offset: %04x\n", offset)); - - if (m_latch) // open bus - return m_open_bus; - else - return hi_access_rom(offset); -} - - -/*------------------------------------------------- - - BMC-POWERFUL-255 - - Unknown Bootleg Multigame Board - Games: - - iNES: mapper 63 - - - In MESS: Preliminary Supported. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_bmc_ch001_device::write_h) -{ - int bank = ((offset >> 1) & 0x1fc); - LOG_MMC(("bmc_ch001 write_h, offset: %04x, data: %02x\n", offset, data)); - - m_latch = ((offset & 0x300) == 0x300); - set_nt_mirroring(BIT(offset, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); - - if (offset & 2) - { - prg8_89(bank + 0); - prg8_ab(bank + 1); - prg8_cd(bank + 2); - prg8_ef(bank + 3); - } - else - { - bank |= (offset & 4) >> 1; - prg8_89(bank + 0); - prg8_ab(bank + 1); - prg8_cd(bank + 0); - prg8_ef(bank + 1); - } - - if (offset & 0x800) // in this case, the last 8KB bank is switched differently... - prg8_ef((offset & 0x07c ) | ((offset & 0x6) ? 0x3 : 0x1)); -} - -READ8_MEMBER(nes_bmc_ch001_device::read_h) -{ - LOG_MMC(("bmc_ch001 read_h, offset: %04x\n", offset)); - - if (m_latch && offset < 0x4000) // open bus - return m_open_bus; - else - return hi_access_rom(offset); -} - -/*------------------------------------------------- - - BMC-SUPER22GAMES - - Unknown Bootleg Multigame Board - Games: - - iNES: - - is there a dsw to access the higher banks above 0x20? - - In MESS: Preliminary Supported. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_bmc_super22_device::write_h) -{ - LOG_MMC(("bmc_super22 write_h, offset: %04x, data: %02x\n", offset, data)); - - if (data & 0x20) - { - prg16_89ab(data & 0x1f); - prg16_cdef(data & 0x1f); - } - else - prg32((data & 0x1f) >> 1); - - switch (data & 0xc0) - { - case 0x00: set_nt_mirroring(PPU_MIRROR_LOW); break; - case 0x40: set_nt_mirroring(PPU_MIRROR_VERT); break; - case 0x80: set_nt_mirroring(PPU_MIRROR_HORZ); break; - case 0xc0: set_nt_mirroring(PPU_MIRROR_HIGH); break; - } -} - - -/*------------------------------------------------- - - BMC-RESETBASED4IN1 - - Unknown Bootleg Multigame Board - - Games: - - iNES: - - No need to use handlers. At reset the banks change - and so does the game. - - In MESS: Preliminary Supported. - - -------------------------------------------------*/ - -/*------------------------------------------------- - - BMC-42IN1RESETBASED - - Unknown Bootleg Multigame Board - - Games: - - iNES: - - In MESS: Preliminary Supported. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_bmc_42in1reset_device::write_h) -{ - int bank; - LOG_MMC(("bmc_42in1reset write_h, offset: %04x, data: %02x\n", offset, data)); - - m_reg[offset & 1] = data; - bank = (m_reg[0] & 0x1f) | (m_latch << 5) | ((m_reg[1] & 1) << 6); - - if (!(m_reg[0] & 0x20)) - prg32(bank >> 1); - else - { - prg16_89ab(bank); - prg16_cdef(bank); - } - - set_nt_mirroring(BIT(offset, 6) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); - -} diff --git a/src/devices/bus/nes/multigame.cpp b/src/devices/bus/nes/multigame.cpp new file mode 100644 index 00000000000..ba65c3d0e7c --- /dev/null +++ b/src/devices/bus/nes/multigame.cpp @@ -0,0 +1,2602 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for Multigame Carts PCBs + + + Here we emulate several PCBs used in multigame pirate carts (not MMC-3 based) + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "multigame.h" + + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_ACTION52 = &device_creator; +const device_type NES_CALTRON6IN1 = &device_creator; +const device_type NES_RUMBLESTATION = &device_creator; +const device_type NES_SVISION16 = &device_creator; +const device_type NES_N625092 = &device_creator; +const device_type NES_A65AS = &device_creator; +const device_type NES_T262 = &device_creator; +const device_type NES_NOVEL1 = &device_creator; +const device_type NES_NOVEL2 = &device_creator; +const device_type NES_STUDYNGAME = &device_creator; +const device_type NES_SUPERGUN20IN1 = &device_creator; +const device_type NES_VT5201 = &device_creator; +const device_type NES_810544C = &device_creator; +const device_type NES_NTD03 = &device_creator; +const device_type NES_BMC_GB63 = &device_creator; +const device_type NES_BMC_GKA = &device_creator; +const device_type NES_BMC_GKB = &device_creator; +const device_type NES_BMC_WS = &device_creator; +const device_type NES_BMC_11160 = &device_creator; +const device_type NES_BMC_G146 = &device_creator; +const device_type NES_BMC_8157 = &device_creator; +const device_type NES_BMC_HIK300 = &device_creator; +const device_type NES_BMC_S700 = &device_creator; +const device_type NES_BMC_BALL11 = &device_creator; +const device_type NES_BMC_22GAMES = &device_creator; +const device_type NES_BMC_64Y2K = &device_creator; +const device_type NES_BMC_12IN1 = &device_creator; +const device_type NES_BMC_20IN1 = &device_creator; +const device_type NES_BMC_21IN1 = &device_creator; +const device_type NES_BMC_31IN1 = &device_creator; +const device_type NES_BMC_35IN1 = &device_creator; +const device_type NES_BMC_36IN1 = &device_creator; +const device_type NES_BMC_64IN1 = &device_creator; +const device_type NES_BMC_70IN1 = &device_creator; +const device_type NES_BMC_72IN1 = &device_creator; +const device_type NES_BMC_76IN1 = &device_creator; +const device_type NES_BMC_110IN1 = &device_creator; +const device_type NES_BMC_150IN1 = &device_creator; +const device_type NES_BMC_190IN1 = &device_creator; +const device_type NES_BMC_800IN1 = &device_creator; +const device_type NES_BMC_1200IN1 = &device_creator; +const device_type NES_BMC_GOLD150 = &device_creator; +const device_type NES_BMC_GOLD260 = &device_creator; +const device_type NES_BMC_CH001 = &device_creator; +const device_type NES_BMC_SUPER22 = &device_creator; +const device_type NES_BMC_4IN1RESET = &device_creator; +const device_type NES_BMC_42IN1RESET = &device_creator; + + +nes_action52_device::nes_action52_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_ACTION52, "NES Cart Action 52 PCB", tag, owner, clock, "nes_action52", __FILE__) +{ +} + +nes_caltron_device::nes_caltron_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_CALTRON6IN1, "NES Cart Caltron 6 in 1 PCB", tag, owner, clock, "nes_caltron", __FILE__) +{ +} + +nes_rumblestat_device::nes_rumblestat_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_RUMBLESTATION, "NES Cart Rumblestation PCB", tag, owner, clock, "nes_rumblestat", __FILE__) +{ +} + +nes_svision16_device::nes_svision16_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_SVISION16, "NES Cart Supervision 16 in 1 PCB", tag, owner, clock, "nes_svision16", __FILE__) +{ +} + +nes_n625092_device::nes_n625092_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_N625092, "NES Cart N625092 PCB", tag, owner, clock, "nes_n625092", __FILE__) +{ +} + +nes_a65as_device::nes_a65as_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_A65AS, "NES Cart A65AS PCB", tag, owner, clock, "nes_a65as", __FILE__) +{ +} + +nes_t262_device::nes_t262_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_T262, "NES Cart T-262 PCB", tag, owner, clock, "nes_t262", __FILE__) +{ +} + +nes_novel1_device::nes_novel1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_NOVEL1, "NES Cart Novel Diamond Type 1 PCB", tag, owner, clock, "nes_novel1", __FILE__) +{ +} + +nes_novel2_device::nes_novel2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_NOVEL2, "NES Cart Novel Diamond Type 2 PCB", tag, owner, clock, "nes_novel2", __FILE__) +{ +} + +nes_studyngame_device::nes_studyngame_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_STUDYNGAME, "NES Cart Study n Game PCB", tag, owner, clock, "nes_studyngame", __FILE__) +{ +} + +nes_sgun20in1_device::nes_sgun20in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_SUPERGUN20IN1, "NES Cart Supergun 20 in 1 PCB", tag, owner, clock, "nes_sgun20in1", __FILE__) +{ +} + +nes_vt5201_device::nes_vt5201_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_VT5201, "NES Cart VT5201 PCB", tag, owner, clock, "nes_vt5201", __FILE__) +{ +} + +nes_810544c_device::nes_810544c_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_810544C, "NES Cart 810544-C-A1 PCB", tag, owner, clock, "nes_810544c", __FILE__) +{ +} + +nes_ntd03_device::nes_ntd03_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_NTD03, "NES Cart NTD-03 PCB", tag, owner, clock, "nes_ntd03", __FILE__) +{ +} + +nes_bmc_gb63_device::nes_bmc_gb63_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_BMC_GB63, "NES Cart BMC Ghostbusters 63 in 1 PCB", tag, owner, clock, "nes_bmc_gb63", __FILE__) +{ +} + +nes_bmc_gka_device::nes_bmc_gka_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_BMC_GKA, "NES Cart BMC GK-A PCB", tag, owner, clock, "nes_bmc_gka", __FILE__) +{ +} + +nes_bmc_gkb_device::nes_bmc_gkb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_BMC_GKB, "NES Cart BMC GK-B PCB", tag, owner, clock, "nes_bmc_gkb", __FILE__) +{ +} + +nes_bmc_ws_device::nes_bmc_ws_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_BMC_WS, "NES Cart BMC WS PCB", tag, owner, clock, "nes_bmc_ws", __FILE__) +{ +} + +nes_bmc_11160_device::nes_bmc_11160_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_BMC_11160, "NES Cart BMC-11160 PCB", tag, owner, clock, "nes_bmc_11160", __FILE__) +{ +} + +nes_bmc_g146_device::nes_bmc_g146_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_BMC_G146, "NES Cart BMC-G-146 PCB", tag, owner, clock, "nes_bmc_g146", __FILE__) +{ +} + +nes_bmc_8157_device::nes_bmc_8157_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_BMC_8157, "NES Cart BMC-8157 PCB", tag, owner, clock, "nes_bmc_8157", __FILE__) +{ +} + +nes_bmc_hik300_device::nes_bmc_hik300_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_BMC_HIK300, "NES Cart BMC HIK 300 in 1 PCB", tag, owner, clock, "nes_bmc_hik300", __FILE__) +{ +} + +nes_bmc_s700_device::nes_bmc_s700_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_BMC_S700, "NES Cart BMC Super 700 in 1 PCB", tag, owner, clock, "nes_bmc_s700", __FILE__) +{ +} + +nes_bmc_ball11_device::nes_bmc_ball11_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_BMC_BALL11, "NES Cart BMC Ball 11 in 1 PCB", tag, owner, clock, "nes_bmc_ball11", __FILE__) +{ +} + +nes_bmc_22games_device::nes_bmc_22games_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_BMC_22GAMES, "NES Cart BMC 22 Games PCB", tag, owner, clock, "nes_bmc_22games", __FILE__) +{ +} + +nes_bmc_64y2k_device::nes_bmc_64y2k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_BMC_64Y2K, "NES Cart BMC 64 in 1 Y2K PCB", tag, owner, clock, "nes_bmc_64y2k", __FILE__) +{ +} + +nes_bmc_12in1_device::nes_bmc_12in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_BMC_12IN1, "NES Cart BMC 12 in 1 PCB", tag, owner, clock, "nes_bmc_12in1", __FILE__) +{ +} + +nes_bmc_20in1_device::nes_bmc_20in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_BMC_20IN1, "NES Cart BMC 20 in 1 PCB", tag, owner, clock, "nes_bmc_20in1", __FILE__) +{ +} + +nes_bmc_21in1_device::nes_bmc_21in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_BMC_21IN1, "NES Cart BMC 21 in 1 PCB", tag, owner, clock, "nes_bmc_21in1", __FILE__) +{ +} + +nes_bmc_31in1_device::nes_bmc_31in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_BMC_31IN1, "NES Cart BMC 31 in 1 PCB", tag, owner, clock, "nes_bmc_31in1", __FILE__) +{ +} + +nes_bmc_35in1_device::nes_bmc_35in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_BMC_35IN1, "NES Cart BMC 35 in 1 PCB", tag, owner, clock, "nes_bmc_35in1", __FILE__) +{ +} + +nes_bmc_36in1_device::nes_bmc_36in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_BMC_36IN1, "NES Cart BMC 36 in 1 PCB", tag, owner, clock, "nes_bmc_36in1", __FILE__) +{ +} + +nes_bmc_64in1_device::nes_bmc_64in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_BMC_64IN1, "NES Cart BMC 64 in 1 PCB", tag, owner, clock, "nes_bmc_64in1", __FILE__) +{ +} + +nes_bmc_70in1_device::nes_bmc_70in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_BMC_70IN1, "NES Cart BMC 70 in 1 PCB", tag, owner, clock, "nes_bmc_70in1", __FILE__) +{ +} + +nes_bmc_72in1_device::nes_bmc_72in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_BMC_72IN1, "NES Cart BMC 72 in 1 PCB", tag, owner, clock, "nes_bmc_72in1", __FILE__) +{ +} + +nes_bmc_76in1_device::nes_bmc_76in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_BMC_76IN1, "NES Cart BMC 76 in 1 PCB", tag, owner, clock, "nes_bmc_76in1", __FILE__) +{ +} + +nes_bmc_110in1_device::nes_bmc_110in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_BMC_110IN1, "NES Cart BMC 110 in 1 PCB", tag, owner, clock, "nes_bmc_110in1", __FILE__) +{ +} + +nes_bmc_150in1_device::nes_bmc_150in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_BMC_150IN1, "NES Cart BMC 150 in 1 PCB", tag, owner, clock, "nes_bmc_150in1", __FILE__) +{ +} + +nes_bmc_190in1_device::nes_bmc_190in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_BMC_190IN1, "NES Cart BMC 190 in 1 PCB", tag, owner, clock, "nes_bmc_190in1", __FILE__) +{ +} + +nes_bmc_800in1_device::nes_bmc_800in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_BMC_800IN1, "NES Cart BMC 800 in 1 PCB", tag, owner, clock, "nes_bmc_800in1", __FILE__) +{ +} + +nes_bmc_1200in1_device::nes_bmc_1200in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_BMC_1200IN1, "NES Cart BMC 1200 in 1 PCB", tag, owner, clock, "nes_bmc_1200in1", __FILE__) +{ +} + +nes_bmc_gold150_device::nes_bmc_gold150_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_BMC_GOLD150, "NES Cart BMC Golden 150 in 1 PCB", tag, owner, clock, "nes_bmc_gold150", __FILE__) +{ +} + +nes_bmc_gold260_device::nes_bmc_gold260_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_BMC_GOLD260, "NES Cart BMC Golden 260 in 1 PCB", tag, owner, clock, "nes_bmc_gold260", __FILE__) +{ +} + +nes_bmc_ch001_device::nes_bmc_ch001_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_BMC_CH001, "NES Cart BMC CH-001 PCB", tag, owner, clock, "nes_bmc_ch001", __FILE__) +{ +} + +nes_bmc_super22_device::nes_bmc_super22_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_BMC_SUPER22, "NES Cart BMC Super 22 Games PCB", tag, owner, clock, "nes_bmc_super22", __FILE__) +{ +} + +nes_bmc_4in1reset_device::nes_bmc_4in1reset_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_BMC_4IN1RESET, "NES Cart BMC 4 in 1 (Reset Based) PCB", tag, owner, clock, "nes_bmc_4in1reset", __FILE__) +{ +} + +nes_bmc_42in1reset_device::nes_bmc_42in1reset_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_BMC_42IN1RESET, "NES Cart BMC 42 in 1 (Reset Based) PCB", tag, owner, clock, "nes_bmc_42in1reset", __FILE__) +{ +} + + + + +void nes_action52_device::device_start() +{ + common_start(); +} + +void nes_action52_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + +void nes_caltron_device::device_start() +{ + common_start(); + save_item(NAME(m_latch)); +} + +void nes_caltron_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); + + m_latch = 0; +} + +void nes_rumblestat_device::device_start() +{ + common_start(); + save_item(NAME(m_prg)); + save_item(NAME(m_chr)); +} + +void nes_rumblestat_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); + + m_prg = 0; + m_chr = 0; +} + +void nes_svision16_device::device_start() +{ + common_start(); + save_item(NAME(m_latch1)); + save_item(NAME(m_latch2)); +} + +void nes_svision16_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); + + m_latch1 = 0; + m_latch2 = 0; +} + +void nes_n625092_device::device_start() +{ + common_start(); + save_item(NAME(m_latch1)); + save_item(NAME(m_latch2)); +} + +void nes_n625092_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(0); + chr8(0, m_chr_source); + + m_latch1 = 0; + m_latch2 = 0; +} + +void nes_a65as_device::device_start() +{ + common_start(); +} + +void nes_a65as_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(7); + set_nt_mirroring(PPU_MIRROR_VERT); + chr8(0, m_chr_source); +} + +void nes_t262_device::device_start() +{ + common_start(); + save_item(NAME(m_latch1)); + save_item(NAME(m_latch2)); +} + +void nes_t262_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(7); + chr8(0, m_chr_source); + + m_latch1 = 0; + m_latch2 = 0; +} + +void nes_novel1_device::device_start() +{ + common_start(); +} + +void nes_novel1_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); + set_nt_mirroring(PPU_MIRROR_VERT); +} + +void nes_novel2_device::device_start() +{ + common_start(); +} + +void nes_novel2_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + +void nes_studyngame_device::device_start() +{ + common_start(); +} + +void nes_studyngame_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + +void nes_sgun20in1_device::device_start() +{ + common_start(); +} + +void nes_sgun20in1_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(0); + chr8(0, m_chr_source); +} + +void nes_vt5201_device::device_start() +{ + common_start(); + save_item(NAME(m_latch)); + save_item(NAME(m_dipsetting)); +} + +void nes_vt5201_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); + + m_latch = 0; + m_dipsetting = 0; +} + +void nes_810544c_device::device_start() +{ + common_start(); +} + +void nes_810544c_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(0); + chr8(0, m_chr_source); + set_nt_mirroring(PPU_MIRROR_VERT); +} + +void nes_ntd03_device::device_start() +{ + common_start(); +} + +void nes_ntd03_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + +void nes_bmc_gb63_device::device_start() +{ + common_start(); + save_item(NAME(m_latch)); + save_item(NAME(m_dipsetting)); + save_item(NAME(m_reg)); + save_item(NAME(m_vram_disable)); +} + +void nes_bmc_gb63_device::pcb_reset() +{ + prg16_89ab(0); + prg16_cdef(0xfff); + chr8(0, CHRRAM); + + m_latch = 0; + m_dipsetting = 0; + m_reg[0] = 0; + m_reg[1] = 0; + update_banks(); + m_vram_disable = 0; +} + +void nes_bmc_gka_device::device_start() +{ + common_start(); + save_item(NAME(m_latch1)); + save_item(NAME(m_latch2)); +} + +void nes_bmc_gka_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(0); + chr8(0, m_chr_source); + + m_latch1 = 0; + m_latch2 = 0; +} + +void nes_bmc_gkb_device::device_start() +{ + common_start(); +} + +void nes_bmc_gkb_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + +void nes_bmc_ws_device::device_start() +{ + common_start(); + save_item(NAME(m_latch)); +} + +void nes_bmc_ws_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); + + m_latch = 0; +} + +void nes_bmc_11160_device::device_start() +{ + common_start(); +} + +void nes_bmc_11160_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + +void nes_bmc_g146_device::device_start() +{ + common_start(); +} + +void nes_bmc_g146_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + +void nes_bmc_8157_device::device_start() +{ + common_start(); +} + +void nes_bmc_8157_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + +void nes_bmc_hik300_device::device_start() +{ + common_start(); +} + +void nes_bmc_hik300_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0xff); + chr8(0xff, CHRROM); +} + +void nes_bmc_s700_device::device_start() +{ + common_start(); +} + +void nes_bmc_s700_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + +void nes_bmc_ball11_device::device_start() +{ + common_start(); + save_item(NAME(m_reg)); +} + +void nes_bmc_ball11_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); + + m_reg[0] = 1; + m_reg[1] = 0; + set_banks(); +} + +void nes_bmc_22games_device::device_start() +{ + common_start(); +} + +void nes_bmc_22games_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(7); + chr8(0, m_chr_source); +} + +void nes_bmc_64y2k_device::device_start() +{ + common_start(); + save_item(NAME(m_reg)); +} + +void nes_bmc_64y2k_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + chr8(0, m_chr_source); + + m_reg[0] = 0x80; + m_reg[1] = 0x43; + m_reg[2] = m_reg[3] = 0; + set_prg(); + set_nt_mirroring(PPU_MIRROR_VERT); +} + +void nes_bmc_12in1_device::device_start() +{ + common_start(); + save_item(NAME(m_reg)); +} + +void nes_bmc_12in1_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); + m_reg[0] = 0; + m_reg[1] = 0; + m_reg[2] = 0; + update_banks(); +} + +void nes_bmc_20in1_device::device_start() +{ + common_start(); +} + +void nes_bmc_20in1_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + set_nt_mirroring(PPU_MIRROR_VERT); +} + +void nes_bmc_21in1_device::device_start() +{ + common_start(); +} + +void nes_bmc_21in1_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + +void nes_bmc_31in1_device::device_start() +{ + common_start(); +} + +void nes_bmc_31in1_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(1); + chr8(0, m_chr_source); +} + +void nes_bmc_35in1_device::device_start() +{ + common_start(); +} + +void nes_bmc_35in1_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(0); + chr8(0, m_chr_source); +} + +void nes_bmc_36in1_device::device_start() +{ + common_start(); +} + +void nes_bmc_36in1_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(m_prg_chunks - 1); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); +} + +void nes_bmc_64in1_device::device_start() +{ + common_start(); +} + +void nes_bmc_64in1_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(0); + chr8(0, m_chr_source); +} + +void nes_bmc_70in1_device::device_start() +{ + common_start(); + save_item(NAME(m_reg)); + save_item(NAME(m_mode)); +} + +void nes_bmc_70in1_device::pcb_reset() +{ + prg16_89ab(m_prg_chunks - 1); + prg16_cdef(m_prg_chunks - 1); + chr8(0, CHRROM); + m_reg[0] = 0; + m_reg[1] = 0; + m_mode = 0; +} + +void nes_bmc_72in1_device::device_start() +{ + common_start(); +} + +void nes_bmc_72in1_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + +void nes_bmc_76in1_device::device_start() +{ + common_start(); + save_item(NAME(m_latch1)); + save_item(NAME(m_latch2)); +} + +void nes_bmc_76in1_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); + + m_latch1 = 0; + m_latch2 = 0; +} + +void nes_bmc_110in1_device::device_start() +{ + common_start(); +} + +void nes_bmc_110in1_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(1); + chr8(0, m_chr_source); + set_nt_mirroring(PPU_MIRROR_VERT); +} + +void nes_bmc_150in1_device::device_start() +{ + common_start(); +} + +void nes_bmc_150in1_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(0); + chr8(0, m_chr_source); +} + +void nes_bmc_190in1_device::device_start() +{ + common_start(); +} + +void nes_bmc_190in1_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(0); + chr8(0, m_chr_source); +} + +void nes_bmc_800in1_device::device_start() +{ + common_start(); + save_item(NAME(m_reg)); + save_item(NAME(m_mode)); +} + +void nes_bmc_800in1_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(m_prg_chunks - 1); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + m_reg[0] = 0; + m_reg[1] = 0; + m_mode = 0; +} + +void nes_bmc_1200in1_device::device_start() +{ + common_start(); + save_item(NAME(m_vram_protect)); +} + +void nes_bmc_1200in1_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(0); + chr8(0, m_chr_source); + m_vram_protect = 0; +} + +void nes_bmc_gold150_device::device_start() +{ + common_start(); + save_item(NAME(m_latch)); +} + +void nes_bmc_gold150_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); + + m_latch = 0; +} + +void nes_bmc_gold260_device::device_start() +{ + common_start(); +} + +void nes_bmc_gold260_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + +void nes_bmc_ch001_device::device_start() +{ + common_start(); + save_item(NAME(m_latch)); +} + +void nes_bmc_ch001_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); + + m_latch = 0; +} + +void nes_bmc_super22_device::device_start() +{ + common_start(); +} + +void nes_bmc_super22_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + + +// This PCB is fully emulated here :) +void nes_bmc_4in1reset_device::device_start() +{ + common_start(); + m_latch = -1; + save_item(NAME(m_latch)); +} + +void nes_bmc_4in1reset_device::pcb_reset() +{ + m_latch++; + m_latch &= 3; + chr8(m_latch, CHRROM); + prg16_89ab(m_latch); + prg16_cdef(m_latch); +} + + +void nes_bmc_42in1reset_device::device_start() +{ + common_start(); + m_latch = -1; + save_item(NAME(m_reg)); +} + +void nes_bmc_42in1reset_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + m_latch++; + m_latch &= 1; + chr8(0, m_chr_source); + prg32(m_latch << 4); + + m_reg[0] = 0; + m_reg[1] = 0; +} + + + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + Active Entertainment Action 52 board emulation + + iNES: mapper 228 + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_action52_device::write_h) +{ + UINT8 pmode = offset & 0x20; + int pbank = (offset & 0x1fc0) >> 6; + int cbank = (data & 0x03) | ((offset & 0x0f) << 2); + LOG_MMC(("ae_act52_w, offset: %04x, data: %02x\n", offset, data)); + + set_nt_mirroring(BIT(offset, 13) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + + chr8(cbank, CHRROM); + + if (pmode) + { + prg16_89ab(pbank); + prg16_cdef(pbank); + } + else + prg32(pbank >> 1); +} + +/*------------------------------------------------- + + Caltron 6 in 1 Board + + Games: 6 in 1 by Caltron + + iNES: mapper 41 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_caltron_device::write_m) +{ + LOG_MMC(("caltron write_m, offset: %04x, data: %02x\n", offset, data)); + + m_latch = offset & 0xff; + set_nt_mirroring(BIT(data, 5) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + prg32(offset & 0x07); +} + +WRITE8_MEMBER(nes_caltron_device::write_h) +{ + LOG_MMC(("caltron write_h, offset: %04x, data: %02x\n", offset, data)); + + if (m_latch & 0x04) + chr8(((m_latch & 0x18) >> 1) | (data & 0x03), CHRROM); +} + +/*------------------------------------------------- + + Rumblestation Board + + Games: Rumblestation 15 in 1 + + iNES: mapper 46 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_rumblestat_device::write_m) +{ + LOG_MMC(("rumblestation write_m, offset: %04x, data: %02x\n", offset, data)); + + m_prg = (m_prg & 0x01) | ((data & 0x0f) << 1); + m_chr = (m_chr & 0x07) | ((data & 0xf0) >> 1); + prg32(m_prg); + chr8(m_chr, CHRROM); +} + +WRITE8_MEMBER(nes_rumblestat_device::write_h) +{ + LOG_MMC(("rumblestation write_h, offset: %04x, data: %02x\n", offset, data)); + + // this pcb is subject to bus conflict + data = account_bus_conflict(offset, data); + + m_prg = (m_prg & ~0x01) | (data & 0x01); + m_chr = (m_chr & ~0x07) | ((data & 0x70) >> 4); + prg32(m_prg); + chr8(m_chr, CHRROM); +} + +/*------------------------------------------------- + + Supervision 16 in 1 Board + + Games: Supervision 16 in 1 + + iNES: mapper 53 + + In MESS: Partially Supported. (the dump contains 32KB of + EEPROM which is not currently handled well) + + -------------------------------------------------*/ + +void nes_svision16_device::update_prg() +{ + int base = (m_latch1 & 0x0f) << 3; + if (m_latch1 & 0x10) + { + prg16_89ab((base | (m_latch2 & 7)) + 2); // +2 due to the eeprom + prg16_cdef((base | 0x07) + 2); // +2 due to the eeprom + } + else + { + prg16_89ab(0); + prg16_cdef(1); + } + +} + +READ8_MEMBER(nes_svision16_device::read_m) +{ + int bank = (((m_latch1 & 0x0f) << 4) | 0x0f) + 4 ; // +4 due to the eeprom + LOG_MMC(("svision16 read_m, offset: %04x\n", offset)); + return m_prg[((bank * 0x2000) + (offset & 0x1fff)) & m_prg_mask]; +} + +WRITE8_MEMBER(nes_svision16_device::write_m) +{ + LOG_MMC(("svision16 write_m, offset: %04x, data: %02x\n", offset, data)); + + m_latch1 = data; + update_prg(); + set_nt_mirroring(BIT(data, 5) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); +} + +WRITE8_MEMBER(nes_svision16_device::write_h) +{ + LOG_MMC(("svision16 write_h, offset: %04x, data: %02x\n", offset, data)); + m_latch2 = data; + update_prg(); +} + +/*------------------------------------------------- + + Bootleg Board N625092 + + Games: 400 in 1, 700 in 1, 1000 in 1 + + iNES: mapper 221 + + In MESS: Supported. + + -------------------------------------------------*/ + +void nes_n625092_device::set_prg(UINT8 reg1, UINT8 reg2) +{ + UINT8 helper1, helper2; + + helper1 = !(reg1 & 0x01) ? reg2 : (reg1 & 0x80) ? reg2 : (reg2 & 0x06) | 0x00; + helper2 = !(reg1 & 0x01) ? reg2 : (reg1 & 0x80) ? 0x07 : (reg2 & 0x06) | 0x01; + + prg16_89ab(helper1 | ((reg1 & 0x70) >> 1)); + prg16_cdef(helper2 | ((reg1 & 0x70) >> 1)); +} + +WRITE8_MEMBER(nes_n625092_device::write_h) +{ + LOG_MMC(("n625092 write_h, offset: %04x, data: %02x\n", offset, data)); + + if (offset < 0x4000) + { + set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + offset = (offset >> 1) & 0xff; + + if (m_latch1 != offset) + { + m_latch1 = offset; + set_prg(m_latch1, m_latch2); + } + } + else + { + offset &= 0x07; + + if (m_latch2 != offset) + { + m_latch2 = offset; + set_prg(m_latch1, m_latch2); + } + } +} + + +/*------------------------------------------------- + + Board BMC-A65AS + + Games: 3-in-1 (N068) + + In MESS: Supported + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_a65as_device::write_h) +{ + UINT8 helper = (data & 0x30) >> 1; + LOG_MMC(("a65as write_h, offset: %04x, data: %02x\n", offset, data)); + + if (data & 0x80) + set_nt_mirroring(BIT(data, 5) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW); + else + set_nt_mirroring(BIT(data, 3) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + + if (data & 0x40) + prg32(data >> 1); + else + { + prg16_89ab(helper | (data & 0x07)); + prg16_cdef(helper | 0x07); + } +} + +/*------------------------------------------------- + + Board BMC-T-262 + + Games: 4-in-1 (D-010), 8-in-1 (A-020) + + In MESS: Supported + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_t262_device::write_h) +{ + UINT8 mmc_helper; + LOG_MMC(("t262 write_h, offset: %04x, data: %02x\n", offset, data)); + + if (m_latch2 || offset == 0) + { + m_latch1 = (m_latch1 & 0x38) | (data & 0x07); + prg16_89ab(m_latch1); + } + else + { + m_latch2 = 1; + set_nt_mirroring(BIT(data, 1) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + mmc_helper = ((offset >> 3) & 0x20) | ((offset >> 2) & 0x18); + m_latch1 = mmc_helper | (m_latch1 & 0x07); + prg16_89ab(m_latch1); + prg16_cdef(mmc_helper | 0x07); + } +} + + +/*------------------------------------------------- + + BMC-NOVELDIAMOND and BMC-999999in1 + + Unknown Bootleg Multigame Board + Games: I only found 'Novel Diamond 999999-in-1.unf' using + this mapper (hence the code is used for BMC_NOVELDIAMOND + board). The code is included here in case a mapper 54 + dump arises. + + iNES: mappers 54 and 213 + + In MESS: Partial Support. + + -------------------------------------------------*/ + +// Are this correct or should they work the same? +WRITE8_MEMBER(nes_novel1_device::write_h) +{ + LOG_MMC(("novel1 write_h, offset: %04x, data: %02x\n", offset, data)); + + prg32(offset & 0x03); + chr8(offset & 0x07, CHRROM); +} + +WRITE8_MEMBER(nes_novel2_device::write_h) +{ + LOG_MMC(("novel2 write_h, offset: %04x, data: %02x\n", offset, data)); + + prg32(offset >> 1); + chr8(offset >> 3, CHRROM); +} + + +/*------------------------------------------------- + + Board UNL-STUDYNGAME + + Games: Study n Game 32 in 1 + + iNES: mapper 39 + + In MESS: Partially Supported (problems with PRG bankswitch, + only keyboard exercise work). + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_studyngame_device::write_h) +{ + LOG_MMC(("studyngame write_h, offset: %04x, data: %02x\n", offset, data)); + prg32(data); +} + +/*------------------------------------------------- + + BMC-SUPERGUN-20IN1 + + Unknown Bootleg Multigame Board + Games: Super Gun 20 in 1 + + iNES: mapper 214 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_sgun20in1_device::write_h) +{ + LOG_MMC(("supergun20in1 write_h, offset: %04x, data: %02x\n", offset, data)); + + prg16_89ab(offset >> 2); + prg16_cdef(offset >> 2); + chr8(offset, CHRROM); +} + +/*------------------------------------------------- + + BMC-VT5201 + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_vt5201_device::write_h) +{ + LOG_MMC(("vt5201 wirte_h, offset: %04x, data: %02x\n", offset, data)); + + m_latch = BIT(offset, 8); + + // not sure about this mirroring bit!! + // without it TN 95 in 1 has glitches in Lunar Ball; with it TN 95 in 1 has glitches in Galaxian! + set_nt_mirroring(BIT(data, 3) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + if (BIT(offset, 7)) + { + prg16_89ab((offset >> 4) & 0x07); + prg16_cdef((offset >> 4) & 0x07); + } + else + prg32((offset >> 5) & 0x03); + chr8(offset, CHRROM); +} + +READ8_MEMBER(nes_vt5201_device::read_h) +{ + LOG_MMC(("bmc_vt5201 read_h, offset: %04x\n", offset)); + // m_dipsetting = ioport("CARTDIPS")->read(); + + if (m_latch) + return m_dipsetting; // cart mode, depending on the Dip Switches (always zero atm, given we have no way to add cart-based DIPs) + else + return hi_access_rom(offset); +} + +/*------------------------------------------------- + + BMC-810544-C-A1 + + Games: 200-in-1 Elfland + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_810544c_device::write_h) +{ + UINT8 bank = (offset >> 7); + LOG_MMC(("810544 write_h, offset: %04x, data: %02x\n", offset, data)); + + if (!BIT(offset, 6)) + { + prg16_89ab((bank << 1) | BIT(offset, 5)); + prg16_cdef((bank << 1) | BIT(offset, 5)); + } + else + prg32(bank); + + set_nt_mirroring(BIT(offset, 4) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + + chr8(offset & 0x0f, CHRROM); +} + +/*------------------------------------------------- + + BMC-NTD-03 + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_ntd03_device::write_h) +{ + UINT8 pbank = (offset >> 10) & 0x1e; + UINT8 cbank = ((offset & 0x300) >> 5) | (offset & 0x07); + LOG_MMC(("ntd03 write_h, offset: %04x, data: %02x\n", offset, data)); + + if (BIT(offset, 7)) + { + prg16_89ab(pbank | BIT(offset, 6)); + prg16_cdef(pbank | BIT(offset, 6)); + } + else + prg32(pbank >> 1); + + set_nt_mirroring(BIT(offset, 10) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + + chr8(cbank, CHRROM); +} + +/*------------------------------------------------- + + BMC-GHOSTBUSTERS63IN1 + + in MESS: only preliminar support + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_bmc_gb63_device::chr_w) +{ + int bank = offset >> 10; + + if (!m_vram_disable) + m_chr_access[bank][offset & 0x3ff] = data; +} + +void nes_bmc_gb63_device::update_banks() +{ + set_nt_mirroring(BIT(m_reg[0], 6) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ); + + if (BIT(m_reg[0], 5)) + { + prg16_89ab(m_reg[0] & 0x1f); + prg16_cdef(m_reg[0] & 0x1f); + } + else + prg32((m_reg[0] & 0x1f) >> 1); + +// according to FCEUMM source, the game should be able to disable the VRAM, but this stops the game from working +// maybe the VRAM disable does not work at start? +// m_vram_disable = BIT(m_reg[1], 1) ? 0 : 1; +} + +WRITE8_MEMBER(nes_bmc_gb63_device::write_h) +{ + LOG_MMC(("bmc_gb63 write_h, offset: %04x, data: %02x\n", offset, data)); + + m_reg[offset & 1] = data; + m_latch = BIT(m_reg[0], 7) | (BIT(m_reg[1], 0) << 1); + update_banks(); +} + +READ8_MEMBER(nes_bmc_gb63_device::read_h) +{ + LOG_MMC(("bmc_gb63 read_h, offset: %04x\n", offset)); + // m_dipsetting = ioport("CARTDIPS")->read(); + + if (m_latch == 1) + return m_open_bus; // open bus + else + return hi_access_rom(offset); +} + + +/*------------------------------------------------- + + Board BMC-GKA + + Unknown Bootleg Multigame Board + Games: 6 in 1, 54 in 1, 106 in 1 + + iNES: mapper 57 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_bmc_gka_device::write_h) +{ + LOG_MMC(("bmc_gka write_h, offset: %04x, data: %02x\n", offset, data)); + + if (offset & 0x0800) + m_latch2 = data; + else + m_latch1 = data; + + if (m_latch2 & 0x80) + prg32(2 | (m_latch2 >> 6)); + else + { + prg16_89ab((m_latch2 >> 5) & 0x03); + prg16_cdef((m_latch2 >> 5) & 0x03); + } + + set_nt_mirroring((m_latch2 & 0x08) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + + chr8((m_latch1 & 0x03) | (m_latch2 & 0x07) | ((m_latch2 & 0x10) >> 1), CHRROM); +} + + +/*------------------------------------------------- + + Board BMC-GKB + + Unknown Bootleg Multigame Board + Games: 68 in 1, 73 in 1, 98 in 1 + + iNES: mapper 58 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_bmc_gkb_device::write_h) +{ + UINT8 bank = (offset & 0x40) ? 0 : 1; + LOG_MMC(("bmc_gkb write_h, offset: %04x, data: %02x\n", offset, data)); + + prg16_89ab(offset & ~bank); + prg16_cdef(offset | bank); + chr8(offset >> 3, m_chr_source); + set_nt_mirroring(BIT(data, 7) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); +} + +/*------------------------------------------------- + + Board BMC-WS + + Games: Super 40-in-1 + + In MESS: Partially Supported (some games, like Galaxian, have + issues) + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_bmc_ws_device::write_m) +{ + UINT8 mmc_helper; + LOG_MMC(("bmc_ws write_m, offset: %04x, data: %02x\n", offset, data)); + + if (offset < 0x1000) + { + switch (offset & 0x01) + { + case 0: + if (!m_latch) + { + m_latch = data & 0x20; + set_nt_mirroring(BIT(data, 4) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + mmc_helper = (~data & 0x08) >> 3; + prg16_89ab(data & ~mmc_helper); + prg16_cdef(data | mmc_helper); + } + break; + case 1: + if (!m_latch) + chr8(data, CHRROM); + break; + } + } +} + +/*------------------------------------------------- + + Board BMC-11160 (by TXC?) + + Games: 6 in 1 (MGC-023) + + In MESS: Partially Supported + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_bmc_11160_device::write_h) +{ + LOG_MMC(("bmc_11160 write_h, offset: %04x, data: %02x\n", offset, data)); + + prg32((data & 0x70) >> 4); + chr8(((data & 0x70) >> 2) | (data & 3), m_chr_source); + set_nt_mirroring(BIT(data, 7) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); +} + +/*------------------------------------------------- + + Board BMC-G-146 + + Games: 1994 Super HIK 14 in 1 (G-136) + + In MESS: Partially Supported + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_bmc_g146_device::write_h) +{ + LOG_MMC(("bmc_g146 write_h, offset: %04x, data: %02x\n", offset, data)); + + if (offset & 0x800) + { + // UNROM mode + int helper = offset & BIT(offset, 6); + prg16_89ab((offset & 0x1f) | helper); + prg16_cdef((offset & 0x18) | 7); + } + else if (offset & 0x40) + { + // 16KB mode + prg16_89ab(offset & 0x1f); + prg16_cdef(offset & 0x1f); + } + else + prg32((offset & 0x1f) >> 4); + + set_nt_mirroring(!BIT(offset, 7) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); +} + +/*------------------------------------------------- + + Board BMC-8157 + + Games: 4 in 1 1993 (CK-001) + + In MESS: Partially Supported + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_bmc_8157_device::write_h) +{ + LOG_MMC(("bmc_8157 write_h, offset: %04x, data: %02x\n", offset, data)); + + prg16_89ab((offset >> 2) & 0x1f); + if (offset & 0x200) + prg16_cdef(offset & 0x1f); + else + prg16_cdef((offset & 0x18) | 7); + + set_nt_mirroring(!BIT(offset, 1) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); +} + +READ8_MEMBER(nes_bmc_8157_device::read_h) +{ + LOG_MMC(("bmc_8157 read_h, offset: %04x\n", offset)); + // m_dipsetting = ioport("CARTDIPS")->read(); + +// UINT8 val = hi_access_rom(offset); +// return val | m_noise; // the first write_h sets m_noise=0xff or 0 depending on dsw + + return hi_access_rom(offset); +} + + +/*------------------------------------------------- + + BMC-SUPERHIK_300IN1 + + Unknown Bootleg Multigame Board + Games: 100000 in 1, Super HIK 300 in 1, 1997 in 1 + + iNES: mapper 212 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_bmc_hik300_device::write_h) +{ + LOG_MMC(("bmc_hik300 write_h, offset: %04x, data: %02x\n", offset, data)); + + set_nt_mirroring(BIT(data, 3) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + chr8(offset, CHRROM); + + if (offset < 0x4000) + { + prg16_89ab(offset); + prg16_cdef(offset); + } + else + prg32(offset >> 1); +} + +/*------------------------------------------------- + + BMC-SUPER-700IN1 + + Unknown Bootleg Multigame Board + Games: Super 700 in 1 + + iNES: mapper 62 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_bmc_s700_device::write_h) +{ + LOG_MMC(("bmc_s700 write_h, offset :%04x, data: %02x\n", offset, data)); + + chr8(((offset & 0x1f) << 2) | (data & 0x03), CHRROM); + + if (offset & 0x20) + { + prg16_89ab((offset & 0x40) | ((offset >> 8) & 0x3f)); + prg16_cdef((offset & 0x40) | ((offset >> 8) & 0x3f)); + } + else + { + prg32(((offset & 0x40) | ((offset >> 8) & 0x3f)) >> 1); + } + + set_nt_mirroring(BIT(data, 7) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); +} + +/*------------------------------------------------- + + BMC-BALLGAMES-11IN1 + + Known Boards: Unknown Multigame Bootleg Board + Games: 11 in 1 Ball Games + + iNES: mapper 51 + + In MESS: Partially Supported. + + -------------------------------------------------*/ + +void nes_bmc_ball11_device::set_banks() +{ + set_nt_mirroring((m_reg[0] == 3) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + + if (m_reg[0] & 0x01) + { + prg32(m_reg[1]); + } + else + { + prg16_89ab((m_reg[1] << 1) | (m_reg[0] >> 1)); + prg16_cdef((m_reg[1] << 1) | 0x07); + } +} + +WRITE8_MEMBER(nes_bmc_ball11_device::write_m) +{ + LOG_MMC(("bmc_ball11 write_m, offset: %04x, data: %02x\n", offset, data)); + + m_reg[0] = ((data >> 1) & 0x01) | ((data >> 3) & 0x02); + set_banks(); +} + +WRITE8_MEMBER(nes_bmc_ball11_device::write_h) +{ + LOG_MMC(("bmc_ball11 write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x6000) + { + case 0x4000: // here we also update reg[0] upper bit + m_reg[0] = (m_reg[0] & 0x01) | ((data >> 3) & 0x02); + case 0x0000: + case 0x2000: + case 0x6000: + m_reg[1] = data & 0x0f; + set_banks(); + break; + } +} + +/*------------------------------------------------- + + BMC-22GAMES + + Unknown Bootleg Multigame Board + Games: 22 in 1 + + iNES: mapper 230 + + In MESS: Partially Supported. It would need a reset + to work (not possible yet) + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_bmc_22games_device::write_h) +{ + LOG_MMC(("bmc_22games write_h, offset: %04x, data: %02x\n", offset, data)); + + if (1) // this should flip at reset + { + prg16_89ab(data & 0x07); + } + else + { + if (data & 0x20) + { + prg16_89ab((data & 0x1f) + 8); + prg16_cdef((data & 0x1f) + 8); + } + else + { + prg16_89ab((data & 0x1f) + 8); + prg16_cdef((data & 0x1f) + 9); + } + set_nt_mirroring(BIT(data, 6) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ); + } +} + +/*------------------------------------------------- + + Board BMC-64IN1NOREPEAT + + Games: 64-in-1 Y2K + + In MESS: Supported + + -------------------------------------------------*/ + +void nes_bmc_64y2k_device::set_prg() +{ + UINT8 helper1 = (m_reg[1] & 0x1f); + UINT8 helper2 = (helper1 << 1) | ((m_reg[1] & 0x40) >> 6); + + if (m_reg[0] & 0x80) + { + if (m_reg[1] & 0x80) + prg32(helper1); + else + { + prg16_89ab(helper2); + prg16_cdef(helper2); + } + } + else + prg16_cdef(helper2); +} + +WRITE8_MEMBER(nes_bmc_64y2k_device::write_l) +{ + LOG_MMC(("bmc64y2k write_l, offset: %04x, data: %02x\n", offset, data)); + offset += 0x100; + + switch (offset) + { + case 0x1000: + case 0x1001: + case 0x1002: + case 0x1003: + m_reg[offset & 0x03] = data; + set_prg(); + chr8(((m_reg[0] >> 1) & 0x03) | (m_reg[2] << 2), CHRROM); + break; + } + if (offset == 0x1000) /* write to reg[0] also sets mirroring */ + set_nt_mirroring(BIT(data, 5) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); +} + +WRITE8_MEMBER(nes_bmc_64y2k_device::write_h) +{ + LOG_MMC(("bmc64y2k write_h, offset: %04x, data: %02x\n", offset, data)); + + m_reg[3] = data; // reg[3] is currently unused?!? +} + +/*------------------------------------------------- + + BMC-12IN1 + + Unknown Bootleg Multigame Board + Games: + + iNES: + + In MESS: Supported. + + -------------------------------------------------*/ + +void nes_bmc_12in1_device::update_banks() +{ + int bank = (m_reg[2] & 3) << 3; + + chr4_0((m_reg[0] >> 3) | (bank << 2), m_chr_source); + chr4_4((m_reg[1] >> 3) | (bank << 2), m_chr_source); + + if (m_reg[2] & 8) + prg32(((m_reg[0] & 7) >> 1) | bank); + else + { + prg16_89ab((m_reg[0] & 7) | bank); + prg16_cdef(7 | bank); + } + + set_nt_mirroring(BIT(m_reg[2], 2) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); +} + +WRITE8_MEMBER(nes_bmc_12in1_device::write_h) +{ + LOG_MMC(("bmc_12in1 write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x6000) + { + case 0x2000: m_reg[0] = data; break; + case 0x4000: m_reg[1] = data; break; + case 0x6000: m_reg[2] = data; break; + } + update_banks(); +} + +/*------------------------------------------------- + + BMC-20IN1 + + Unknown Bootleg Multigame Board + Games: 20 in 1 + + iNES: mapper 231 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_bmc_20in1_device::write_h) +{ + LOG_MMC(("bmc_20in1 write_h, offset: %04x, data: %02x\n", offset, data)); + + set_nt_mirroring(BIT(data, 7) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + + prg16_89ab((offset & 0x1e)); + prg16_cdef((offset & 0x1e) | ((offset & 0x20) ? 1 : 0)); +} + +/*------------------------------------------------- + + BMC-21IN1 + + Unknown Bootleg Multigame Board + Games: 8 in 1, 21 in 1 + + iNES: mapper 201 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_bmc_21in1_device::write_h) +{ + LOG_MMC(("bmc_21in1 write_h, offset: %04x, data: %02x\n", offset, data)); + + prg32(offset & 0x03); + chr8(offset & 0x03, CHRROM); +} + +/*------------------------------------------------- + + BMC-31IN1 + + Unknown Bootleg Multigame Board + Games: 31 in 1 + + iNES: mapper 229 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_bmc_31in1_device::write_h) +{ + LOG_MMC(("bmc_31in1 write_h, offset: %04x, data: %02x\n", offset, data)); + + set_nt_mirroring(BIT(data, 5) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + chr8(offset, CHRROM); + + if ((offset & 0x1e) == 0) + { + prg16_89ab(0); + prg16_89ab(1); + } + else + { + prg16_89ab(offset & 0x1f); + prg16_89ab(offset & 0x1f); + } +} + +/*------------------------------------------------- + + BMC-35IN1 + + Unknown Bootleg Multigame Board + Games: 35 in 1 + + iNES: mapper 203 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_bmc_35in1_device::write_h) +{ + LOG_MMC(("bmc_35in1 write_h, offset: %04x, data: %02x\n", offset, data)); + + prg16_89ab((data >> 2) & 0x03); + prg16_cdef((data >> 2) & 0x03); + chr8(data & 0x03, CHRROM); +} + +/*------------------------------------------------- + + BMC-36IN1 + + Unknown Bootleg Multigame Board + Games: 36 in 1, 1200 in 1 + + iNES: mapper 200 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_bmc_36in1_device::write_h) +{ + LOG_MMC(("bmc_36in1 write_h, offset: %04x, data: %02x\n", offset, data)); + + prg16_89ab(offset & 0x07); + prg16_cdef(offset & 0x07); + chr8(offset & 0x07, CHRROM); + + set_nt_mirroring(BIT(data, 3) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); +} + +/*------------------------------------------------- + + BMC-64IN1 + + Unknown Bootleg Multigame Board + Games: 64 in 1 + + iNES: mapper 204 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_bmc_64in1_device::write_h) +{ + int bank = (offset >> 1) & (offset >> 2) & 0x01; + + LOG_MMC(("bmc_64in1 write_h, offset: %04x, data: %02x\n", offset, data)); + + prg16_89ab(offset & ~bank); + prg16_cdef(offset | bank); + chr8(offset & ~bank, CHRROM); + + set_nt_mirroring(BIT(data, 4) ? PPU_MIRROR_HORZ: PPU_MIRROR_VERT); +} + +/*------------------------------------------------- + + BMC-70IN1 + + Unknown Bootleg Multigame Board + Games: + + iNES: mapper + + This is same hardware as BMC-800IN1 below, but this + cart has CHR and slightly diff bankswitch. + DSW not emulated yet. + + In MESS: Preliminary Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_bmc_70in1_device::write_h) +{ + LOG_MMC(("bmc70in1 write_h, offset: %04x, data: %02x\n", offset, data)); + + if (offset < 0x4000) + { + set_nt_mirroring(BIT(offset, 5) ? PPU_MIRROR_HORZ: PPU_MIRROR_VERT); + chr8(offset & 7, CHRROM); + } + else + { + switch (offset & 0x30) + { + case 0x00: m_mode = 0x0; m_reg[0] = (m_reg[0] & 0x38) | (offset & 0x7); m_reg[1] = m_reg[0] | 0x7; break; + case 0x10: m_mode = 0x1; m_reg[0] = (m_reg[0] & 0x38) | (offset & 0x7); m_reg[1] = m_reg[0] | 0x7; break; + case 0x20: m_mode = 0x0; m_reg[0] = (m_reg[0] & 0x38) | (offset & 0x6); m_reg[1] = m_reg[0] | 0x1; break; + case 0x30: m_mode = 0x0; m_reg[0] = (m_reg[0] & 0x38) | (offset & 0x7); m_reg[1] = m_reg[0] | 0x0; break; + } + prg16_89ab(m_reg[0]); + prg16_cdef(m_reg[1]); + } +} + +READ8_MEMBER(nes_bmc_70in1_device::read_h) +{ + LOG_MMC(("bmc70in1 read_h, offset: %04x\n", offset)); + + if (m_mode) + offset = (offset & 0x7ff0) | m_mode; + + return hi_access_rom(offset); +} + +/*------------------------------------------------- + + BMC-72IN1 + + Unknown Bootleg Multigame Board + Games: 72 in 1, 115 in 1 and other multigame carts + + iNES: mapper 225 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_bmc_72in1_device::write_h) +{ + int hi_bank = offset & 0x40; + int size_16 = offset & 0x1000; + int bank = (offset & 0xf80) >> 7; + + LOG_MMC(("bmc_72in1 write_h, offset: %04x, data: %02x\n", offset, data)); + + chr8(offset, CHRROM); + set_nt_mirroring((offset & 0x2000) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + if (size_16) + { + bank <<= 1; + if (hi_bank) + bank ++; + + prg16_89ab(bank); + prg16_cdef(bank); + } + else + prg32(bank); +} + +/*------------------------------------------------- + + BMC-76IN1 + + Unknown Bootleg Multigame Board + Games: 76 in 1, Super 42 in 1 + + iNES: mapper 226 + + In MESS: Supported. + + -------------------------------------------------*/ + +// does this work for super42in1 as well?!? +WRITE8_MEMBER(nes_bmc_76in1_device::write_h) +{ + int hi_bank; + int size_16; + int bank; + + LOG_MMC(("bmc_76in1 write_h, offset: %04x, data: %02x\n", offset, data)); + + if (offset & 0x01) + m_latch2 = data; + else + m_latch1 = data; + + set_nt_mirroring(BIT(m_latch1, 6) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + + hi_bank = m_latch1 & 0x01; + size_16 = m_latch1 & 0x20; + bank = ((m_latch1 & 0x1e) >> 1) | ((m_latch1 & 0x80) >> 3) | ((m_latch2 & 0x01) << 5); + + if (size_16) + { + bank <<= 1; + if (hi_bank) + bank ++; + + prg16_89ab(bank); + prg16_cdef(bank); + } + else + prg32(bank); +} + +/*------------------------------------------------- + + BMC-110IN1 + + Known Boards: Unknown Bootleg Board + Games: 110 in 1 + + iNES: mapper 255 + + In MESS: Preliminary support. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_bmc_110in1_device::write_h) +{ + UINT8 helper1 = (offset >> 12) ? 0 : 1; + UINT8 helper2 = ((offset >> 8) & 0x40) | ((offset >> 6) & 0x3f); + + LOG_MMC(("bmc_110in1 write_h, offset: %04x, data: %02x\n", offset, data)); + + set_nt_mirroring((offset & 0x2000) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + prg16_89ab(helper1 & ~helper2); + prg16_cdef(helper1 | helper2); + chr8(((offset >> 8) & 0x40) | (offset & 0x3f), CHRROM); +} + + +/*------------------------------------------------- + + BMC-150IN1 + + Unknown Bootleg Multigame Board + Games: 150 in 1 + + iNES: mapper 202 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_bmc_150in1_device::write_h) +{ + int bank = (offset >> 1) & 0x07; + + LOG_MMC(("bmc_150in1 write_h, offset: %04x, data: %02x\n", offset, data)); + + prg16_89ab(bank); + prg16_cdef(bank + (((bank & 0x06) == 0x06) ? 1 : 0)); + chr8(bank, CHRROM); + + set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ: PPU_MIRROR_VERT); +} + + +/*------------------------------------------------- + + Board BMC-190IN1 + + Games: 190-in-1 + + In MESS: Supported + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_bmc_190in1_device::write_h) +{ + LOG_MMC(("bmc190in1 write_h, offset: %04x, data: %02x\n", offset, data)); + + set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + offset >>= 2; + prg16_89ab(offset); + prg16_cdef(offset); + chr8(offset, CHRROM); +} + +/*------------------------------------------------- + + BMC-800IN1 + + Unknown Bootleg Multigame Board + Games: + + iNES: mapper + + DSW not emulated yet. + + In MESS: Preliminary Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_bmc_800in1_device::write_h) +{ + LOG_MMC(("bmc800in1 write_h, offset: %04x, data: %02x\n", offset, data)); + + if (offset < 0x4000) + { + set_nt_mirroring(BIT(offset, 5) ? PPU_MIRROR_HORZ: PPU_MIRROR_VERT); + + m_reg[0] = (m_reg[0]) | ((offset << 3) & 0x38); + m_reg[1] = (m_reg[1]) | ((offset << 3) & 0x38); + } + else + { + switch (offset & 0x30) + { + case 0x00: m_mode = 0x0; m_reg[0] = (m_reg[0] & 0x38) | (offset & 0x7); m_reg[1] = m_reg[0] | 0x7; break; + case 0x10: m_mode = 0x1; m_reg[0] = (m_reg[0] & 0x38) | (offset & 0x7); m_reg[1] = m_reg[0] | 0x7; break; + case 0x20: m_mode = 0x0; m_reg[0] = (m_reg[0] & 0x38) | (offset & 0x6); m_reg[1] = m_reg[0] | 0x1; break; + case 0x30: m_mode = 0x0; m_reg[0] = (m_reg[0] & 0x38) | (offset & 0x7); m_reg[1] = m_reg[0] | 0x0; break; + } + } + prg16_89ab(m_reg[0]); + prg16_cdef(m_reg[1]); +} + +READ8_MEMBER(nes_bmc_800in1_device::read_h) +{ + LOG_MMC(("bmc800in1 read_h, offset: %04x\n", offset)); + + if (m_mode) + offset = (offset & 0x7ff0) | m_mode; + + return hi_access_rom(offset); +} + +/*------------------------------------------------- + + BMC-1200IN1 + + Unknown Bootleg Multigame Board + Games: 1200 in 1, 295 in 1, 76 in 1 + + iNES: mapper 227 + + In MESS: Preliminary Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_bmc_1200in1_device::chr_w) +{ + int bank = offset >> 10; + + if (!m_vram_protect) + m_chr_access[bank][offset & 0x3ff] = data; +} + + +WRITE8_MEMBER(nes_bmc_1200in1_device::write_h) +{ + int bank = ((offset >> 2) & 0x1f) | ((offset & 0x0100) >> 3); + + LOG_MMC(("bmc_1200in1 write_h, offset: %04x, data: %02x\n", offset, data)); + + if (offset & 0x80) + { +// m_vram_protect = 1; + prg16_89ab(bank); + prg16_cdef(bank + (offset & 1)); + } + else + { + int low_mask = (offset & 1) ? 0x3e : 0xff; + +// m_vram_protect = 0; + if (!BIT(offset, 9)) + { + prg16_89ab(bank & low_mask); + prg16_cdef(bank & 0x38); + } + else + { + prg16_89ab(bank & low_mask); + prg16_cdef(bank | 0x07); + } + } + + set_nt_mirroring(BIT(offset, 1) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); +} + + +/*------------------------------------------------- + + BMC-GOLDEN260IN1 + + Unknown Bootleg Multigame Board + Games: + + iNES: mapper 235 + + In MESS: Preliminary Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_bmc_gold260_device::write_h) +{ + int bank = (offset & 0x1f) | ((offset & 0x0300) >> 3); + LOG_MMC(("bmc_gold260 write_h, offset: %04x, data: %02x\n", offset, data)); + + if (offset & 0x400) + set_nt_mirroring(PPU_MIRROR_LOW); + else + set_nt_mirroring(BIT(offset, 13) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + + if (offset & 0x800) + { + bank = (bank << 1) | BIT(offset, 12); + prg16_89ab(bank); + prg16_cdef(bank); + } + else + prg32(bank); +} + + +/*------------------------------------------------- + + BMC-GOLDEN150IN1 + + Unknown Bootleg Multigame Board + Games: + + iNES: mapper 235 + + Same as the above + open bus in 0x8000-0xffff when + enabled + + In MESS: Preliminary Supported. + + -------------------------------------------------*/ + + +WRITE8_MEMBER(nes_bmc_gold150_device::write_h) +{ + int bank = (offset & 0x1f) | ((offset & 0x0200) >> 4); + LOG_MMC(("bmc_gold150 write_h, offset: %04x, data: %02x\n", offset, data)); + + m_latch = (offset & 0x0100); + + if (offset & 0x400) + set_nt_mirroring(PPU_MIRROR_LOW); + else + set_nt_mirroring(BIT(offset, 13) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + + if (offset & 0x800) + { + bank = (bank << 1) | BIT(offset, 12); + prg16_89ab(bank); + prg16_cdef(bank); + } + else + prg32(bank); +} + +READ8_MEMBER(nes_bmc_gold150_device::read_h) +{ + LOG_MMC(("bmc_gold150 read_h, offset: %04x\n", offset)); + + if (m_latch) // open bus + return m_open_bus; + else + return hi_access_rom(offset); +} + + +/*------------------------------------------------- + + BMC-POWERFUL-255 + + Unknown Bootleg Multigame Board + Games: + + iNES: mapper 63 + + + In MESS: Preliminary Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_bmc_ch001_device::write_h) +{ + int bank = ((offset >> 1) & 0x1fc); + LOG_MMC(("bmc_ch001 write_h, offset: %04x, data: %02x\n", offset, data)); + + m_latch = ((offset & 0x300) == 0x300); + set_nt_mirroring(BIT(offset, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + + if (offset & 2) + { + prg8_89(bank + 0); + prg8_ab(bank + 1); + prg8_cd(bank + 2); + prg8_ef(bank + 3); + } + else + { + bank |= (offset & 4) >> 1; + prg8_89(bank + 0); + prg8_ab(bank + 1); + prg8_cd(bank + 0); + prg8_ef(bank + 1); + } + + if (offset & 0x800) // in this case, the last 8KB bank is switched differently... + prg8_ef((offset & 0x07c ) | ((offset & 0x6) ? 0x3 : 0x1)); +} + +READ8_MEMBER(nes_bmc_ch001_device::read_h) +{ + LOG_MMC(("bmc_ch001 read_h, offset: %04x\n", offset)); + + if (m_latch && offset < 0x4000) // open bus + return m_open_bus; + else + return hi_access_rom(offset); +} + +/*------------------------------------------------- + + BMC-SUPER22GAMES + + Unknown Bootleg Multigame Board + Games: + + iNES: + + is there a dsw to access the higher banks above 0x20? + + In MESS: Preliminary Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_bmc_super22_device::write_h) +{ + LOG_MMC(("bmc_super22 write_h, offset: %04x, data: %02x\n", offset, data)); + + if (data & 0x20) + { + prg16_89ab(data & 0x1f); + prg16_cdef(data & 0x1f); + } + else + prg32((data & 0x1f) >> 1); + + switch (data & 0xc0) + { + case 0x00: set_nt_mirroring(PPU_MIRROR_LOW); break; + case 0x40: set_nt_mirroring(PPU_MIRROR_VERT); break; + case 0x80: set_nt_mirroring(PPU_MIRROR_HORZ); break; + case 0xc0: set_nt_mirroring(PPU_MIRROR_HIGH); break; + } +} + + +/*------------------------------------------------- + + BMC-RESETBASED4IN1 + + Unknown Bootleg Multigame Board + + Games: + + iNES: + + No need to use handlers. At reset the banks change + and so does the game. + + In MESS: Preliminary Supported. + + -------------------------------------------------*/ + +/*------------------------------------------------- + + BMC-42IN1RESETBASED + + Unknown Bootleg Multigame Board + + Games: + + iNES: + + In MESS: Preliminary Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_bmc_42in1reset_device::write_h) +{ + int bank; + LOG_MMC(("bmc_42in1reset write_h, offset: %04x, data: %02x\n", offset, data)); + + m_reg[offset & 1] = data; + bank = (m_reg[0] & 0x1f) | (m_latch << 5) | ((m_reg[1] & 1) << 6); + + if (!(m_reg[0] & 0x20)) + prg32(bank >> 1); + else + { + prg16_89ab(bank); + prg16_cdef(bank); + } + + set_nt_mirroring(BIT(offset, 6) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + +} diff --git a/src/devices/bus/nes/namcot.c b/src/devices/bus/nes/namcot.c deleted file mode 100644 index 236effc4a24..00000000000 --- a/src/devices/bus/nes/namcot.c +++ /dev/null @@ -1,688 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Fabio Priuli -/*********************************************************************************************************** - - - NES/Famicom cartridge emulation for Namcot PCBs - - - Here we emulate the following PCBs - - * Namcot 3433 & 3443 (aka DxROM) [mapper 88, 204, 154] - * Namcot 3446 [mapper 76] - * Namcot 3425 [mapper 95] - * Namcot 163 [mapper 19] - * Namcot 175 [mapper 210] - * Namcot 340 [mapper 210] - - TODO: - - add sound feature of Namcot-163 - - Quinty is not working (same issue of Mendel Palace on TxROM boards, of course) - - ***********************************************************************************************************/ - - -#include "emu.h" -#include "namcot.h" -#include "ui/ui.h" - -#include "cpu/m6502/m6502.h" - -#ifdef NES_PCB_DEBUG -#define VERBOSE 1 -#else -#define VERBOSE 0 -#endif - -#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) - - -//------------------------------------------------- -// constructor -//------------------------------------------------- - -const device_type NES_NAMCOT3433 = &device_creator; -const device_type NES_NAMCOT3446 = &device_creator; -const device_type NES_NAMCOT3425 = &device_creator; -const device_type NES_NAMCOT175 = &device_creator; -const device_type NES_NAMCOT340 = &device_creator; -const device_type NES_NAMCOT163 = &device_creator; - - -nes_namcot3433_device::nes_namcot3433_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) - : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source) -{ -} - -nes_namcot3433_device::nes_namcot3433_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_NAMCOT3433, "NES Cart Namcot 3433 & 3443 / DxROM PCB", tag, owner, clock, "nes_namcot3433", __FILE__) -{ -} - -nes_namcot3446_device::nes_namcot3446_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_NAMCOT3446, "NES Cart Namcot 3446 PCB", tag, owner, clock, "nes_namcot3446", __FILE__) -{ -} - -nes_namcot3425_device::nes_namcot3425_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_NAMCOT3425, "NES Cart Namcot 3425 PCB", tag, owner, clock, "nes_namcot3425", __FILE__) -{ -} - -nes_namcot340_device::nes_namcot340_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) - : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source) -{ -} - -nes_namcot340_device::nes_namcot340_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_NAMCOT175, "NES Cart Namcot 340 PCB", tag, owner, clock, "nes_namcot340", __FILE__) -{ -} - -nes_namcot175_device::nes_namcot175_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_namcot340_device(mconfig, NES_NAMCOT340, "NES Cart Namcot 175 PCB", tag, owner, clock, "nes_namcot175", __FILE__) -{ -} - -nes_namcot163_device::nes_namcot163_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_namcot340_device(mconfig, NES_NAMCOT163, "NES Cart Namcot 163 PCB", tag, owner, clock, "nes_namcot163", __FILE__) -{ -} - - - -void nes_namcot3433_device::device_start() -{ - common_start(); - save_item(NAME(m_latch)); -} - -void nes_namcot3433_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(m_prg_chunks - 2); - prg16_cdef(m_prg_chunks - 1); - chr8(0, m_chr_source); - - m_latch = 0; -} - -void nes_namcot3446_device::device_start() -{ - common_start(); - save_item(NAME(m_latch)); -} - -void nes_namcot3446_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(0); - prg16_cdef(m_prg_chunks - 1); - chr8(0, m_chr_source); - - m_latch = 0; -} - -void nes_namcot3425_device::device_start() -{ - common_start(); - save_item(NAME(m_latch)); - save_item(NAME(m_reg)); -} - -void nes_namcot3425_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(0); - prg16_cdef(m_prg_chunks - 1); - chr8(0, m_chr_source); - - m_latch = 0; - memset(m_reg, 0, sizeof(m_reg)); -} - -void nes_namcot340_device::device_start() -{ - common_start(); - irq_timer = timer_alloc(TIMER_IRQ); - irq_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1)); - - save_item(NAME(m_irq_enable)); - save_item(NAME(m_irq_count)); - save_item(NAME(m_n163_ram)); - - m_mapper_sram_size = 0x2000; - m_mapper_sram = m_n163_ram; -} - -void nes_namcot340_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(0); - prg16_cdef(m_prg_chunks - 1); - chr8(0, m_chr_source); - set_nt_mirroring(PPU_MIRROR_VERT); - - m_irq_enable = 0; - m_irq_count = 0; -} - -void nes_namcot175_device::device_start() -{ - common_start(); - irq_timer = timer_alloc(TIMER_IRQ); - irq_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1)); - - save_item(NAME(m_irq_enable)); - save_item(NAME(m_irq_count)); - save_item(NAME(m_wram_protect)); - save_item(NAME(m_n163_ram)); - - m_mapper_sram_size = 0x2000; - m_mapper_sram = m_n163_ram; -} - -void nes_namcot175_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(0); - prg16_cdef(m_prg_chunks - 1); - chr8(0, m_chr_source); - set_nt_mirroring(PPU_MIRROR_VERT); - - m_irq_enable = 0; - m_irq_count = 0; - m_wram_protect = 0; -} - -void nes_namcot163_device::device_start() -{ - common_start(); - irq_timer = timer_alloc(TIMER_IRQ); - irq_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1)); - - save_item(NAME(m_irq_enable)); - save_item(NAME(m_irq_count)); - save_item(NAME(m_wram_protect)); - save_item(NAME(m_latch)); - save_item(NAME(m_chr_bank)); - save_item(NAME(m_n163_ram)); - - m_mapper_sram_size = 0x2000; - m_mapper_sram = m_n163_ram; -} - -void nes_namcot163_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(0); - prg16_cdef(m_prg_chunks - 1); - chr8(0, m_chr_source); - set_nt_mirroring(PPU_MIRROR_VERT); - - m_irq_enable = 0; - m_irq_count = 0; - m_wram_protect = 0; - m_latch = 0; - m_chr_bank = 0; -} - - - -/*------------------------------------------------- - mapper specific handlers - -------------------------------------------------*/ - -/*------------------------------------------------- - - DxROM & Namcot 3433 - 3443 - 3453 board emulation - - Games: Dragon Spirit - Aratanaru Densetsu, Namcot Mahjong, Quinty, - Devilman - - These are the same board, but DRROM (and Tengen 800004) have - 4-screen mirroring - - iNES: mappers 88, 206 (same as 88 but possibly 4-screen mirroring), - and 154 (same as 88 but with additional mirroring control) - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_namcot3433_device::dxrom_write) -{ - LOG_MMC(("dxrom_write, offset: %04x, data: %02x\n", offset, data)); - - if (!(offset & 1) && m_pcb_ctrl_mirror) - set_nt_mirroring(BIT(data, 6) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW); - - if (offset >= 0x2000) - return; - - switch (offset & 1) - { - case 1: - switch (m_latch & 0x07) - { - case 0: chr2_0(data >> 1, CHRROM); break; - case 1: chr2_2(data >> 1, CHRROM); break; - case 2: chr1_4(data | 0x40, CHRROM); break; - case 3: chr1_5(data | 0x40, CHRROM); break; - case 4: chr1_6(data | 0x40, CHRROM); break; - case 5: chr1_7(data | 0x40, CHRROM); break; - case 6: prg8_89(data); break; - case 7: prg8_ab(data); break; - } - break; - case 0: - m_latch = data; - break; - } -} - - -/*------------------------------------------------- - - Namcot 3446 board emulation - - Games: Digital Devil Monogatari - Megami Tensei - - These are similar Namcot 34x3, but different bankswitch capabilities - - iNES: mapper 76 - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_namcot3446_device::write_h) -{ - LOG_MMC(("namcot3446 write_h, offset: %04x, data: %02x\n", offset, data)); - - // NEStopia does not have this! - if (offset >= 0x2000) - { - if (!(offset & 1)) - set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); - return; - } - - switch (offset & 1) - { - case 1: - switch (m_latch & 0x07) - { - case 2: chr2_0(data, CHRROM); break; - case 3: chr2_2(data, CHRROM); break; - case 4: chr2_4(data, CHRROM); break; - case 5: chr2_6(data, CHRROM); break; - case 6: BIT(m_latch, 6) ? prg8_cd(data) : prg8_89(data); break; - case 7: prg8_ab(data); break; - } - break; - case 0: - m_latch = data; - break; - } -} - -/*------------------------------------------------- - - Namcot 3425 board emulation - - Games: Dragon Buster - - These are similar Namcot 34x3, but with NT mirroring (two - different modes) - - iNES: mapper 95 - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_namcot3425_device::write_h) -{ - UINT8 mode; - LOG_MMC(("namcot3425 write_h, offset: %04x, data: %02x\n", offset, data)); - if (offset >= 0x2000) - return; - - switch (offset & 1) - { - case 1: - mode = m_latch & 0x07; - switch (mode) - { - case 0: chr2_0(data >> 1, CHRROM); break; - case 1: chr2_2(data >> 1, CHRROM); break; - case 2: - case 3: - case 4: - case 5: - chr1_x(2 + mode, data, CHRROM); - m_reg[mode - 2] = BIT(data, 5); - if (!BIT(m_latch, 7)) - { - set_nt_page(0, CIRAM, m_reg[0], 1); - set_nt_page(1, CIRAM, m_reg[1], 1); - set_nt_page(2, CIRAM, m_reg[2], 1); - set_nt_page(3, CIRAM, m_reg[3], 1); - } - else - set_nt_mirroring(PPU_MIRROR_HORZ); - break; - case 6: prg8_89(data); break; - case 7: prg8_ab(data); break; - } - break; - case 0: - m_latch = data; - break; - } -} - -/*------------------------------------------------- - - Namcot-340 board emulation - - Games: Famista '92, '93 & '94, Top Striker, - Wagyan Land 2 & 3 - - This (and Namcot-175 below) is a cut-down version - of the Namcot-163 chip, without the sound capabilities. - They also cannot use NTRAM as VRAM and differ for - the mirroring handling - - iNES: mapper 210 - - In MESS: Supported - - -------------------------------------------------*/ - -void nes_namcot340_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) -{ - if (id == TIMER_IRQ) - { - if (m_irq_enable) - { - if (m_irq_count == 0x7fff) // counter does not wrap to 0! - m_maincpu->set_input_line(M6502_IRQ_LINE, ASSERT_LINE); - else - m_irq_count++; - } - } -} - -WRITE8_MEMBER(nes_namcot340_device::n340_lowrite) -{ - LOG_MMC(("n340_lowrite, offset: %04x, data: %02x\n", offset, data)); - offset += 0x100; - - switch (offset & 0x1800) - { - case 0x1000: /* low byte of IRQ */ - m_irq_count = (m_irq_count & 0x7f00) | data; - m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); - break; - case 0x1800: /* high byte of IRQ, IRQ enable in high bit */ - m_irq_count = (m_irq_count & 0xff) | ((data & 0x7f) << 8); - m_irq_enable = data & 0x80; - m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); - break; - } -} - -READ8_MEMBER(nes_namcot340_device::n340_loread) -{ - LOG_MMC(("n340_loread, offset: %04x\n", offset)); - offset += 0x100; - - switch (offset & 0x1800) - { - case 0x1000: - return m_irq_count & 0xff; - m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); - case 0x1800: - return (m_irq_count >> 8) & 0xff; - m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); - default: - return 0x00; - } -} - -WRITE8_MEMBER(nes_namcot340_device::n340_hiwrite) -{ - LOG_MMC(("n340_hiwrite, offset: %04x, data: %02x\n", offset, data)); - - switch (offset & 0x7800) - { - case 0x0000: case 0x0800: - case 0x1000: case 0x1800: - case 0x2000: case 0x2800: - case 0x3000: case 0x3800: - chr1_x(offset / 0x800, data, CHRROM); - break; - case 0x4000: - // no cart found with wram, so it is not clear if this could work as in Namcot-175... - break; - case 0x6000: - switch (data & 0xc0) - { - case 0x00: - set_nt_mirroring(PPU_MIRROR_LOW); - break; - case 0x40: - set_nt_mirroring(PPU_MIRROR_VERT); - break; - case 0x80: - set_nt_mirroring(PPU_MIRROR_HIGH); - break; - case 0xc0: - set_nt_mirroring(PPU_MIRROR_HORZ); - break; - } - prg8_89(data & 0x3f); - break; - case 0x6800: - prg8_ab(data & 0x3f); - break; - case 0x7000: - prg8_cd(data & 0x3f); - break; - } -} - - -/*------------------------------------------------- - - Namcot-175 board emulation - - Games: Chibi Maruko-chan, Family Circuit '91, - Famista '91 - - This (and Namcot-340 above) is a cut-down version - of the Namcot-163 chip, without the sound capabilities. - They also cannot use NTRAM as VRAM and differ for - the mirroring handling - - iNES: mapper 210 - - In MESS: Supported - - -------------------------------------------------*/ - -READ8_MEMBER(nes_namcot175_device::read_m) -{ - // the only game supporting this is Family Circuit '91, and it has 2KB of battery - // but it's mirrored up to 8KB (see Sprint Race -> Back Up menu breakage if not) - if (!m_battery.empty() && !m_wram_protect) - return m_battery[offset & (m_battery.size() - 1)]; - - return m_open_bus; // open bus -} - -WRITE8_MEMBER(nes_namcot175_device::write_m) -{ - // the only game supporting this is Family Circuit '91, and it has 2KB of battery - // but it's mirrored up to 8KB (see Sprint Race -> Back Up menu breakage if not) - if (!m_battery.empty() && !m_wram_protect) - m_battery[offset & (m_battery.size() - 1)] = data; -} - -WRITE8_MEMBER(nes_namcot175_device::write_h) -{ - LOG_MMC(("namcot175 write_h, offset: %04x, data: %02x\n", offset, data)); - - switch (offset & 0x7800) - { - case 0x4000: - m_wram_protect = data & 1; - break; - case 0x6000: - prg8_89(data & 0x3f); - break; - default: - n340_hiwrite(space, offset, data, mem_mask); - break; - } -} - -/*------------------------------------------------- - - Namcot-163 board emulation - - Games: Battle Fleet, Famista '90, Megami Tensei II, - Juvei Quest, etc. - - Compared to Namcot-175 here we have mapper controlled - mirroring, NTRAM mapping to VRAM and additional - sound hw inside the chip (currently unemulated) and - some internal RAM. - - iNES: mapper 19 - - In MESS: Supported (with no emulation of the - sound component) - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_namcot163_device::chr_w) -{ - int bank = offset >> 10; - - if (!(m_latch & 0x40) && m_chr_bank >= 0xe0) - { - // CIRAM!!! - machine().ui().popup_time(10, "CIRAM mapped to VRAM. Please contact MAMEDevs."); - - if (!m_nt_writable[bank & 0x03]) - return; - m_nt_access[bank & 0x03][offset & 0x3ff] = data; - } - // or ROM, so no write -} - -READ8_MEMBER(nes_namcot163_device::chr_r) -{ - int bank = offset >> 10; - if (!(m_latch & 0x40) && m_chr_bank >= 0xe0) - { - // CIRAM!!! - machine().ui().popup_time(10, "CIRAM mapped to VRAM. Please contact MAMEDevs."); - return m_nt_access[bank & 0x03][offset & 0x3ff]; - } - // or ROM, accessed as usual - return m_chr_access[bank][offset & 0x3ff]; -} - - -READ8_MEMBER(nes_namcot163_device::read_m) -{ - if (!m_battery.empty() && offset < m_battery.size()) - return m_battery[offset & (m_battery.size() - 1)]; - - return m_open_bus; // open bus -} - -WRITE8_MEMBER(nes_namcot163_device::write_m) -{ - // the pcb can separately protect each 2KB chunk of the external wram from writes - int bank = (offset & 0x1800) >> 11; - if (!m_battery.empty() && !BIT(m_wram_protect, bank)) - m_battery[offset & (m_battery.size() - 1)] = data; -} - -WRITE8_MEMBER(nes_namcot163_device::write_l) -{ - LOG_MMC(("namcot163 write_l, offset: %04x, data: %02x\n", offset, data)); - offset += 0x100; - - switch (offset & 0x1800) - { - case 0x0800: - LOG_MMC(("Namcot-163 sound reg write, data: %02x\n", data)); - break; - default: - n340_lowrite(space, offset, data, mem_mask); - break; - } -} - -READ8_MEMBER(nes_namcot163_device::read_l) -{ - LOG_MMC(("namcot163 read_l, offset: %04x\n", offset)); - offset += 0x100; - - switch (offset & 0x1800) - { - case 0x0800: - LOG_MMC(("Namcot-163 sound reg read\n")); - return 0; - default: - return n340_loread(space, offset, mem_mask); - } -} - -void nes_namcot163_device::set_mirror(UINT8 page, UINT8 data) -{ - if (data < 0xe0) - set_nt_page(page, VROM, data, 0); - else - set_nt_page(page, CIRAM, data & 0x01, 1); -} - -WRITE8_MEMBER(nes_namcot163_device::write_h) -{ - int page; - LOG_MMC(("namcot163 write_h, offset: %04x, data: %02x\n", offset, data)); - - switch (offset & 0x7800) - { - case 0x0000: case 0x0800: - case 0x1000: case 0x1800: - case 0x2000: case 0x2800: - case 0x3000: case 0x3800: - m_chr_bank = data; - chr1_x(offset / 0x800, m_chr_bank, CHRROM); - break; - case 0x4000: - case 0x4800: - case 0x5000: - case 0x5800: - page = (offset & 0x1800) >> 11; - set_mirror(page, data); - break; - case 0x6000: - // TODO: data & 40 (or data & c0) disable sound if set - prg8_89(data & 0x3f); - break; - case 0x6800: - m_latch = data & 0xc0; - prg8_ab(data & 0x3f); - break; - case 0x7800: - // the lower 4 bits work *BOTH* as WRAM write protect *AND* as sound address! - m_wram_protect = data & 0x0f; - LOG_MMC(("Namcot-163 sound address write, data: %02x\n", data)); - break; - default: - n340_hiwrite(space, offset, data, mem_mask); - break; - } -} diff --git a/src/devices/bus/nes/namcot.cpp b/src/devices/bus/nes/namcot.cpp new file mode 100644 index 00000000000..236effc4a24 --- /dev/null +++ b/src/devices/bus/nes/namcot.cpp @@ -0,0 +1,688 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for Namcot PCBs + + + Here we emulate the following PCBs + + * Namcot 3433 & 3443 (aka DxROM) [mapper 88, 204, 154] + * Namcot 3446 [mapper 76] + * Namcot 3425 [mapper 95] + * Namcot 163 [mapper 19] + * Namcot 175 [mapper 210] + * Namcot 340 [mapper 210] + + TODO: + - add sound feature of Namcot-163 + - Quinty is not working (same issue of Mendel Palace on TxROM boards, of course) + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "namcot.h" +#include "ui/ui.h" + +#include "cpu/m6502/m6502.h" + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_NAMCOT3433 = &device_creator; +const device_type NES_NAMCOT3446 = &device_creator; +const device_type NES_NAMCOT3425 = &device_creator; +const device_type NES_NAMCOT175 = &device_creator; +const device_type NES_NAMCOT340 = &device_creator; +const device_type NES_NAMCOT163 = &device_creator; + + +nes_namcot3433_device::nes_namcot3433_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +nes_namcot3433_device::nes_namcot3433_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_NAMCOT3433, "NES Cart Namcot 3433 & 3443 / DxROM PCB", tag, owner, clock, "nes_namcot3433", __FILE__) +{ +} + +nes_namcot3446_device::nes_namcot3446_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_NAMCOT3446, "NES Cart Namcot 3446 PCB", tag, owner, clock, "nes_namcot3446", __FILE__) +{ +} + +nes_namcot3425_device::nes_namcot3425_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_NAMCOT3425, "NES Cart Namcot 3425 PCB", tag, owner, clock, "nes_namcot3425", __FILE__) +{ +} + +nes_namcot340_device::nes_namcot340_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +nes_namcot340_device::nes_namcot340_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_NAMCOT175, "NES Cart Namcot 340 PCB", tag, owner, clock, "nes_namcot340", __FILE__) +{ +} + +nes_namcot175_device::nes_namcot175_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_namcot340_device(mconfig, NES_NAMCOT340, "NES Cart Namcot 175 PCB", tag, owner, clock, "nes_namcot175", __FILE__) +{ +} + +nes_namcot163_device::nes_namcot163_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_namcot340_device(mconfig, NES_NAMCOT163, "NES Cart Namcot 163 PCB", tag, owner, clock, "nes_namcot163", __FILE__) +{ +} + + + +void nes_namcot3433_device::device_start() +{ + common_start(); + save_item(NAME(m_latch)); +} + +void nes_namcot3433_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(m_prg_chunks - 2); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + + m_latch = 0; +} + +void nes_namcot3446_device::device_start() +{ + common_start(); + save_item(NAME(m_latch)); +} + +void nes_namcot3446_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + + m_latch = 0; +} + +void nes_namcot3425_device::device_start() +{ + common_start(); + save_item(NAME(m_latch)); + save_item(NAME(m_reg)); +} + +void nes_namcot3425_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + + m_latch = 0; + memset(m_reg, 0, sizeof(m_reg)); +} + +void nes_namcot340_device::device_start() +{ + common_start(); + irq_timer = timer_alloc(TIMER_IRQ); + irq_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1)); + + save_item(NAME(m_irq_enable)); + save_item(NAME(m_irq_count)); + save_item(NAME(m_n163_ram)); + + m_mapper_sram_size = 0x2000; + m_mapper_sram = m_n163_ram; +} + +void nes_namcot340_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + set_nt_mirroring(PPU_MIRROR_VERT); + + m_irq_enable = 0; + m_irq_count = 0; +} + +void nes_namcot175_device::device_start() +{ + common_start(); + irq_timer = timer_alloc(TIMER_IRQ); + irq_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1)); + + save_item(NAME(m_irq_enable)); + save_item(NAME(m_irq_count)); + save_item(NAME(m_wram_protect)); + save_item(NAME(m_n163_ram)); + + m_mapper_sram_size = 0x2000; + m_mapper_sram = m_n163_ram; +} + +void nes_namcot175_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + set_nt_mirroring(PPU_MIRROR_VERT); + + m_irq_enable = 0; + m_irq_count = 0; + m_wram_protect = 0; +} + +void nes_namcot163_device::device_start() +{ + common_start(); + irq_timer = timer_alloc(TIMER_IRQ); + irq_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1)); + + save_item(NAME(m_irq_enable)); + save_item(NAME(m_irq_count)); + save_item(NAME(m_wram_protect)); + save_item(NAME(m_latch)); + save_item(NAME(m_chr_bank)); + save_item(NAME(m_n163_ram)); + + m_mapper_sram_size = 0x2000; + m_mapper_sram = m_n163_ram; +} + +void nes_namcot163_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + set_nt_mirroring(PPU_MIRROR_VERT); + + m_irq_enable = 0; + m_irq_count = 0; + m_wram_protect = 0; + m_latch = 0; + m_chr_bank = 0; +} + + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + DxROM & Namcot 3433 - 3443 - 3453 board emulation + + Games: Dragon Spirit - Aratanaru Densetsu, Namcot Mahjong, Quinty, + Devilman + + These are the same board, but DRROM (and Tengen 800004) have + 4-screen mirroring + + iNES: mappers 88, 206 (same as 88 but possibly 4-screen mirroring), + and 154 (same as 88 but with additional mirroring control) + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_namcot3433_device::dxrom_write) +{ + LOG_MMC(("dxrom_write, offset: %04x, data: %02x\n", offset, data)); + + if (!(offset & 1) && m_pcb_ctrl_mirror) + set_nt_mirroring(BIT(data, 6) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW); + + if (offset >= 0x2000) + return; + + switch (offset & 1) + { + case 1: + switch (m_latch & 0x07) + { + case 0: chr2_0(data >> 1, CHRROM); break; + case 1: chr2_2(data >> 1, CHRROM); break; + case 2: chr1_4(data | 0x40, CHRROM); break; + case 3: chr1_5(data | 0x40, CHRROM); break; + case 4: chr1_6(data | 0x40, CHRROM); break; + case 5: chr1_7(data | 0x40, CHRROM); break; + case 6: prg8_89(data); break; + case 7: prg8_ab(data); break; + } + break; + case 0: + m_latch = data; + break; + } +} + + +/*------------------------------------------------- + + Namcot 3446 board emulation + + Games: Digital Devil Monogatari - Megami Tensei + + These are similar Namcot 34x3, but different bankswitch capabilities + + iNES: mapper 76 + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_namcot3446_device::write_h) +{ + LOG_MMC(("namcot3446 write_h, offset: %04x, data: %02x\n", offset, data)); + + // NEStopia does not have this! + if (offset >= 0x2000) + { + if (!(offset & 1)) + set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + return; + } + + switch (offset & 1) + { + case 1: + switch (m_latch & 0x07) + { + case 2: chr2_0(data, CHRROM); break; + case 3: chr2_2(data, CHRROM); break; + case 4: chr2_4(data, CHRROM); break; + case 5: chr2_6(data, CHRROM); break; + case 6: BIT(m_latch, 6) ? prg8_cd(data) : prg8_89(data); break; + case 7: prg8_ab(data); break; + } + break; + case 0: + m_latch = data; + break; + } +} + +/*------------------------------------------------- + + Namcot 3425 board emulation + + Games: Dragon Buster + + These are similar Namcot 34x3, but with NT mirroring (two + different modes) + + iNES: mapper 95 + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_namcot3425_device::write_h) +{ + UINT8 mode; + LOG_MMC(("namcot3425 write_h, offset: %04x, data: %02x\n", offset, data)); + if (offset >= 0x2000) + return; + + switch (offset & 1) + { + case 1: + mode = m_latch & 0x07; + switch (mode) + { + case 0: chr2_0(data >> 1, CHRROM); break; + case 1: chr2_2(data >> 1, CHRROM); break; + case 2: + case 3: + case 4: + case 5: + chr1_x(2 + mode, data, CHRROM); + m_reg[mode - 2] = BIT(data, 5); + if (!BIT(m_latch, 7)) + { + set_nt_page(0, CIRAM, m_reg[0], 1); + set_nt_page(1, CIRAM, m_reg[1], 1); + set_nt_page(2, CIRAM, m_reg[2], 1); + set_nt_page(3, CIRAM, m_reg[3], 1); + } + else + set_nt_mirroring(PPU_MIRROR_HORZ); + break; + case 6: prg8_89(data); break; + case 7: prg8_ab(data); break; + } + break; + case 0: + m_latch = data; + break; + } +} + +/*------------------------------------------------- + + Namcot-340 board emulation + + Games: Famista '92, '93 & '94, Top Striker, + Wagyan Land 2 & 3 + + This (and Namcot-175 below) is a cut-down version + of the Namcot-163 chip, without the sound capabilities. + They also cannot use NTRAM as VRAM and differ for + the mirroring handling + + iNES: mapper 210 + + In MESS: Supported + + -------------------------------------------------*/ + +void nes_namcot340_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (id == TIMER_IRQ) + { + if (m_irq_enable) + { + if (m_irq_count == 0x7fff) // counter does not wrap to 0! + m_maincpu->set_input_line(M6502_IRQ_LINE, ASSERT_LINE); + else + m_irq_count++; + } + } +} + +WRITE8_MEMBER(nes_namcot340_device::n340_lowrite) +{ + LOG_MMC(("n340_lowrite, offset: %04x, data: %02x\n", offset, data)); + offset += 0x100; + + switch (offset & 0x1800) + { + case 0x1000: /* low byte of IRQ */ + m_irq_count = (m_irq_count & 0x7f00) | data; + m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); + break; + case 0x1800: /* high byte of IRQ, IRQ enable in high bit */ + m_irq_count = (m_irq_count & 0xff) | ((data & 0x7f) << 8); + m_irq_enable = data & 0x80; + m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); + break; + } +} + +READ8_MEMBER(nes_namcot340_device::n340_loread) +{ + LOG_MMC(("n340_loread, offset: %04x\n", offset)); + offset += 0x100; + + switch (offset & 0x1800) + { + case 0x1000: + return m_irq_count & 0xff; + m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); + case 0x1800: + return (m_irq_count >> 8) & 0xff; + m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); + default: + return 0x00; + } +} + +WRITE8_MEMBER(nes_namcot340_device::n340_hiwrite) +{ + LOG_MMC(("n340_hiwrite, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x7800) + { + case 0x0000: case 0x0800: + case 0x1000: case 0x1800: + case 0x2000: case 0x2800: + case 0x3000: case 0x3800: + chr1_x(offset / 0x800, data, CHRROM); + break; + case 0x4000: + // no cart found with wram, so it is not clear if this could work as in Namcot-175... + break; + case 0x6000: + switch (data & 0xc0) + { + case 0x00: + set_nt_mirroring(PPU_MIRROR_LOW); + break; + case 0x40: + set_nt_mirroring(PPU_MIRROR_VERT); + break; + case 0x80: + set_nt_mirroring(PPU_MIRROR_HIGH); + break; + case 0xc0: + set_nt_mirroring(PPU_MIRROR_HORZ); + break; + } + prg8_89(data & 0x3f); + break; + case 0x6800: + prg8_ab(data & 0x3f); + break; + case 0x7000: + prg8_cd(data & 0x3f); + break; + } +} + + +/*------------------------------------------------- + + Namcot-175 board emulation + + Games: Chibi Maruko-chan, Family Circuit '91, + Famista '91 + + This (and Namcot-340 above) is a cut-down version + of the Namcot-163 chip, without the sound capabilities. + They also cannot use NTRAM as VRAM and differ for + the mirroring handling + + iNES: mapper 210 + + In MESS: Supported + + -------------------------------------------------*/ + +READ8_MEMBER(nes_namcot175_device::read_m) +{ + // the only game supporting this is Family Circuit '91, and it has 2KB of battery + // but it's mirrored up to 8KB (see Sprint Race -> Back Up menu breakage if not) + if (!m_battery.empty() && !m_wram_protect) + return m_battery[offset & (m_battery.size() - 1)]; + + return m_open_bus; // open bus +} + +WRITE8_MEMBER(nes_namcot175_device::write_m) +{ + // the only game supporting this is Family Circuit '91, and it has 2KB of battery + // but it's mirrored up to 8KB (see Sprint Race -> Back Up menu breakage if not) + if (!m_battery.empty() && !m_wram_protect) + m_battery[offset & (m_battery.size() - 1)] = data; +} + +WRITE8_MEMBER(nes_namcot175_device::write_h) +{ + LOG_MMC(("namcot175 write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x7800) + { + case 0x4000: + m_wram_protect = data & 1; + break; + case 0x6000: + prg8_89(data & 0x3f); + break; + default: + n340_hiwrite(space, offset, data, mem_mask); + break; + } +} + +/*------------------------------------------------- + + Namcot-163 board emulation + + Games: Battle Fleet, Famista '90, Megami Tensei II, + Juvei Quest, etc. + + Compared to Namcot-175 here we have mapper controlled + mirroring, NTRAM mapping to VRAM and additional + sound hw inside the chip (currently unemulated) and + some internal RAM. + + iNES: mapper 19 + + In MESS: Supported (with no emulation of the + sound component) + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_namcot163_device::chr_w) +{ + int bank = offset >> 10; + + if (!(m_latch & 0x40) && m_chr_bank >= 0xe0) + { + // CIRAM!!! + machine().ui().popup_time(10, "CIRAM mapped to VRAM. Please contact MAMEDevs."); + + if (!m_nt_writable[bank & 0x03]) + return; + m_nt_access[bank & 0x03][offset & 0x3ff] = data; + } + // or ROM, so no write +} + +READ8_MEMBER(nes_namcot163_device::chr_r) +{ + int bank = offset >> 10; + if (!(m_latch & 0x40) && m_chr_bank >= 0xe0) + { + // CIRAM!!! + machine().ui().popup_time(10, "CIRAM mapped to VRAM. Please contact MAMEDevs."); + return m_nt_access[bank & 0x03][offset & 0x3ff]; + } + // or ROM, accessed as usual + return m_chr_access[bank][offset & 0x3ff]; +} + + +READ8_MEMBER(nes_namcot163_device::read_m) +{ + if (!m_battery.empty() && offset < m_battery.size()) + return m_battery[offset & (m_battery.size() - 1)]; + + return m_open_bus; // open bus +} + +WRITE8_MEMBER(nes_namcot163_device::write_m) +{ + // the pcb can separately protect each 2KB chunk of the external wram from writes + int bank = (offset & 0x1800) >> 11; + if (!m_battery.empty() && !BIT(m_wram_protect, bank)) + m_battery[offset & (m_battery.size() - 1)] = data; +} + +WRITE8_MEMBER(nes_namcot163_device::write_l) +{ + LOG_MMC(("namcot163 write_l, offset: %04x, data: %02x\n", offset, data)); + offset += 0x100; + + switch (offset & 0x1800) + { + case 0x0800: + LOG_MMC(("Namcot-163 sound reg write, data: %02x\n", data)); + break; + default: + n340_lowrite(space, offset, data, mem_mask); + break; + } +} + +READ8_MEMBER(nes_namcot163_device::read_l) +{ + LOG_MMC(("namcot163 read_l, offset: %04x\n", offset)); + offset += 0x100; + + switch (offset & 0x1800) + { + case 0x0800: + LOG_MMC(("Namcot-163 sound reg read\n")); + return 0; + default: + return n340_loread(space, offset, mem_mask); + } +} + +void nes_namcot163_device::set_mirror(UINT8 page, UINT8 data) +{ + if (data < 0xe0) + set_nt_page(page, VROM, data, 0); + else + set_nt_page(page, CIRAM, data & 0x01, 1); +} + +WRITE8_MEMBER(nes_namcot163_device::write_h) +{ + int page; + LOG_MMC(("namcot163 write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x7800) + { + case 0x0000: case 0x0800: + case 0x1000: case 0x1800: + case 0x2000: case 0x2800: + case 0x3000: case 0x3800: + m_chr_bank = data; + chr1_x(offset / 0x800, m_chr_bank, CHRROM); + break; + case 0x4000: + case 0x4800: + case 0x5000: + case 0x5800: + page = (offset & 0x1800) >> 11; + set_mirror(page, data); + break; + case 0x6000: + // TODO: data & 40 (or data & c0) disable sound if set + prg8_89(data & 0x3f); + break; + case 0x6800: + m_latch = data & 0xc0; + prg8_ab(data & 0x3f); + break; + case 0x7800: + // the lower 4 bits work *BOTH* as WRAM write protect *AND* as sound address! + m_wram_protect = data & 0x0f; + LOG_MMC(("Namcot-163 sound address write, data: %02x\n", data)); + break; + default: + n340_hiwrite(space, offset, data, mem_mask); + break; + } +} diff --git a/src/devices/bus/nes/nanjing.c b/src/devices/bus/nes/nanjing.c deleted file mode 100644 index 4d0fc022520..00000000000 --- a/src/devices/bus/nes/nanjing.c +++ /dev/null @@ -1,175 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Fabio Priuli -/*********************************************************************************************************** - - - NES/Famicom cartridge emulation for Nanjing PCBs - - TODO: - - Emulate the variants often assigned to mapper 162/164 (and investigate connection with Waixing FS-304)! - - ***********************************************************************************************************/ - - -#include "emu.h" -#include "nanjing.h" - -#include "video/ppu2c0x.h" - - -#ifdef NES_PCB_DEBUG -#define VERBOSE 1 -#else -#define VERBOSE 0 -#endif - -#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) - - -//------------------------------------------------- -// constructor -//------------------------------------------------- - -const device_type NES_NANJING = &device_creator; - - -nes_nanjing_device::nes_nanjing_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_NANJING, "NES Cart Nanjing PCB", tag, owner, clock, "nes_nanjing", __FILE__) -{ -} - - - - -void nes_nanjing_device::device_start() -{ - common_start(); - save_item(NAME(m_count)); - save_item(NAME(m_latch1)); - save_item(NAME(m_latch2)); - save_item(NAME(m_reg)); -} - -void nes_nanjing_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(m_prg_chunks - 2); - prg16_cdef(m_prg_chunks - 1); - chr8(0, m_chr_source); - - m_count = 0xff; - m_latch1 = 0; - m_latch2 = 0; - m_reg[0] = 0xff; - m_reg[1] = 0; -} - - - - - -/*------------------------------------------------- - mapper specific handlers - -------------------------------------------------*/ - -/*------------------------------------------------- - - Bootleg Board by Nanjing - - Games: A lot of pirate originals - - iNES: mapper 163 - - In MESS: Unsupported. - - -------------------------------------------------*/ - -void nes_nanjing_device::hblank_irq(int scanline, int vblank, int blanked) -{ - if (BIT(m_reg[0], 7)) - { - if (scanline == 127) - { - chr4_0(1, CHRRAM); - chr4_4(1, CHRRAM); - } - - if (scanline == 239) - { - chr4_0(0, CHRRAM); - chr4_4(0, CHRRAM); - } - } - -} - -WRITE8_MEMBER(nes_nanjing_device::write_l) -{ - LOG_MMC(("nanjing write_l, offset: %04x, data: %02x\n", offset, data)); - - offset += 0x100; - - if (offset < 0x1000) - return; - - if (offset == 0x1100) // 0x5100 - { - if (data == 6) - prg32(3); - return; - } - - if (offset == 0x1101) // 0x5101 - { - UINT8 temp = m_count; - m_count = data; - - if (temp & !data) - m_latch2 ^= 0xff; - } - - switch (offset & 0x300) - { - case 0x000: - case 0x200: - m_reg[BIT(offset, 9)] = data; - if (!BIT(m_reg[0], 7) && machine().device("ppu")->get_current_scanline() <= 127) - chr8(0, CHRRAM); - break; - case 0x300: - m_latch1 = data; - break; - } - - prg32((m_reg[0] & 0x0f) | ((m_reg[1] & 0x0f) << 4)); -} - -READ8_MEMBER(nes_nanjing_device::read_l) -{ - UINT8 value = 0; - LOG_MMC(("nanjing read_l, offset: %04x\n", offset)); - - offset += 0x100; - - if (offset < 0x1000) - return 0; - - switch (offset & 0x700) - { - case 0x100: - value = m_latch1; - break; - case 0x500: - value = m_latch2 & m_latch1; - break; - case 0x000: - case 0x200: - case 0x300: - case 0x400: - case 0x600: - case 0x700: - value = 4; - break; - } - return value; -} diff --git a/src/devices/bus/nes/nanjing.cpp b/src/devices/bus/nes/nanjing.cpp new file mode 100644 index 00000000000..4d0fc022520 --- /dev/null +++ b/src/devices/bus/nes/nanjing.cpp @@ -0,0 +1,175 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for Nanjing PCBs + + TODO: + - Emulate the variants often assigned to mapper 162/164 (and investigate connection with Waixing FS-304)! + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "nanjing.h" + +#include "video/ppu2c0x.h" + + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_NANJING = &device_creator; + + +nes_nanjing_device::nes_nanjing_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_NANJING, "NES Cart Nanjing PCB", tag, owner, clock, "nes_nanjing", __FILE__) +{ +} + + + + +void nes_nanjing_device::device_start() +{ + common_start(); + save_item(NAME(m_count)); + save_item(NAME(m_latch1)); + save_item(NAME(m_latch2)); + save_item(NAME(m_reg)); +} + +void nes_nanjing_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(m_prg_chunks - 2); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + + m_count = 0xff; + m_latch1 = 0; + m_latch2 = 0; + m_reg[0] = 0xff; + m_reg[1] = 0; +} + + + + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + Bootleg Board by Nanjing + + Games: A lot of pirate originals + + iNES: mapper 163 + + In MESS: Unsupported. + + -------------------------------------------------*/ + +void nes_nanjing_device::hblank_irq(int scanline, int vblank, int blanked) +{ + if (BIT(m_reg[0], 7)) + { + if (scanline == 127) + { + chr4_0(1, CHRRAM); + chr4_4(1, CHRRAM); + } + + if (scanline == 239) + { + chr4_0(0, CHRRAM); + chr4_4(0, CHRRAM); + } + } + +} + +WRITE8_MEMBER(nes_nanjing_device::write_l) +{ + LOG_MMC(("nanjing write_l, offset: %04x, data: %02x\n", offset, data)); + + offset += 0x100; + + if (offset < 0x1000) + return; + + if (offset == 0x1100) // 0x5100 + { + if (data == 6) + prg32(3); + return; + } + + if (offset == 0x1101) // 0x5101 + { + UINT8 temp = m_count; + m_count = data; + + if (temp & !data) + m_latch2 ^= 0xff; + } + + switch (offset & 0x300) + { + case 0x000: + case 0x200: + m_reg[BIT(offset, 9)] = data; + if (!BIT(m_reg[0], 7) && machine().device("ppu")->get_current_scanline() <= 127) + chr8(0, CHRRAM); + break; + case 0x300: + m_latch1 = data; + break; + } + + prg32((m_reg[0] & 0x0f) | ((m_reg[1] & 0x0f) << 4)); +} + +READ8_MEMBER(nes_nanjing_device::read_l) +{ + UINT8 value = 0; + LOG_MMC(("nanjing read_l, offset: %04x\n", offset)); + + offset += 0x100; + + if (offset < 0x1000) + return 0; + + switch (offset & 0x700) + { + case 0x100: + value = m_latch1; + break; + case 0x500: + value = m_latch2 & m_latch1; + break; + case 0x000: + case 0x200: + case 0x300: + case 0x400: + case 0x600: + case 0x700: + value = 4; + break; + } + return value; +} diff --git a/src/devices/bus/nes/nes_carts.c b/src/devices/bus/nes/nes_carts.c deleted file mode 100644 index 6acac2fc6e7..00000000000 --- a/src/devices/bus/nes/nes_carts.c +++ /dev/null @@ -1,366 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Fabio Priuli -/********************************************************************** - - NES carts - -**********************************************************************/ - -#include "nes_carts.h" - -SLOT_INTERFACE_START(nes_cart) -// HROM, NROM, RROM, SROM & STROM - SLOT_INTERFACE_INTERNAL("nrom", NES_NROM) -// Nintendo Family BASIC pcb (NROM + 2K or 4K WRAM) - SLOT_INTERFACE_INTERNAL("hvc_basic", NES_FCBASIC) -// Extended NROM-368 board (NROM with 46K PRG) - SLOT_INTERFACE_INTERNAL("nrom368", NES_NROM368) -// Game Genie - SLOT_INTERFACE_INTERNAL("nrom_gg", NES_GGENIE) -// UNROM/UOROM - SLOT_INTERFACE_INTERNAL("uxrom", NES_UXROM) - SLOT_INTERFACE_INTERNAL("unrom_cc", NES_UXROM_CC) -// CNROM - SLOT_INTERFACE_INTERNAL("cnrom", NES_CNROM) -// Bandai PT-554 (CNROM boards + special audio chip, used by Aerobics Studio) - SLOT_INTERFACE_INTERNAL("bandai_pt554", NES_BANDAI_PT554) -// CPROM - SLOT_INTERFACE_INTERNAL("cprom", NES_CPROM) -// AMROM, ANROM, AOROM - SLOT_INTERFACE_INTERNAL("axrom", NES_AXROM) -// PxROM - SLOT_INTERFACE_INTERNAL("pxrom", NES_PXROM) -// FxROM - SLOT_INTERFACE_INTERNAL("fxrom", NES_FXROM) -// BNROM - SLOT_INTERFACE_INTERNAL("bnrom", NES_BXROM) -// GNROM & MHROM - SLOT_INTERFACE_INTERNAL("gxrom", NES_GXROM) -// UN1ROM - SLOT_INTERFACE_INTERNAL("un1rom", NES_UN1ROM) -// SxROM - SLOT_INTERFACE_INTERNAL("sxrom", NES_SXROM) - SLOT_INTERFACE_INTERNAL("sorom", NES_SOROM) - SLOT_INTERFACE_INTERNAL("sxrom_a", NES_SXROM_A) // in MMC1-A PRG RAM is always enabled - SLOT_INTERFACE_INTERNAL("sorom_a", NES_SOROM_A) // in MMC1-A PRG RAM is always enabled -// TxROM - SLOT_INTERFACE_INTERNAL("txrom", NES_TXROM) -// HKROM - SLOT_INTERFACE_INTERNAL("hkrom", NES_HKROM) -// TQROM - SLOT_INTERFACE_INTERNAL("tqrom", NES_TQROM) -// TxSROM - SLOT_INTERFACE_INTERNAL("txsrom", NES_TXSROM) -// ExROM - SLOT_INTERFACE_INTERNAL("exrom", NES_EXROM) -// RAM expansion + Disk System add-on - SLOT_INTERFACE_INTERNAL("disksys", NES_DISKSYS) -// Nintendo Custom boards - SLOT_INTERFACE_INTERNAL("pal_zz", NES_ZZ_PCB) - SLOT_INTERFACE_INTERNAL("nes_qj", NES_QJ_PCB) - SLOT_INTERFACE_INTERNAL("nes_event", NES_EVENT) -// Discrete Components boards -// IC_74x139x74 - SLOT_INTERFACE_INTERNAL("discrete_74x139", NES_74X139X74) -// IC_74x377 - SLOT_INTERFACE_INTERNAL("discrete_74x377", NES_74X377) -// Discrete board IC_74x161x161x32 - SLOT_INTERFACE_INTERNAL("discrete_74x161", NES_74X161X161X32) -// Discrete board IC_74x161x138 - SLOT_INTERFACE_INTERNAL("bitcorp_dis", NES_74X161X138) -// Bandai boards - SLOT_INTERFACE_INTERNAL("lz93d50", NES_LZ93D50) - SLOT_INTERFACE_INTERNAL("lz93d50_ep1", NES_LZ93D50_24C01) - SLOT_INTERFACE_INTERNAL("lz93d50_ep2", NES_LZ93D50_24C02) - SLOT_INTERFACE_INTERNAL("fcg", NES_FCG) - SLOT_INTERFACE_INTERNAL("fjump2", NES_FJUMP2) - SLOT_INTERFACE_INTERNAL("datach", NES_DATACH) - SLOT_INTERFACE_INTERNAL("karastudio", NES_KARAOKESTUDIO) - SLOT_INTERFACE_INTERNAL("oekakids", NES_OEKAKIDS) -// Irem boards - SLOT_INTERFACE_INTERNAL("g101", NES_G101) - SLOT_INTERFACE_INTERNAL("lrog017", NES_LROG017) - SLOT_INTERFACE_INTERNAL("h3001", NES_H3001) - SLOT_INTERFACE_INTERNAL("holydivr", NES_HOLYDIVR) - SLOT_INTERFACE_INTERNAL("tam_s1", NES_TAM_S1) -// Jaleco boards - SLOT_INTERFACE_INTERNAL("jf11", NES_JF11) - SLOT_INTERFACE_INTERNAL("jf13", NES_JF13) - SLOT_INTERFACE_INTERNAL("jf16", NES_JF16) - SLOT_INTERFACE_INTERNAL("jf17", NES_JF17) - SLOT_INTERFACE_INTERNAL("jf17pcm", NES_JF17_ADPCM) - SLOT_INTERFACE_INTERNAL("jf19", NES_JF19) - SLOT_INTERFACE_INTERNAL("jf19pcm", NES_JF19_ADPCM) - SLOT_INTERFACE_INTERNAL("ss88006", NES_SS88006) - SLOT_INTERFACE_INTERNAL("jf23", NES_JF23) - SLOT_INTERFACE_INTERNAL("jf24", NES_JF24) - SLOT_INTERFACE_INTERNAL("jf29", NES_JF29) - SLOT_INTERFACE_INTERNAL("jf33", NES_JF33) -// Konami boards - SLOT_INTERFACE_INTERNAL("vrc1", NES_VRC1) - SLOT_INTERFACE_INTERNAL("vrc2", NES_VRC2) - SLOT_INTERFACE_INTERNAL("vrc3", NES_VRC3) - SLOT_INTERFACE_INTERNAL("vrc4", NES_VRC4) - SLOT_INTERFACE_INTERNAL("vrc6", NES_VRC6) - SLOT_INTERFACE_INTERNAL("vrc7", NES_VRC7) -// Namcot boards - SLOT_INTERFACE_INTERNAL("namcot_163", NES_NAMCOT163) - SLOT_INTERFACE_INTERNAL("namcot_175", NES_NAMCOT175) - SLOT_INTERFACE_INTERNAL("namcot_340", NES_NAMCOT340) - SLOT_INTERFACE_INTERNAL("namcot_3433", NES_NAMCOT3433) // DxROM is a Nintendo board for US versions of the 3433/3443 games - SLOT_INTERFACE_INTERNAL("namcot_3425", NES_NAMCOT3425) - SLOT_INTERFACE_INTERNAL("namcot_3446", NES_NAMCOT3446) -// Sunsoft boards - SLOT_INTERFACE_INTERNAL("sunsoft1", NES_SUNSOFT_1) - SLOT_INTERFACE_INTERNAL("sunsoft2", NES_SUNSOFT_2) - SLOT_INTERFACE_INTERNAL("sunsoft3", NES_SUNSOFT_3) - SLOT_INTERFACE_INTERNAL("sunsoft4", NES_SUNSOFT_4) - SLOT_INTERFACE_INTERNAL("sunsoft_dcs", NES_SUNSOFT_DCS) - SLOT_INTERFACE_INTERNAL("sunsoft_fme7", NES_SUNSOFT_FME7) // JxROM is a Nintendo board for US versions of the Sunsoft FME7 games - SLOT_INTERFACE_INTERNAL("sunsoft5a", NES_SUNSOFT_5) - SLOT_INTERFACE_INTERNAL("sunsoft5b", NES_SUNSOFT_5) -// Taito boards - SLOT_INTERFACE_INTERNAL("tc0190fmc", NES_TC0190FMC) - SLOT_INTERFACE_INTERNAL("tc0190fmcp", NES_TC0190FMC_PAL16R4) - SLOT_INTERFACE_INTERNAL("tc0350fmr", NES_TC0190FMC) - SLOT_INTERFACE_INTERNAL("x1_005", NES_X1_005) // two variants exist, depending on pin17 & pin31 connections - SLOT_INTERFACE_INTERNAL("x1_017", NES_X1_017) -// Misc pirate boards (by AVE, Camerica, C&E, Nanjing, NTDEC, JY Company, Sachen, Tengen, TXC, Waixing, Henggendianzi, etc.) - SLOT_INTERFACE_INTERNAL("nina001", NES_NINA001) - SLOT_INTERFACE_INTERNAL("nina006", NES_NINA006) - SLOT_INTERFACE_INTERNAL("bf9093", NES_BF9093) - SLOT_INTERFACE_INTERNAL("bf9096", NES_BF9096) - SLOT_INTERFACE_INTERNAL("goldenfive", NES_GOLDEN5) - SLOT_INTERFACE_INTERNAL("ade", NES_ALADDIN) - SLOT_INTERFACE_INTERNAL("cne_decathl", NES_CNE_DECATHL) - SLOT_INTERFACE_INTERNAL("cne_fsb", NES_CNE_FSB) - SLOT_INTERFACE_INTERNAL("cne_shlz", NES_CNE_SHLZ) - SLOT_INTERFACE_INTERNAL("nanjing", NES_NANJING) // mapper 163 - SLOT_INTERFACE_INTERNAL("ntdec_asder", NES_NTDEC_ASDER) // mapper 112 - SLOT_INTERFACE_INTERNAL("ntdec_fh", NES_NTDEC_FH) // mapper 193 - SLOT_INTERFACE_INTERNAL("jyc_a", NES_JY_TYPEA) // mapper 90 - SLOT_INTERFACE_INTERNAL("jyc_b", NES_JY_TYPEB) // mapper 211 - SLOT_INTERFACE_INTERNAL("jyc_c", NES_JY_TYPEC) // mapper 209 - SLOT_INTERFACE_INTERNAL("sa009", NES_SACHEN_SA009) - SLOT_INTERFACE_INTERNAL("sa0036", NES_SACHEN_SA0036) - SLOT_INTERFACE_INTERNAL("sa0037", NES_SACHEN_SA0037) - SLOT_INTERFACE_INTERNAL("sa72007", NES_SACHEN_SA72007) - SLOT_INTERFACE_INTERNAL("sa72008", NES_SACHEN_SA72008) - SLOT_INTERFACE_INTERNAL("tca01", NES_SACHEN_TCA01) - SLOT_INTERFACE_INTERNAL("s8259a", NES_SACHEN_8259A) - SLOT_INTERFACE_INTERNAL("s8259b", NES_SACHEN_8259B) - SLOT_INTERFACE_INTERNAL("s8259c", NES_SACHEN_8259C) - SLOT_INTERFACE_INTERNAL("s8259d", NES_SACHEN_8259D) - SLOT_INTERFACE_INTERNAL("s74x374", NES_SACHEN_74X374) - SLOT_INTERFACE_INTERNAL("s74x374a", NES_SACHEN_74X374_ALT) /* FIXME: Made up boards some different handling */ - SLOT_INTERFACE_INTERNAL("tcu01", NES_SACHEN_TCU01) - SLOT_INTERFACE_INTERNAL("tcu02", NES_SACHEN_TCU02) - SLOT_INTERFACE_INTERNAL("tengen_800008", NES_TENGEN_800008) /* FIXME: Is this the same as CNROM? */ - SLOT_INTERFACE_INTERNAL("tengen_800032", NES_TENGEN_800032) - SLOT_INTERFACE_INTERNAL("tengen_800037", NES_TENGEN_800037) - SLOT_INTERFACE_INTERNAL("txc_22211", NES_TXC_22211) - SLOT_INTERFACE_INTERNAL("txc_dumarc", NES_TXC_DUMARACING) - SLOT_INTERFACE_INTERNAL("txc_mjblock", NES_TXC_MJBLOCK) - SLOT_INTERFACE_INTERNAL("txc_strikew", NES_TXC_STRIKEW) - SLOT_INTERFACE_INTERNAL("txc_commandos", NES_TXC_COMMANDOS) - SLOT_INTERFACE_INTERNAL("waixing_a", NES_WAIXING_A) - SLOT_INTERFACE_INTERNAL("waixing_a1", NES_WAIXING_A1) /* FIXME: Made up boards the different CHRRAM banks (see Ji Jia Zhan Shi) */ - SLOT_INTERFACE_INTERNAL("waixing_b", NES_WAIXING_B) - SLOT_INTERFACE_INTERNAL("waixing_c", NES_WAIXING_C) - SLOT_INTERFACE_INTERNAL("waixing_d", NES_WAIXING_D) - SLOT_INTERFACE_INTERNAL("waixing_e", NES_WAIXING_E) - SLOT_INTERFACE_INTERNAL("waixing_f", NES_WAIXING_F) - SLOT_INTERFACE_INTERNAL("waixing_g", NES_WAIXING_G) - SLOT_INTERFACE_INTERNAL("waixing_h", NES_WAIXING_H) - SLOT_INTERFACE_INTERNAL("waixing_h1", NES_WAIXING_H1) /* FIXME: Made up boards the different WRAM protect banks (see Shen Mi Jin San Jiao) */ - SLOT_INTERFACE_INTERNAL("waixing_i", NES_WAIXING_I) - SLOT_INTERFACE_INTERNAL("waixing_j", NES_WAIXING_J) - SLOT_INTERFACE_INTERNAL("waixing_sgz", NES_WAIXING_SGZ) - SLOT_INTERFACE_INTERNAL("waixing_sgzlz", NES_WAIXING_SGZLZ) - SLOT_INTERFACE_INTERNAL("waixing_sec", NES_WAIXING_SEC) - SLOT_INTERFACE_INTERNAL("waixing_ffv", NES_WAIXING_FFV) - SLOT_INTERFACE_INTERNAL("waixing_wxzs", NES_WAIXING_WXZS) - SLOT_INTERFACE_INTERNAL("waixing_wxzs2", NES_WAIXING_WXZS2) - SLOT_INTERFACE_INTERNAL("waixing_dq8", NES_WAIXING_DQ8) - SLOT_INTERFACE_INTERNAL("waixing_sh2", NES_WAIXING_SH2) - SLOT_INTERFACE_INTERNAL("fs304", NES_WAIXING_FS304) // used in Zelda 3 by Waixing - SLOT_INTERFACE_INTERNAL("cony", NES_CONY) - SLOT_INTERFACE_INTERNAL("yoko", NES_YOKO) - SLOT_INTERFACE_INTERNAL("hengg_srich", NES_HENGG_SRICH) - SLOT_INTERFACE_INTERNAL("hengg_xhzs", NES_HENGG_XHZS) - SLOT_INTERFACE_INTERNAL("hengg_shjy3", NES_HENGG_SHJY3) // mapper 253 - SLOT_INTERFACE_INTERNAL("hes", NES_HES) - SLOT_INTERFACE_INTERNAL("hosenkan", NES_HOSENKAN) - SLOT_INTERFACE_INTERNAL("ks7058", NES_KS7058) - SLOT_INTERFACE_INTERNAL("ks202", NES_KS202) // mapper 56 - SLOT_INTERFACE_INTERNAL("ks7022", NES_KS7022)// mapper 175 - SLOT_INTERFACE_INTERNAL("ks7017", NES_KS7017) - SLOT_INTERFACE_INTERNAL("ks7032", NES_KS7032) // mapper 142 - SLOT_INTERFACE_INTERNAL("ks7012", NES_KS7012) // used in Zanac (FDS Conversion) - SLOT_INTERFACE_INTERNAL("ks7013b", NES_KS7013B) // used in Highway Star (FDS Conversion) - SLOT_INTERFACE_INTERNAL("ks7031", NES_KS7031) // used in Dracula II (FDS Conversion) - SLOT_INTERFACE_INTERNAL("gs2015", NES_GS2015) - SLOT_INTERFACE_INTERNAL("gs2004", NES_GS2004) - SLOT_INTERFACE_INTERNAL("gs2013", NES_GS2013) - SLOT_INTERFACE_INTERNAL("tf9in1", NES_TF9IN1) - SLOT_INTERFACE_INTERNAL("3dblock", NES_3DBLOCK) // NROM + IRQ? - SLOT_INTERFACE_INTERNAL("racermate", NES_RACERMATE) // mapper 168 - SLOT_INTERFACE_INTERNAL("agci_50282", NES_AGCI_50282) - SLOT_INTERFACE_INTERNAL("dreamtech01", NES_DREAMTECH01) - SLOT_INTERFACE_INTERNAL("fukutake", NES_FUKUTAKE) - SLOT_INTERFACE_INTERNAL("futuremedia", NES_FUTUREMEDIA) - SLOT_INTERFACE_INTERNAL("magicseries", NES_MAGSERIES) - SLOT_INTERFACE_INTERNAL("daou_306", NES_DAOU306) - SLOT_INTERFACE_INTERNAL("subor0", NES_SUBOR0) - SLOT_INTERFACE_INTERNAL("subor1", NES_SUBOR1) - SLOT_INTERFACE_INTERNAL("cc21", NES_CC21) - SLOT_INTERFACE_INTERNAL("xiaozy", NES_XIAOZY) - SLOT_INTERFACE_INTERNAL("edu2k", NES_EDU2K) - SLOT_INTERFACE_INTERNAL("t230", NES_T230) - SLOT_INTERFACE_INTERNAL("mk2", NES_MK2) - SLOT_INTERFACE_INTERNAL("unl_whero", NES_WHERO) // mapper 27 - SLOT_INTERFACE_INTERNAL("unl_43272", NES_43272) // used in Gaau Hok Gwong Cheung - SLOT_INTERFACE_INTERNAL("tf1201", NES_TF1201) - SLOT_INTERFACE_INTERNAL("unl_cfight", NES_CITYFIGHT) // used by City Fighter IV -// misc bootleg boards - SLOT_INTERFACE_INTERNAL("ax5705", NES_AX5705) - SLOT_INTERFACE_INTERNAL("sc127", NES_SC127) - SLOT_INTERFACE_INTERNAL("mariobaby", NES_MARIOBABY) - SLOT_INTERFACE_INTERNAL("asnicol", NES_ASN) - SLOT_INTERFACE_INTERNAL("smb3pirate", NES_SMB3PIRATE) - SLOT_INTERFACE_INTERNAL("btl_dninja", NES_BTL_DNINJA) - SLOT_INTERFACE_INTERNAL("whirl2706", NES_WHIRLWIND_2706) - SLOT_INTERFACE_INTERNAL("smb2j", NES_SMB2J) - SLOT_INTERFACE_INTERNAL("smb2ja", NES_SMB2JA) - SLOT_INTERFACE_INTERNAL("smb2jb", NES_SMB2JB) - SLOT_INTERFACE_INTERNAL("09034a", NES_09034A) - SLOT_INTERFACE_INTERNAL("tobidase", NES_TOBIDASE) // mapper 120 - SLOT_INTERFACE_INTERNAL("mmalee2", NES_MMALEE) // mapper 55? - SLOT_INTERFACE_INTERNAL("unl_2708", NES_2708) // mapper 103 - SLOT_INTERFACE_INTERNAL("unl_lh32", NES_LH32) // used by Monty no Doki Doki Daidassou FDS conversion - SLOT_INTERFACE_INTERNAL("unl_lh10", NES_LH10) // used in Fuuun Shaolin Kyo (FDS Conversion) - SLOT_INTERFACE_INTERNAL("unl_lh53", NES_LH53) // used in Nazo no Murasamejou (FDS Conversion) - SLOT_INTERFACE_INTERNAL("unl_ac08", NES_AC08) // used by Green Beret FDS conversion - SLOT_INTERFACE_INTERNAL("unl_bb", NES_UNL_BB) // used by a few FDS conversions - SLOT_INTERFACE_INTERNAL("sgpipe", NES_SHUIGUAN) // mapper 183 -// misc MMC3 clone boards - SLOT_INTERFACE_INTERNAL("dbz5", NES_REX_DBZ5) - SLOT_INTERFACE_INTERNAL("sl1632", NES_REX_SL1632) - SLOT_INTERFACE_INTERNAL("somari", NES_SOMARI) // mapper 116 - SLOT_INTERFACE_INTERNAL("nitra", NES_NITRA) - SLOT_INTERFACE_INTERNAL("ks7057", NES_KS7057) // mapper 196 alt (for Street Fighter VI / Fight Street VI) - SLOT_INTERFACE_INTERNAL("sbros11", NES_SBROS11) - SLOT_INTERFACE_INTERNAL("unl_malisb", NES_MALISB) // used by Super Mali Splash Bomb - SLOT_INTERFACE_INTERNAL("family4646", NES_FAMILY4646) - SLOT_INTERFACE_INTERNAL("pikay2k", NES_PIKAY2K) // mapper 254 - SLOT_INTERFACE_INTERNAL("8237", NES_8237) - SLOT_INTERFACE_INTERNAL("8237a", NES_NROM) // UNSUPPORTED - SLOT_INTERFACE_INTERNAL("sg_lionk", NES_SG_LIONK) - SLOT_INTERFACE_INTERNAL("sg_boog", NES_SG_BOOG) - SLOT_INTERFACE_INTERNAL("kasing", NES_KASING) - SLOT_INTERFACE_INTERNAL("kay", NES_KAY) - SLOT_INTERFACE_INTERNAL("h2288", NES_H2288) - SLOT_INTERFACE_INTERNAL("unl_6035052", NES_6035052) // mapper 238? - SLOT_INTERFACE_INTERNAL("txc_tw", NES_TXC_TW) - SLOT_INTERFACE_INTERNAL("kof97", NES_KOF97) - SLOT_INTERFACE_INTERNAL("kof96", NES_KOF96) - SLOT_INTERFACE_INTERNAL("sfight3", NES_SF3) - SLOT_INTERFACE_INTERNAL("gouder", NES_GOUDER) - SLOT_INTERFACE_INTERNAL("sa9602b", NES_SA9602B) - SLOT_INTERFACE_INTERNAL("unl_shero", NES_SACHEN_SHERO) -// misc multigame cart boards - SLOT_INTERFACE_INTERNAL("benshieng", NES_BENSHIENG) - SLOT_INTERFACE_INTERNAL("action52", NES_ACTION52) - SLOT_INTERFACE_INTERNAL("caltron6in1", NES_CALTRON6IN1) - SLOT_INTERFACE_INTERNAL("maxi15", NES_MAXI15) // mapper 234 - SLOT_INTERFACE_INTERNAL("rumblestation", NES_RUMBLESTATION) // mapper 46 - SLOT_INTERFACE_INTERNAL("svision16", NES_SVISION16) // mapper 53 - SLOT_INTERFACE_INTERNAL("n625092", NES_N625092) - SLOT_INTERFACE_INTERNAL("a65as", NES_A65AS) - SLOT_INTERFACE_INTERNAL("t262", NES_T262) - SLOT_INTERFACE_INTERNAL("novel1", NES_NOVEL1) - SLOT_INTERFACE_INTERNAL("novel2", NES_NOVEL2) // mapper 213... same as BMC-NOVELDIAMOND9999999IN1 board? - SLOT_INTERFACE_INTERNAL("studyngame", NES_STUDYNGAME) // mapper 39 - SLOT_INTERFACE_INTERNAL("sgun20in1", NES_SUPERGUN20IN1) - SLOT_INTERFACE_INTERNAL("bmc_vt5201", NES_VT5201) // mapper 60 otherwise - SLOT_INTERFACE_INTERNAL("bmc_d1038", NES_VT5201) // mapper 60? - SLOT_INTERFACE_INTERNAL("810544c", NES_810544C) - SLOT_INTERFACE_INTERNAL("ntd03", NES_NTD03) - SLOT_INTERFACE_INTERNAL("bmc_gb63", NES_BMC_GB63) - SLOT_INTERFACE_INTERNAL("bmc_gka", NES_BMC_GKA) - SLOT_INTERFACE_INTERNAL("bmc_gkb", NES_BMC_GKB) - SLOT_INTERFACE_INTERNAL("bmc_ws", NES_BMC_WS) - SLOT_INTERFACE_INTERNAL("bmc_g146", NES_BMC_G146) - SLOT_INTERFACE_INTERNAL("bmc_11160", NES_BMC_11160) - SLOT_INTERFACE_INTERNAL("bmc_8157", NES_BMC_8157) - SLOT_INTERFACE_INTERNAL("bmc_hik300", NES_BMC_HIK300) - SLOT_INTERFACE_INTERNAL("bmc_s700", NES_BMC_S700) - SLOT_INTERFACE_INTERNAL("bmc_ball11", NES_BMC_BALL11) - SLOT_INTERFACE_INTERNAL("bmc_22games", NES_BMC_22GAMES) - SLOT_INTERFACE_INTERNAL("bmc_64y2k", NES_BMC_64Y2K) - SLOT_INTERFACE_INTERNAL("bmc_12in1", NES_BMC_12IN1) - SLOT_INTERFACE_INTERNAL("bmc_20in1", NES_BMC_20IN1) - SLOT_INTERFACE_INTERNAL("bmc_21in1", NES_BMC_21IN1) - SLOT_INTERFACE_INTERNAL("bmc_31in1", NES_BMC_31IN1) - SLOT_INTERFACE_INTERNAL("bmc_35in1", NES_BMC_35IN1) - SLOT_INTERFACE_INTERNAL("bmc_36in1", NES_BMC_36IN1) - SLOT_INTERFACE_INTERNAL("bmc_64in1", NES_BMC_64IN1) - SLOT_INTERFACE_INTERNAL("bmc_70in1", NES_BMC_70IN1) // mapper 236? - SLOT_INTERFACE_INTERNAL("bmc_72in1", NES_BMC_72IN1) - SLOT_INTERFACE_INTERNAL("bmc_76in1", NES_BMC_76IN1) - SLOT_INTERFACE_INTERNAL("bmc_s42in1", NES_BMC_76IN1) - SLOT_INTERFACE_INTERNAL("bmc_110in1", NES_BMC_110IN1) - SLOT_INTERFACE_INTERNAL("bmc_150in1", NES_BMC_150IN1) - SLOT_INTERFACE_INTERNAL("bmc_190in1", NES_BMC_190IN1) - SLOT_INTERFACE_INTERNAL("bmc_800in1", NES_BMC_800IN1) // mapper 236? - SLOT_INTERFACE_INTERNAL("bmc_1200in1", NES_BMC_1200IN1) - SLOT_INTERFACE_INTERNAL("bmc_gold150", NES_BMC_GOLD150) // mapper 235 with 2M PRG - SLOT_INTERFACE_INTERNAL("bmc_gold260", NES_BMC_GOLD260) // mapper 235 with 4M PRG - SLOT_INTERFACE_INTERNAL("bmc_power255", NES_BMC_CH001) // mapper 63? - SLOT_INTERFACE_INTERNAL("bmc_s22games", NES_BMC_SUPER22) // mapper 233 - SLOT_INTERFACE_INTERNAL("bmc_reset4", NES_BMC_4IN1RESET) // mapper 60 with 64k prg and 32k chr - SLOT_INTERFACE_INTERNAL("bmc_reset42", NES_BMC_42IN1RESET) // mapper 60? or 226? or 233? -// misc multigame cart MMC3 clone boards - SLOT_INTERFACE_INTERNAL("fk23c", NES_FK23C) - SLOT_INTERFACE_INTERNAL("fk23ca", NES_FK23CA) - SLOT_INTERFACE_INTERNAL("s24in1c03", NES_S24IN1SC03) - SLOT_INTERFACE_INTERNAL("bmc_15in1", NES_BMC_15IN1) - SLOT_INTERFACE_INTERNAL("bmc_sbig7in1", NES_BMC_SBIG7) - SLOT_INTERFACE_INTERNAL("bmc_hik8in1", NES_BMC_HIK8) - SLOT_INTERFACE_INTERNAL("bmc_hik4in1", NES_BMC_HIK4) - SLOT_INTERFACE_INTERNAL("bmc_mario7in1", NES_BMC_MARIO7IN1) - SLOT_INTERFACE_INTERNAL("bmc_gold7in1", NES_BMC_GOLD7IN1) - SLOT_INTERFACE_INTERNAL("bmc_gc6in1", NES_BMC_GC6IN1) - SLOT_INTERFACE_INTERNAL("bmc_411120c", NES_BMC_411120C) - SLOT_INTERFACE_INTERNAL("bmc_830118c", NES_BMC_830118C) - SLOT_INTERFACE_INTERNAL("pjoy84", NES_PJOY84) - SLOT_INTERFACE_INTERNAL("nocash_nochr", NES_NOCHR) - SLOT_INTERFACE_INTERNAL("nes_action53", NES_ACTION53) - SLOT_INTERFACE_INTERNAL("nes_2a03pur", NES_2A03PURITANS) -// other unsupported... - SLOT_INTERFACE_INTERNAL("ninjaryu", NES_NROM) // mapper 111 - UNSUPPORTED - SLOT_INTERFACE_INTERNAL("unl_dance", NES_NROM) // UNSUPPORTED - SLOT_INTERFACE_INTERNAL("onebus", NES_NROM) // UNSUPPORTED - SLOT_INTERFACE_INTERNAL("dance2k", NES_NROM) // UNSUPPORTED - SLOT_INTERFACE_INTERNAL("pec586", NES_NROM) // UNSUPPORTED -// are there dumps of games with these boards? - SLOT_INTERFACE_INTERNAL("bmc_hik_kof", NES_NROM) // mapper 251 - UNSUPPORTED - SLOT_INTERFACE_INTERNAL("bmc_13in1jy110", NES_NROM) // [mentioned in FCEUMM source - we need more info] - UNSUPPORTED - SLOT_INTERFACE_INTERNAL("bmc_gk_192", NES_NROM) // [mentioned in FCEUMM source - we need more info] - UNSUPPORTED - SLOT_INTERFACE_INTERNAL("konami_qtai", NES_NROM) // [mentioned in FCEUMM source - we need more info] - UNSUPPORTED - SLOT_INTERFACE_INTERNAL("unl_3d_block", NES_NROM) // [mentioned in FCEUMM source - we need more info] - UNSUPPORTED - SLOT_INTERFACE_INTERNAL("unl_c_n22m", NES_NROM) // [mentioned in FCEUMM source - we need more info] - UNSUPPORTED - SLOT_INTERFACE_INTERNAL("a9746", NES_NROM) // mapper 219 - UNSUPPORTED (no dump available) -// legacy boards for FFE copier mappers (are there images available to fix/improve emulation?) - SLOT_INTERFACE_INTERNAL("ffe3", NES_FFE3) - SLOT_INTERFACE_INTERNAL("ffe4", NES_FFE4) - SLOT_INTERFACE_INTERNAL("ffe8", NES_FFE8) - SLOT_INTERFACE_INTERNAL("test", NES_NROM) -// - SLOT_INTERFACE_INTERNAL("unknown", NES_NROM) // a few pirate dumps uses the wrong mapper... -SLOT_INTERFACE_END - -SLOT_INTERFACE_START(disksys_only) - // RAM expansion + Disk System add-on - SLOT_INTERFACE("disksys", NES_DISKSYS) -SLOT_INTERFACE_END diff --git a/src/devices/bus/nes/nes_carts.cpp b/src/devices/bus/nes/nes_carts.cpp new file mode 100644 index 00000000000..6acac2fc6e7 --- /dev/null +++ b/src/devices/bus/nes/nes_carts.cpp @@ -0,0 +1,366 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + NES carts + +**********************************************************************/ + +#include "nes_carts.h" + +SLOT_INTERFACE_START(nes_cart) +// HROM, NROM, RROM, SROM & STROM + SLOT_INTERFACE_INTERNAL("nrom", NES_NROM) +// Nintendo Family BASIC pcb (NROM + 2K or 4K WRAM) + SLOT_INTERFACE_INTERNAL("hvc_basic", NES_FCBASIC) +// Extended NROM-368 board (NROM with 46K PRG) + SLOT_INTERFACE_INTERNAL("nrom368", NES_NROM368) +// Game Genie + SLOT_INTERFACE_INTERNAL("nrom_gg", NES_GGENIE) +// UNROM/UOROM + SLOT_INTERFACE_INTERNAL("uxrom", NES_UXROM) + SLOT_INTERFACE_INTERNAL("unrom_cc", NES_UXROM_CC) +// CNROM + SLOT_INTERFACE_INTERNAL("cnrom", NES_CNROM) +// Bandai PT-554 (CNROM boards + special audio chip, used by Aerobics Studio) + SLOT_INTERFACE_INTERNAL("bandai_pt554", NES_BANDAI_PT554) +// CPROM + SLOT_INTERFACE_INTERNAL("cprom", NES_CPROM) +// AMROM, ANROM, AOROM + SLOT_INTERFACE_INTERNAL("axrom", NES_AXROM) +// PxROM + SLOT_INTERFACE_INTERNAL("pxrom", NES_PXROM) +// FxROM + SLOT_INTERFACE_INTERNAL("fxrom", NES_FXROM) +// BNROM + SLOT_INTERFACE_INTERNAL("bnrom", NES_BXROM) +// GNROM & MHROM + SLOT_INTERFACE_INTERNAL("gxrom", NES_GXROM) +// UN1ROM + SLOT_INTERFACE_INTERNAL("un1rom", NES_UN1ROM) +// SxROM + SLOT_INTERFACE_INTERNAL("sxrom", NES_SXROM) + SLOT_INTERFACE_INTERNAL("sorom", NES_SOROM) + SLOT_INTERFACE_INTERNAL("sxrom_a", NES_SXROM_A) // in MMC1-A PRG RAM is always enabled + SLOT_INTERFACE_INTERNAL("sorom_a", NES_SOROM_A) // in MMC1-A PRG RAM is always enabled +// TxROM + SLOT_INTERFACE_INTERNAL("txrom", NES_TXROM) +// HKROM + SLOT_INTERFACE_INTERNAL("hkrom", NES_HKROM) +// TQROM + SLOT_INTERFACE_INTERNAL("tqrom", NES_TQROM) +// TxSROM + SLOT_INTERFACE_INTERNAL("txsrom", NES_TXSROM) +// ExROM + SLOT_INTERFACE_INTERNAL("exrom", NES_EXROM) +// RAM expansion + Disk System add-on + SLOT_INTERFACE_INTERNAL("disksys", NES_DISKSYS) +// Nintendo Custom boards + SLOT_INTERFACE_INTERNAL("pal_zz", NES_ZZ_PCB) + SLOT_INTERFACE_INTERNAL("nes_qj", NES_QJ_PCB) + SLOT_INTERFACE_INTERNAL("nes_event", NES_EVENT) +// Discrete Components boards +// IC_74x139x74 + SLOT_INTERFACE_INTERNAL("discrete_74x139", NES_74X139X74) +// IC_74x377 + SLOT_INTERFACE_INTERNAL("discrete_74x377", NES_74X377) +// Discrete board IC_74x161x161x32 + SLOT_INTERFACE_INTERNAL("discrete_74x161", NES_74X161X161X32) +// Discrete board IC_74x161x138 + SLOT_INTERFACE_INTERNAL("bitcorp_dis", NES_74X161X138) +// Bandai boards + SLOT_INTERFACE_INTERNAL("lz93d50", NES_LZ93D50) + SLOT_INTERFACE_INTERNAL("lz93d50_ep1", NES_LZ93D50_24C01) + SLOT_INTERFACE_INTERNAL("lz93d50_ep2", NES_LZ93D50_24C02) + SLOT_INTERFACE_INTERNAL("fcg", NES_FCG) + SLOT_INTERFACE_INTERNAL("fjump2", NES_FJUMP2) + SLOT_INTERFACE_INTERNAL("datach", NES_DATACH) + SLOT_INTERFACE_INTERNAL("karastudio", NES_KARAOKESTUDIO) + SLOT_INTERFACE_INTERNAL("oekakids", NES_OEKAKIDS) +// Irem boards + SLOT_INTERFACE_INTERNAL("g101", NES_G101) + SLOT_INTERFACE_INTERNAL("lrog017", NES_LROG017) + SLOT_INTERFACE_INTERNAL("h3001", NES_H3001) + SLOT_INTERFACE_INTERNAL("holydivr", NES_HOLYDIVR) + SLOT_INTERFACE_INTERNAL("tam_s1", NES_TAM_S1) +// Jaleco boards + SLOT_INTERFACE_INTERNAL("jf11", NES_JF11) + SLOT_INTERFACE_INTERNAL("jf13", NES_JF13) + SLOT_INTERFACE_INTERNAL("jf16", NES_JF16) + SLOT_INTERFACE_INTERNAL("jf17", NES_JF17) + SLOT_INTERFACE_INTERNAL("jf17pcm", NES_JF17_ADPCM) + SLOT_INTERFACE_INTERNAL("jf19", NES_JF19) + SLOT_INTERFACE_INTERNAL("jf19pcm", NES_JF19_ADPCM) + SLOT_INTERFACE_INTERNAL("ss88006", NES_SS88006) + SLOT_INTERFACE_INTERNAL("jf23", NES_JF23) + SLOT_INTERFACE_INTERNAL("jf24", NES_JF24) + SLOT_INTERFACE_INTERNAL("jf29", NES_JF29) + SLOT_INTERFACE_INTERNAL("jf33", NES_JF33) +// Konami boards + SLOT_INTERFACE_INTERNAL("vrc1", NES_VRC1) + SLOT_INTERFACE_INTERNAL("vrc2", NES_VRC2) + SLOT_INTERFACE_INTERNAL("vrc3", NES_VRC3) + SLOT_INTERFACE_INTERNAL("vrc4", NES_VRC4) + SLOT_INTERFACE_INTERNAL("vrc6", NES_VRC6) + SLOT_INTERFACE_INTERNAL("vrc7", NES_VRC7) +// Namcot boards + SLOT_INTERFACE_INTERNAL("namcot_163", NES_NAMCOT163) + SLOT_INTERFACE_INTERNAL("namcot_175", NES_NAMCOT175) + SLOT_INTERFACE_INTERNAL("namcot_340", NES_NAMCOT340) + SLOT_INTERFACE_INTERNAL("namcot_3433", NES_NAMCOT3433) // DxROM is a Nintendo board for US versions of the 3433/3443 games + SLOT_INTERFACE_INTERNAL("namcot_3425", NES_NAMCOT3425) + SLOT_INTERFACE_INTERNAL("namcot_3446", NES_NAMCOT3446) +// Sunsoft boards + SLOT_INTERFACE_INTERNAL("sunsoft1", NES_SUNSOFT_1) + SLOT_INTERFACE_INTERNAL("sunsoft2", NES_SUNSOFT_2) + SLOT_INTERFACE_INTERNAL("sunsoft3", NES_SUNSOFT_3) + SLOT_INTERFACE_INTERNAL("sunsoft4", NES_SUNSOFT_4) + SLOT_INTERFACE_INTERNAL("sunsoft_dcs", NES_SUNSOFT_DCS) + SLOT_INTERFACE_INTERNAL("sunsoft_fme7", NES_SUNSOFT_FME7) // JxROM is a Nintendo board for US versions of the Sunsoft FME7 games + SLOT_INTERFACE_INTERNAL("sunsoft5a", NES_SUNSOFT_5) + SLOT_INTERFACE_INTERNAL("sunsoft5b", NES_SUNSOFT_5) +// Taito boards + SLOT_INTERFACE_INTERNAL("tc0190fmc", NES_TC0190FMC) + SLOT_INTERFACE_INTERNAL("tc0190fmcp", NES_TC0190FMC_PAL16R4) + SLOT_INTERFACE_INTERNAL("tc0350fmr", NES_TC0190FMC) + SLOT_INTERFACE_INTERNAL("x1_005", NES_X1_005) // two variants exist, depending on pin17 & pin31 connections + SLOT_INTERFACE_INTERNAL("x1_017", NES_X1_017) +// Misc pirate boards (by AVE, Camerica, C&E, Nanjing, NTDEC, JY Company, Sachen, Tengen, TXC, Waixing, Henggendianzi, etc.) + SLOT_INTERFACE_INTERNAL("nina001", NES_NINA001) + SLOT_INTERFACE_INTERNAL("nina006", NES_NINA006) + SLOT_INTERFACE_INTERNAL("bf9093", NES_BF9093) + SLOT_INTERFACE_INTERNAL("bf9096", NES_BF9096) + SLOT_INTERFACE_INTERNAL("goldenfive", NES_GOLDEN5) + SLOT_INTERFACE_INTERNAL("ade", NES_ALADDIN) + SLOT_INTERFACE_INTERNAL("cne_decathl", NES_CNE_DECATHL) + SLOT_INTERFACE_INTERNAL("cne_fsb", NES_CNE_FSB) + SLOT_INTERFACE_INTERNAL("cne_shlz", NES_CNE_SHLZ) + SLOT_INTERFACE_INTERNAL("nanjing", NES_NANJING) // mapper 163 + SLOT_INTERFACE_INTERNAL("ntdec_asder", NES_NTDEC_ASDER) // mapper 112 + SLOT_INTERFACE_INTERNAL("ntdec_fh", NES_NTDEC_FH) // mapper 193 + SLOT_INTERFACE_INTERNAL("jyc_a", NES_JY_TYPEA) // mapper 90 + SLOT_INTERFACE_INTERNAL("jyc_b", NES_JY_TYPEB) // mapper 211 + SLOT_INTERFACE_INTERNAL("jyc_c", NES_JY_TYPEC) // mapper 209 + SLOT_INTERFACE_INTERNAL("sa009", NES_SACHEN_SA009) + SLOT_INTERFACE_INTERNAL("sa0036", NES_SACHEN_SA0036) + SLOT_INTERFACE_INTERNAL("sa0037", NES_SACHEN_SA0037) + SLOT_INTERFACE_INTERNAL("sa72007", NES_SACHEN_SA72007) + SLOT_INTERFACE_INTERNAL("sa72008", NES_SACHEN_SA72008) + SLOT_INTERFACE_INTERNAL("tca01", NES_SACHEN_TCA01) + SLOT_INTERFACE_INTERNAL("s8259a", NES_SACHEN_8259A) + SLOT_INTERFACE_INTERNAL("s8259b", NES_SACHEN_8259B) + SLOT_INTERFACE_INTERNAL("s8259c", NES_SACHEN_8259C) + SLOT_INTERFACE_INTERNAL("s8259d", NES_SACHEN_8259D) + SLOT_INTERFACE_INTERNAL("s74x374", NES_SACHEN_74X374) + SLOT_INTERFACE_INTERNAL("s74x374a", NES_SACHEN_74X374_ALT) /* FIXME: Made up boards some different handling */ + SLOT_INTERFACE_INTERNAL("tcu01", NES_SACHEN_TCU01) + SLOT_INTERFACE_INTERNAL("tcu02", NES_SACHEN_TCU02) + SLOT_INTERFACE_INTERNAL("tengen_800008", NES_TENGEN_800008) /* FIXME: Is this the same as CNROM? */ + SLOT_INTERFACE_INTERNAL("tengen_800032", NES_TENGEN_800032) + SLOT_INTERFACE_INTERNAL("tengen_800037", NES_TENGEN_800037) + SLOT_INTERFACE_INTERNAL("txc_22211", NES_TXC_22211) + SLOT_INTERFACE_INTERNAL("txc_dumarc", NES_TXC_DUMARACING) + SLOT_INTERFACE_INTERNAL("txc_mjblock", NES_TXC_MJBLOCK) + SLOT_INTERFACE_INTERNAL("txc_strikew", NES_TXC_STRIKEW) + SLOT_INTERFACE_INTERNAL("txc_commandos", NES_TXC_COMMANDOS) + SLOT_INTERFACE_INTERNAL("waixing_a", NES_WAIXING_A) + SLOT_INTERFACE_INTERNAL("waixing_a1", NES_WAIXING_A1) /* FIXME: Made up boards the different CHRRAM banks (see Ji Jia Zhan Shi) */ + SLOT_INTERFACE_INTERNAL("waixing_b", NES_WAIXING_B) + SLOT_INTERFACE_INTERNAL("waixing_c", NES_WAIXING_C) + SLOT_INTERFACE_INTERNAL("waixing_d", NES_WAIXING_D) + SLOT_INTERFACE_INTERNAL("waixing_e", NES_WAIXING_E) + SLOT_INTERFACE_INTERNAL("waixing_f", NES_WAIXING_F) + SLOT_INTERFACE_INTERNAL("waixing_g", NES_WAIXING_G) + SLOT_INTERFACE_INTERNAL("waixing_h", NES_WAIXING_H) + SLOT_INTERFACE_INTERNAL("waixing_h1", NES_WAIXING_H1) /* FIXME: Made up boards the different WRAM protect banks (see Shen Mi Jin San Jiao) */ + SLOT_INTERFACE_INTERNAL("waixing_i", NES_WAIXING_I) + SLOT_INTERFACE_INTERNAL("waixing_j", NES_WAIXING_J) + SLOT_INTERFACE_INTERNAL("waixing_sgz", NES_WAIXING_SGZ) + SLOT_INTERFACE_INTERNAL("waixing_sgzlz", NES_WAIXING_SGZLZ) + SLOT_INTERFACE_INTERNAL("waixing_sec", NES_WAIXING_SEC) + SLOT_INTERFACE_INTERNAL("waixing_ffv", NES_WAIXING_FFV) + SLOT_INTERFACE_INTERNAL("waixing_wxzs", NES_WAIXING_WXZS) + SLOT_INTERFACE_INTERNAL("waixing_wxzs2", NES_WAIXING_WXZS2) + SLOT_INTERFACE_INTERNAL("waixing_dq8", NES_WAIXING_DQ8) + SLOT_INTERFACE_INTERNAL("waixing_sh2", NES_WAIXING_SH2) + SLOT_INTERFACE_INTERNAL("fs304", NES_WAIXING_FS304) // used in Zelda 3 by Waixing + SLOT_INTERFACE_INTERNAL("cony", NES_CONY) + SLOT_INTERFACE_INTERNAL("yoko", NES_YOKO) + SLOT_INTERFACE_INTERNAL("hengg_srich", NES_HENGG_SRICH) + SLOT_INTERFACE_INTERNAL("hengg_xhzs", NES_HENGG_XHZS) + SLOT_INTERFACE_INTERNAL("hengg_shjy3", NES_HENGG_SHJY3) // mapper 253 + SLOT_INTERFACE_INTERNAL("hes", NES_HES) + SLOT_INTERFACE_INTERNAL("hosenkan", NES_HOSENKAN) + SLOT_INTERFACE_INTERNAL("ks7058", NES_KS7058) + SLOT_INTERFACE_INTERNAL("ks202", NES_KS202) // mapper 56 + SLOT_INTERFACE_INTERNAL("ks7022", NES_KS7022)// mapper 175 + SLOT_INTERFACE_INTERNAL("ks7017", NES_KS7017) + SLOT_INTERFACE_INTERNAL("ks7032", NES_KS7032) // mapper 142 + SLOT_INTERFACE_INTERNAL("ks7012", NES_KS7012) // used in Zanac (FDS Conversion) + SLOT_INTERFACE_INTERNAL("ks7013b", NES_KS7013B) // used in Highway Star (FDS Conversion) + SLOT_INTERFACE_INTERNAL("ks7031", NES_KS7031) // used in Dracula II (FDS Conversion) + SLOT_INTERFACE_INTERNAL("gs2015", NES_GS2015) + SLOT_INTERFACE_INTERNAL("gs2004", NES_GS2004) + SLOT_INTERFACE_INTERNAL("gs2013", NES_GS2013) + SLOT_INTERFACE_INTERNAL("tf9in1", NES_TF9IN1) + SLOT_INTERFACE_INTERNAL("3dblock", NES_3DBLOCK) // NROM + IRQ? + SLOT_INTERFACE_INTERNAL("racermate", NES_RACERMATE) // mapper 168 + SLOT_INTERFACE_INTERNAL("agci_50282", NES_AGCI_50282) + SLOT_INTERFACE_INTERNAL("dreamtech01", NES_DREAMTECH01) + SLOT_INTERFACE_INTERNAL("fukutake", NES_FUKUTAKE) + SLOT_INTERFACE_INTERNAL("futuremedia", NES_FUTUREMEDIA) + SLOT_INTERFACE_INTERNAL("magicseries", NES_MAGSERIES) + SLOT_INTERFACE_INTERNAL("daou_306", NES_DAOU306) + SLOT_INTERFACE_INTERNAL("subor0", NES_SUBOR0) + SLOT_INTERFACE_INTERNAL("subor1", NES_SUBOR1) + SLOT_INTERFACE_INTERNAL("cc21", NES_CC21) + SLOT_INTERFACE_INTERNAL("xiaozy", NES_XIAOZY) + SLOT_INTERFACE_INTERNAL("edu2k", NES_EDU2K) + SLOT_INTERFACE_INTERNAL("t230", NES_T230) + SLOT_INTERFACE_INTERNAL("mk2", NES_MK2) + SLOT_INTERFACE_INTERNAL("unl_whero", NES_WHERO) // mapper 27 + SLOT_INTERFACE_INTERNAL("unl_43272", NES_43272) // used in Gaau Hok Gwong Cheung + SLOT_INTERFACE_INTERNAL("tf1201", NES_TF1201) + SLOT_INTERFACE_INTERNAL("unl_cfight", NES_CITYFIGHT) // used by City Fighter IV +// misc bootleg boards + SLOT_INTERFACE_INTERNAL("ax5705", NES_AX5705) + SLOT_INTERFACE_INTERNAL("sc127", NES_SC127) + SLOT_INTERFACE_INTERNAL("mariobaby", NES_MARIOBABY) + SLOT_INTERFACE_INTERNAL("asnicol", NES_ASN) + SLOT_INTERFACE_INTERNAL("smb3pirate", NES_SMB3PIRATE) + SLOT_INTERFACE_INTERNAL("btl_dninja", NES_BTL_DNINJA) + SLOT_INTERFACE_INTERNAL("whirl2706", NES_WHIRLWIND_2706) + SLOT_INTERFACE_INTERNAL("smb2j", NES_SMB2J) + SLOT_INTERFACE_INTERNAL("smb2ja", NES_SMB2JA) + SLOT_INTERFACE_INTERNAL("smb2jb", NES_SMB2JB) + SLOT_INTERFACE_INTERNAL("09034a", NES_09034A) + SLOT_INTERFACE_INTERNAL("tobidase", NES_TOBIDASE) // mapper 120 + SLOT_INTERFACE_INTERNAL("mmalee2", NES_MMALEE) // mapper 55? + SLOT_INTERFACE_INTERNAL("unl_2708", NES_2708) // mapper 103 + SLOT_INTERFACE_INTERNAL("unl_lh32", NES_LH32) // used by Monty no Doki Doki Daidassou FDS conversion + SLOT_INTERFACE_INTERNAL("unl_lh10", NES_LH10) // used in Fuuun Shaolin Kyo (FDS Conversion) + SLOT_INTERFACE_INTERNAL("unl_lh53", NES_LH53) // used in Nazo no Murasamejou (FDS Conversion) + SLOT_INTERFACE_INTERNAL("unl_ac08", NES_AC08) // used by Green Beret FDS conversion + SLOT_INTERFACE_INTERNAL("unl_bb", NES_UNL_BB) // used by a few FDS conversions + SLOT_INTERFACE_INTERNAL("sgpipe", NES_SHUIGUAN) // mapper 183 +// misc MMC3 clone boards + SLOT_INTERFACE_INTERNAL("dbz5", NES_REX_DBZ5) + SLOT_INTERFACE_INTERNAL("sl1632", NES_REX_SL1632) + SLOT_INTERFACE_INTERNAL("somari", NES_SOMARI) // mapper 116 + SLOT_INTERFACE_INTERNAL("nitra", NES_NITRA) + SLOT_INTERFACE_INTERNAL("ks7057", NES_KS7057) // mapper 196 alt (for Street Fighter VI / Fight Street VI) + SLOT_INTERFACE_INTERNAL("sbros11", NES_SBROS11) + SLOT_INTERFACE_INTERNAL("unl_malisb", NES_MALISB) // used by Super Mali Splash Bomb + SLOT_INTERFACE_INTERNAL("family4646", NES_FAMILY4646) + SLOT_INTERFACE_INTERNAL("pikay2k", NES_PIKAY2K) // mapper 254 + SLOT_INTERFACE_INTERNAL("8237", NES_8237) + SLOT_INTERFACE_INTERNAL("8237a", NES_NROM) // UNSUPPORTED + SLOT_INTERFACE_INTERNAL("sg_lionk", NES_SG_LIONK) + SLOT_INTERFACE_INTERNAL("sg_boog", NES_SG_BOOG) + SLOT_INTERFACE_INTERNAL("kasing", NES_KASING) + SLOT_INTERFACE_INTERNAL("kay", NES_KAY) + SLOT_INTERFACE_INTERNAL("h2288", NES_H2288) + SLOT_INTERFACE_INTERNAL("unl_6035052", NES_6035052) // mapper 238? + SLOT_INTERFACE_INTERNAL("txc_tw", NES_TXC_TW) + SLOT_INTERFACE_INTERNAL("kof97", NES_KOF97) + SLOT_INTERFACE_INTERNAL("kof96", NES_KOF96) + SLOT_INTERFACE_INTERNAL("sfight3", NES_SF3) + SLOT_INTERFACE_INTERNAL("gouder", NES_GOUDER) + SLOT_INTERFACE_INTERNAL("sa9602b", NES_SA9602B) + SLOT_INTERFACE_INTERNAL("unl_shero", NES_SACHEN_SHERO) +// misc multigame cart boards + SLOT_INTERFACE_INTERNAL("benshieng", NES_BENSHIENG) + SLOT_INTERFACE_INTERNAL("action52", NES_ACTION52) + SLOT_INTERFACE_INTERNAL("caltron6in1", NES_CALTRON6IN1) + SLOT_INTERFACE_INTERNAL("maxi15", NES_MAXI15) // mapper 234 + SLOT_INTERFACE_INTERNAL("rumblestation", NES_RUMBLESTATION) // mapper 46 + SLOT_INTERFACE_INTERNAL("svision16", NES_SVISION16) // mapper 53 + SLOT_INTERFACE_INTERNAL("n625092", NES_N625092) + SLOT_INTERFACE_INTERNAL("a65as", NES_A65AS) + SLOT_INTERFACE_INTERNAL("t262", NES_T262) + SLOT_INTERFACE_INTERNAL("novel1", NES_NOVEL1) + SLOT_INTERFACE_INTERNAL("novel2", NES_NOVEL2) // mapper 213... same as BMC-NOVELDIAMOND9999999IN1 board? + SLOT_INTERFACE_INTERNAL("studyngame", NES_STUDYNGAME) // mapper 39 + SLOT_INTERFACE_INTERNAL("sgun20in1", NES_SUPERGUN20IN1) + SLOT_INTERFACE_INTERNAL("bmc_vt5201", NES_VT5201) // mapper 60 otherwise + SLOT_INTERFACE_INTERNAL("bmc_d1038", NES_VT5201) // mapper 60? + SLOT_INTERFACE_INTERNAL("810544c", NES_810544C) + SLOT_INTERFACE_INTERNAL("ntd03", NES_NTD03) + SLOT_INTERFACE_INTERNAL("bmc_gb63", NES_BMC_GB63) + SLOT_INTERFACE_INTERNAL("bmc_gka", NES_BMC_GKA) + SLOT_INTERFACE_INTERNAL("bmc_gkb", NES_BMC_GKB) + SLOT_INTERFACE_INTERNAL("bmc_ws", NES_BMC_WS) + SLOT_INTERFACE_INTERNAL("bmc_g146", NES_BMC_G146) + SLOT_INTERFACE_INTERNAL("bmc_11160", NES_BMC_11160) + SLOT_INTERFACE_INTERNAL("bmc_8157", NES_BMC_8157) + SLOT_INTERFACE_INTERNAL("bmc_hik300", NES_BMC_HIK300) + SLOT_INTERFACE_INTERNAL("bmc_s700", NES_BMC_S700) + SLOT_INTERFACE_INTERNAL("bmc_ball11", NES_BMC_BALL11) + SLOT_INTERFACE_INTERNAL("bmc_22games", NES_BMC_22GAMES) + SLOT_INTERFACE_INTERNAL("bmc_64y2k", NES_BMC_64Y2K) + SLOT_INTERFACE_INTERNAL("bmc_12in1", NES_BMC_12IN1) + SLOT_INTERFACE_INTERNAL("bmc_20in1", NES_BMC_20IN1) + SLOT_INTERFACE_INTERNAL("bmc_21in1", NES_BMC_21IN1) + SLOT_INTERFACE_INTERNAL("bmc_31in1", NES_BMC_31IN1) + SLOT_INTERFACE_INTERNAL("bmc_35in1", NES_BMC_35IN1) + SLOT_INTERFACE_INTERNAL("bmc_36in1", NES_BMC_36IN1) + SLOT_INTERFACE_INTERNAL("bmc_64in1", NES_BMC_64IN1) + SLOT_INTERFACE_INTERNAL("bmc_70in1", NES_BMC_70IN1) // mapper 236? + SLOT_INTERFACE_INTERNAL("bmc_72in1", NES_BMC_72IN1) + SLOT_INTERFACE_INTERNAL("bmc_76in1", NES_BMC_76IN1) + SLOT_INTERFACE_INTERNAL("bmc_s42in1", NES_BMC_76IN1) + SLOT_INTERFACE_INTERNAL("bmc_110in1", NES_BMC_110IN1) + SLOT_INTERFACE_INTERNAL("bmc_150in1", NES_BMC_150IN1) + SLOT_INTERFACE_INTERNAL("bmc_190in1", NES_BMC_190IN1) + SLOT_INTERFACE_INTERNAL("bmc_800in1", NES_BMC_800IN1) // mapper 236? + SLOT_INTERFACE_INTERNAL("bmc_1200in1", NES_BMC_1200IN1) + SLOT_INTERFACE_INTERNAL("bmc_gold150", NES_BMC_GOLD150) // mapper 235 with 2M PRG + SLOT_INTERFACE_INTERNAL("bmc_gold260", NES_BMC_GOLD260) // mapper 235 with 4M PRG + SLOT_INTERFACE_INTERNAL("bmc_power255", NES_BMC_CH001) // mapper 63? + SLOT_INTERFACE_INTERNAL("bmc_s22games", NES_BMC_SUPER22) // mapper 233 + SLOT_INTERFACE_INTERNAL("bmc_reset4", NES_BMC_4IN1RESET) // mapper 60 with 64k prg and 32k chr + SLOT_INTERFACE_INTERNAL("bmc_reset42", NES_BMC_42IN1RESET) // mapper 60? or 226? or 233? +// misc multigame cart MMC3 clone boards + SLOT_INTERFACE_INTERNAL("fk23c", NES_FK23C) + SLOT_INTERFACE_INTERNAL("fk23ca", NES_FK23CA) + SLOT_INTERFACE_INTERNAL("s24in1c03", NES_S24IN1SC03) + SLOT_INTERFACE_INTERNAL("bmc_15in1", NES_BMC_15IN1) + SLOT_INTERFACE_INTERNAL("bmc_sbig7in1", NES_BMC_SBIG7) + SLOT_INTERFACE_INTERNAL("bmc_hik8in1", NES_BMC_HIK8) + SLOT_INTERFACE_INTERNAL("bmc_hik4in1", NES_BMC_HIK4) + SLOT_INTERFACE_INTERNAL("bmc_mario7in1", NES_BMC_MARIO7IN1) + SLOT_INTERFACE_INTERNAL("bmc_gold7in1", NES_BMC_GOLD7IN1) + SLOT_INTERFACE_INTERNAL("bmc_gc6in1", NES_BMC_GC6IN1) + SLOT_INTERFACE_INTERNAL("bmc_411120c", NES_BMC_411120C) + SLOT_INTERFACE_INTERNAL("bmc_830118c", NES_BMC_830118C) + SLOT_INTERFACE_INTERNAL("pjoy84", NES_PJOY84) + SLOT_INTERFACE_INTERNAL("nocash_nochr", NES_NOCHR) + SLOT_INTERFACE_INTERNAL("nes_action53", NES_ACTION53) + SLOT_INTERFACE_INTERNAL("nes_2a03pur", NES_2A03PURITANS) +// other unsupported... + SLOT_INTERFACE_INTERNAL("ninjaryu", NES_NROM) // mapper 111 - UNSUPPORTED + SLOT_INTERFACE_INTERNAL("unl_dance", NES_NROM) // UNSUPPORTED + SLOT_INTERFACE_INTERNAL("onebus", NES_NROM) // UNSUPPORTED + SLOT_INTERFACE_INTERNAL("dance2k", NES_NROM) // UNSUPPORTED + SLOT_INTERFACE_INTERNAL("pec586", NES_NROM) // UNSUPPORTED +// are there dumps of games with these boards? + SLOT_INTERFACE_INTERNAL("bmc_hik_kof", NES_NROM) // mapper 251 - UNSUPPORTED + SLOT_INTERFACE_INTERNAL("bmc_13in1jy110", NES_NROM) // [mentioned in FCEUMM source - we need more info] - UNSUPPORTED + SLOT_INTERFACE_INTERNAL("bmc_gk_192", NES_NROM) // [mentioned in FCEUMM source - we need more info] - UNSUPPORTED + SLOT_INTERFACE_INTERNAL("konami_qtai", NES_NROM) // [mentioned in FCEUMM source - we need more info] - UNSUPPORTED + SLOT_INTERFACE_INTERNAL("unl_3d_block", NES_NROM) // [mentioned in FCEUMM source - we need more info] - UNSUPPORTED + SLOT_INTERFACE_INTERNAL("unl_c_n22m", NES_NROM) // [mentioned in FCEUMM source - we need more info] - UNSUPPORTED + SLOT_INTERFACE_INTERNAL("a9746", NES_NROM) // mapper 219 - UNSUPPORTED (no dump available) +// legacy boards for FFE copier mappers (are there images available to fix/improve emulation?) + SLOT_INTERFACE_INTERNAL("ffe3", NES_FFE3) + SLOT_INTERFACE_INTERNAL("ffe4", NES_FFE4) + SLOT_INTERFACE_INTERNAL("ffe8", NES_FFE8) + SLOT_INTERFACE_INTERNAL("test", NES_NROM) +// + SLOT_INTERFACE_INTERNAL("unknown", NES_NROM) // a few pirate dumps uses the wrong mapper... +SLOT_INTERFACE_END + +SLOT_INTERFACE_START(disksys_only) + // RAM expansion + Disk System add-on + SLOT_INTERFACE("disksys", NES_DISKSYS) +SLOT_INTERFACE_END diff --git a/src/devices/bus/nes/nes_slot.c b/src/devices/bus/nes/nes_slot.c deleted file mode 100644 index ec1b1f5f4af..00000000000 --- a/src/devices/bus/nes/nes_slot.c +++ /dev/null @@ -1,1053 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Fabio Priuli -/*********************************************************************************************************** - - - Nintendo NES/FC cart emulation - (through slot devices) - - The driver exposes address ranges - 0x4100-0x5fff to read_l/write_l - 0x6000-0x7fff to read_m/write_m (here are *usually* installed NVRAM & WRAM, if any) - 0x8000-0xffff to write_h (reads are directed to 4 x 8K PRG banks) - Default implementations of these handlers are available here, to be rewritten by PCB-specific ones when needed. - - Additional handlers are available, but have to be manually installed at machine_start - * read_ex/write_ex for address range 0x4020-0x40ff - * read_h for address range 0x8000-0xffff when a cart does some protection or address scramble before reading ROM - - PPU exposes address ranges - 0x0000-0x1fff to chr_r/chr_w - 0x2000-0x3eff to nt_r/nt_w - Default implementations of these handlers are available here, to be rewritten by PCB-specific ones when needed. - - Plus a few of latch functions are available: ppu_latch (see MMC2), hblank_irq and scanline_irq (see e.g. MMC3), - but these might be subject to future changes when the PPU is revisited. - - Notes: - - Differently from later systems (like SNES or MD), it is uncommon to find PRG ROMs of NES games which are not a - power of 2K, so we do not perform any mirroring by default. - A bunch of pcb types, though, come with 1.5MB of PRG (some Waixing translations) or with multiple PRG chips - having peculiar size (32K + 16K, 32K + 8K, 32K + 2K). Hence, if such a configuration is detected, we provide - a m_prg_bank_map array to handle internally PRG mirroring up to the next power of 2K, as long as the size is - a multiple of 8K (i.e. the unit chunk for standard PRG). - For the case of PRG chips which are not-multiple of 8K (e.g. UNL-MARIO2-MALEE pcb), the handling has to be - handled in the pcb-specific code! - - Our open bus emulation is very sketchy, by simply returning the higher 8bits of the accessed address. This seems - enough for most games (only two sets have issues with this). A slightly better implementation is almost ready - to fix these two remaining cases, but I plan to revisit the whole implementation in an accurate way at a later - stage - - Bus conflict is implemented based on latest tests by Blargg. There is some uncertainty about AxROM behavior - (some AOROM pcbs suffers from bus conflict, some do not... since no AOROM game is known to glitch due to lack - of bus conflict it seems safe to emulate the board without bus conflict, but eventually it would be good to - differentiate the real variants) - - - Many information about the mappers/pcbs come from the wonderful doc written by Disch. - Current info (when used) are based on v0.6.1 of his docs. - You can find the latest version of the doc at http://www.romhacking.net/docs/362/ - - A lot of details have been based on the researches carried on at NesDev forums (by Blargg, Quietust and many more) - and collected on the NesDev Wiki http://wiki.nesdev.com/ - - Particular thanks go to - - Martin Freij for his work on NEStopia - - Cah4e3 for his efforts on FCEUMM and the reverse engineering of pirate boards - - BootGod, lidnariq and naruko for the PCB tests which made possible - - - ***********************************************************************************************************/ - -/***************************************************************************************** - - A few Mappers suffer of hardware conflict: original dumpers have used the same mapper number for more than - a kind of boards. In these cases (and only in these cases) we exploit nes.hsi to set up accordingly - emulation. Games which requires this hack are the following: - * 032 - Major League needs hardwired mirroring (missing windows and glitched field in top view, otherwise) - * 034 - Impossible Mission II is not like BxROM games (it writes to 0x7ffd-0x7fff, instead of 0x8000). It is still - unplayable though (see above) - * 071 - Fire Hawk is different from other Camerica games (no hardwired mirroring). Without crc_hack no helicopter graphics - * 078 - Cosmo Carrier needs a different mirroring than Holy Diver - * 113 - HES 6-in-1 requires mirroring (check Bookyman playfield), while other games break with this (check AV Soccer) - * 153 - Famicom Jump II uses a different board (or the same in a very different way) - * 242 - DQ8 has no mirroring (missing graphics is due to other reasons though) - - crc_hacks have been added also to handle a few wiring settings which would require submappers: - * CHR protection pins for mapper 185 - * VRC-2, VRC-4 and VRC-6 line wiring - - Remember that the MMC # does not equal the mapper #. In particular, Mapper 4 is - in fact MMC3, Mapper 9 is MMC2 and Mapper 10 is MMC4. Makes perfect sense, right? - - ****************************************************************************************/ - - -#include "emu.h" -#include "hashfile.h" -#include "nes_slot.h" - -#define NES_BATTERY_SIZE 0x2000 - - -//************************************************************************** -// GLOBAL VARIABLES -//************************************************************************** - -const device_type NES_CART_SLOT = &device_creator; - - -//************************************************************************** -// NES cartridges Interface -//************************************************************************** - -//------------------------------------------------- -// device_nes_cart_interface - constructor -//------------------------------------------------- - -device_nes_cart_interface::device_nes_cart_interface(const machine_config &mconfig, device_t &device) - : device_slot_card_interface(mconfig, device), - m_prg(NULL), - m_vrom(NULL), - m_ciram(NULL), - m_prg_size(0), - m_vrom_size(0), - m_mapper_sram(NULL), - m_mapper_sram_size(0), - m_ce_mask(0), - m_ce_state(0), - m_vrc_ls_prg_a(0), - m_vrc_ls_prg_b(0), - m_vrc_ls_chr(0), - m_mirroring(PPU_MIRROR_NONE), - m_pcb_ctrl_mirror(FALSE), - m_four_screen_vram(FALSE), - m_has_trainer(FALSE), - m_x1_005_alt_mirroring(FALSE), - m_bus_conflict(TRUE), - m_open_bus(0), - m_prg_chunks(0), - m_prg_mask(0xffff), - m_chr_source(CHRRAM), - m_vrom_chunks(0), - m_vram_chunks(0) -{ -} - - -//------------------------------------------------- -// ~device_nes_cart_interface - destructor -//------------------------------------------------- - -device_nes_cart_interface::~device_nes_cart_interface() -{ -} - -//------------------------------------------------- -// pointer allocators -//------------------------------------------------- - -void device_nes_cart_interface::prg_alloc(size_t size, const char *tag) -{ - if (m_prg == NULL) - { - m_prg = device().machine().memory().region_alloc(std::string(tag).append(NESSLOT_PRGROM_REGION_TAG).c_str(), size, 1, ENDIANNESS_LITTLE)->base(); - m_prg_size = size; - m_prg_chunks = size / 0x4000; - if (size % 0x2000) - { - // A few pirate carts have PRG made of 32K + 2K or some weird similar config - // in this case we treat the banking as if this 'extra' PRG is not present and - // the pcb code has to handle it by accessing directly m_prg! - printf("Warning! The loaded PRG has size not a multiple of 8KB (0x%X)\n", (UINT32)size); - m_prg_chunks--; - } - - m_prg_mask = ((m_prg_chunks << 1) - 1); - -// printf("first mask %x!\n", m_prg_mask); - if ((m_prg_chunks << 1) & m_prg_mask) - { - int mask_bits = 0, temp = (m_prg_chunks << 1), mapsize; - // contrary to what happens with later systems, like e.g. SNES or MD, - // only half a dozen of NES carts have PRG which is not a power of 2 - // so we use this bank_map only as an exception -// printf("uneven rom!\n"); - - // 1. redefine mask as (next power of 2)-1 - for (; temp; ) - { - mask_bits++; - temp >>= 1; - } - m_prg_mask = (1 << mask_bits) - 1; -// printf("new mask %x!\n", m_prg_mask); - mapsize = (1 << mask_bits)/2; - - // 2. create a bank_map for banks in the range mask/2 -> mask - m_prg_bank_map.resize(mapsize); - - // 3. fill the bank_map accounting for mirrors - int j; - for (j = mapsize; j < (m_prg_chunks << 1); j++) - m_prg_bank_map[j - mapsize] = j; - - while (j % mapsize) - { - int k = 0, repeat_banks; - while ((j % (mapsize >> k)) && k < mask_bits) - k++; - repeat_banks = j % (mapsize >> (k - 1)); - for (int l = 0; l < repeat_banks; l++) - m_prg_bank_map[(j - mapsize) + l] = m_prg_bank_map[(j - mapsize) + l - repeat_banks]; - j += repeat_banks; - } - - // check bank map! -// for (int i = 0; i < mapsize; i++) -// { -// printf("bank %3d = %3d\t", i, m_prg_bank_map[i]); -// if ((i%8) == 7) -// printf("\n"); -// } - } - } -} - -void device_nes_cart_interface::vrom_alloc(size_t size, const char *tag) -{ - if (m_vrom == NULL) - { - std::string tempstring(tag); - tempstring.append(NESSLOT_CHRROM_REGION_TAG); - m_vrom = device().machine().memory().region_alloc(tempstring.c_str(), size, 1, ENDIANNESS_LITTLE)->base(); - m_vrom_size = size; - m_vrom_chunks = size / 0x2000; - } -} - -void device_nes_cart_interface::prgram_alloc(size_t size) -{ - m_prgram.resize(size); -} - -void device_nes_cart_interface::vram_alloc(size_t size) -{ - m_vram.resize(size); - m_vram_chunks = size / 0x2000; -} - -void device_nes_cart_interface::battery_alloc(size_t size) -{ - m_battery.resize(size); -} - - -//------------------------------------------------- -// PRG helpers -//------------------------------------------------- - -inline int device_nes_cart_interface::prg_8k_bank_num(int bank_8k) -{ - if (m_prg_mask == ((m_prg_chunks << 1) - 1)) - return bank_8k & m_prg_mask; - - // only a few pirate games (less than a dozen) have PRG which is not power of 2 - // so we treat it here separately, rather than forcing all games to use m_prg_bank_map - - // case 1: if we are accessing a bank before the end of the image, just return that bank - if (bank_8k < ((m_prg_chunks << 1) - 1)) - return bank_8k; - - // case 2: otherwise return a mirror using the bank_map! -// UINT8 temp = bank_8k; - bank_8k &= m_prg_mask; - bank_8k -= (m_prg_mask/2 + 1); -// printf("bank: accessed %x (top: %x), returned %x\n", temp, (m_prg_chunks << 1) - 1, m_prg_bank_map[bank_8k]); - return m_prg_bank_map[bank_8k]; -} - -inline void device_nes_cart_interface::update_prg_banks(int prg_bank_start, int prg_bank_end) -{ - for (int prg_bank = prg_bank_start; prg_bank <= prg_bank_end; prg_bank++) - { - assert(prg_bank >= 0); - assert(prg_bank < ARRAY_LENGTH(m_prg_bank)); - assert(prg_bank < ARRAY_LENGTH(m_prg_bank_mem)); - - m_prg_bank_mem[prg_bank]->set_entry(m_prg_bank[prg_bank]); - } -} - -void device_nes_cart_interface::prg32(int bank) -{ - /* if there is only 16k PRG, return */ - if (!(m_prg_chunks >> 1)) - return; - - /* assumes that bank references a 32k chunk */ - bank = prg_8k_bank_num(bank * 4); - - m_prg_bank[0] = bank + 0; - m_prg_bank[1] = bank + 1; - m_prg_bank[2] = bank + 2; - m_prg_bank[3] = bank + 3; - update_prg_banks(0, 3); -} - -void device_nes_cart_interface::prg16_89ab(int bank) -{ - /* assumes that bank references a 16k chunk */ - bank = prg_8k_bank_num(bank * 2); - - m_prg_bank[0] = bank + 0; - m_prg_bank[1] = bank + 1; - update_prg_banks(0, 1); -} - -void device_nes_cart_interface::prg16_cdef(int bank) -{ - /* assumes that bank references a 16k chunk */ - bank = prg_8k_bank_num(bank * 2); - - m_prg_bank[2] = bank + 0; - m_prg_bank[3] = bank + 1; - update_prg_banks(2, 3); -} - -void device_nes_cart_interface::prg8_89(int bank) -{ - /* assumes that bank references an 8k chunk */ - bank = prg_8k_bank_num(bank); - - m_prg_bank[0] = bank; - update_prg_banks(0, 0); -} - -void device_nes_cart_interface::prg8_ab(int bank) -{ - /* assumes that bank references an 8k chunk */ - bank = prg_8k_bank_num(bank); - - m_prg_bank[1] = bank; - update_prg_banks(1, 1); -} - -void device_nes_cart_interface::prg8_cd(int bank) -{ - /* assumes that bank references an 8k chunk */ - bank = prg_8k_bank_num(bank); - - m_prg_bank[2] = bank; - update_prg_banks(2, 2); -} - -void device_nes_cart_interface::prg8_ef(int bank) -{ - /* assumes that bank references an 8k chunk */ - bank = prg_8k_bank_num(bank); - - m_prg_bank[3] = bank; - update_prg_banks(3, 3); -} - -/* We also define an additional helper to map 8k PRG-ROM to one of the banks (passed as parameter) */ -void device_nes_cart_interface::prg8_x(int start, int bank) -{ - assert(start < 4); - - /* assumes that bank references an 8k chunk */ - bank = prg_8k_bank_num(bank); - - m_prg_bank[start] = bank; - update_prg_banks(start, start); -} - -//------------------------------------------------- -// CHR helpers -//------------------------------------------------- - -inline void device_nes_cart_interface::chr_sanity_check( int source ) -{ - if (source == CHRRAM && m_vram.empty()) - fatalerror("CHRRAM bankswitch with no VRAM\n"); - - if (source == CHRROM && m_vrom == NULL) - fatalerror("CHRROM bankswitch with no VROM\n"); -} - -void device_nes_cart_interface::chr8(int bank, int source) -{ - chr_sanity_check(source); - - if (source == CHRRAM) - { - bank &= (m_vram_chunks - 1); - for (int i = 0; i < 8; i++) - { - m_chr_src[i] = source; - m_chr_orig[i] = (bank * 0x2000) + (i * 0x400); // for save state uses! - m_chr_access[i] = &m_vram[m_chr_orig[i]]; - } - } - else - { - bank &= (m_vrom_chunks - 1); - for (int i = 0; i < 8; i++) - { - m_chr_src[i] = source; - m_chr_orig[i] = (bank * 0x2000) + (i * 0x400); // for save state uses! - m_chr_access[i] = &m_vrom[m_chr_orig[i]]; - } - } -} - -void device_nes_cart_interface::chr4_x(int start, int bank, int source) -{ - chr_sanity_check(source); - - if (source == CHRRAM) - { - bank &= ((m_vram_chunks << 1) - 1); - for (int i = 0; i < 4; i++) - { - m_chr_src[i + start] = source; - m_chr_orig[i + start] = (bank * 0x1000) + (i * 0x400); // for save state uses! - m_chr_access[i + start] = &m_vram[m_chr_orig[i + start]]; - } - } - else - { - bank &= ((m_vrom_chunks << 1) - 1); - for (int i = 0; i < 4; i++) - { - m_chr_src[i + start] = source; - m_chr_orig[i + start] = (bank * 0x1000) + (i * 0x400); // for save state uses! - m_chr_access[i + start] = &m_vrom[m_chr_orig[i + start]]; - } - } -} - -void device_nes_cart_interface::chr2_x(int start, int bank, int source) -{ - chr_sanity_check(source); - - if (source == CHRRAM) - { - bank &= ((m_vram_chunks << 2) - 1); - for (int i = 0; i < 2; i++) - { - m_chr_src[i + start] = source; - m_chr_orig[i + start] = (bank * 0x800) + (i * 0x400); // for save state uses! - m_chr_access[i + start] = &m_vram[m_chr_orig[i + start]]; - } - } - else - { - bank &= ((m_vrom_chunks << 2) - 1); - for (int i = 0; i < 2; i++) - { - m_chr_src[i + start] = source; - m_chr_orig[i + start] = (bank * 0x800) + (i * 0x400); // for save state uses! - m_chr_access[i + start] = &m_vrom[m_chr_orig[i + start]]; - } - } -} - -void device_nes_cart_interface::chr1_x(int start, int bank, int source) -{ - chr_sanity_check(source); - - if (source == CHRRAM) - { - bank &= ((m_vram_chunks << 3) - 1); - m_chr_src[start] = source; - m_chr_orig[start] = (bank * 0x400); // for save state uses! - m_chr_access[start] = &m_vram[m_chr_orig[start]]; - } - else - { - bank &= ((m_vrom_chunks << 3) - 1); - m_chr_src[start] = source; - m_chr_orig[start] = (bank * 0x400); // for save state uses! - m_chr_access[start] = &m_vrom[m_chr_orig[start]]; - } -} - -//------------------------------------------------- -// NT & Mirroring helpers -//------------------------------------------------- - -void device_nes_cart_interface::set_nt_page(int page, int source, int bank, int writable) -{ - UINT8* base_ptr; - - switch (source) - { - case CART_NTRAM: - base_ptr = &m_ext_ntram[0]; - break; - case VROM: - bank &= ((m_vrom_chunks << 3) - 1); - base_ptr = m_vrom; - break; - case EXRAM: - case MMC5FILL: - base_ptr = NULL; - break; - case CIRAM: - default: - base_ptr = m_ciram; - break; - } - - page &= 3; /* mask down to the 4 logical pages */ - m_nt_src[page] = source; - - if (base_ptr) - { - m_nt_orig[page] = bank * 0x400; - m_nt_access[page] = base_ptr + m_nt_orig[page]; - } - - m_nt_writable[page] = writable; -} - -void device_nes_cart_interface::set_nt_mirroring(int mirroring) -{ - /* setup our videomem handlers based on mirroring */ - switch (mirroring) - { - case PPU_MIRROR_VERT: - set_nt_page(0, CIRAM, 0, 1); - set_nt_page(1, CIRAM, 1, 1); - set_nt_page(2, CIRAM, 0, 1); - set_nt_page(3, CIRAM, 1, 1); - break; - - case PPU_MIRROR_HORZ: - set_nt_page(0, CIRAM, 0, 1); - set_nt_page(1, CIRAM, 0, 1); - set_nt_page(2, CIRAM, 1, 1); - set_nt_page(3, CIRAM, 1, 1); - break; - - case PPU_MIRROR_HIGH: - set_nt_page(0, CIRAM, 1, 1); - set_nt_page(1, CIRAM, 1, 1); - set_nt_page(2, CIRAM, 1, 1); - set_nt_page(3, CIRAM, 1, 1); - break; - - case PPU_MIRROR_LOW: - set_nt_page(0, CIRAM, 0, 1); - set_nt_page(1, CIRAM, 0, 1); - set_nt_page(2, CIRAM, 0, 1); - set_nt_page(3, CIRAM, 0, 1); - break; - - case PPU_MIRROR_4SCREEN: - if (m_ext_ntram.empty()) fatalerror("4-screen mirroring without on-cart NTRAM!\n"); - set_nt_page(0, CART_NTRAM, 0, 1); - set_nt_page(1, CART_NTRAM, 1, 1); - set_nt_page(2, CART_NTRAM, 2, 1); - set_nt_page(3, CART_NTRAM, 3, 1); - break; - - case PPU_MIRROR_NONE: - default: - set_nt_page(0, CIRAM, 0, 1); - set_nt_page(1, CIRAM, 0, 1); - set_nt_page(2, CIRAM, 1, 1); - set_nt_page(3, CIRAM, 1, 1); - break; - } -} - -//------------------------------------------------- -// Other helpers -//------------------------------------------------- - -// Helper function for the few mappers reading from 0x8000-0xffff for protection -// so that they can access the ROM after the protection handling (which overwrites -// the memory banks) -UINT8 device_nes_cart_interface::hi_access_rom(UINT32 offset) -{ - int bank = (offset & 0x6000) >> 13; - return m_prg[m_prg_bank[bank] * 0x2000 + (offset & 0x1fff)]; -} - -// Helper function for the few mappers subject to bus conflict at write. -// Tests by blargg showed that in many of the boards suffering of CPU/ROM -// conflicts the behaviour can be accurately emulated by writing not the -// original data, but data & rom[offset] -UINT8 device_nes_cart_interface::account_bus_conflict(UINT32 offset, UINT8 data) -{ - // pirate variants of boards subject to bus conflict are often not subject to it - // so we allow to set m_bus_conflict to FALSE at loading time when necessary - if (m_bus_conflict) - return data & hi_access_rom(offset); - else - return data; -} - - -//------------------------------------------------- -// PPU accessors -//------------------------------------------------- - -WRITE8_MEMBER(device_nes_cart_interface::chr_w) -{ - int bank = offset >> 10; - - if (m_chr_src[bank] == CHRRAM) - m_chr_access[bank][offset & 0x3ff] = data; -} - -READ8_MEMBER(device_nes_cart_interface::chr_r) -{ - int bank = offset >> 10; - return m_chr_access[bank][offset & 0x3ff]; -} - - -WRITE8_MEMBER(device_nes_cart_interface::nt_w) -{ - int page = ((offset & 0xc00) >> 10); - - if (!m_nt_writable[page]) - return; - - m_nt_access[page][offset & 0x3ff] = data; -} - -READ8_MEMBER(device_nes_cart_interface::nt_r) -{ - int page = ((offset & 0xc00) >> 10); - return m_nt_access[page][offset & 0x3ff]; -} - - -//------------------------------------------------- -// Base memory accessors (emulating open bus -// behaviour and/or WRAM accesses) -// Open bus emulation is defective, but it should -// be enough for the few cases known to rely on -// this (more in the comments at the top of the -// source) -//------------------------------------------------- - -READ8_MEMBER(device_nes_cart_interface::read_l) -{ - return m_open_bus; -} - -READ8_MEMBER(device_nes_cart_interface::read_m) -{ - if (!m_battery.empty()) - return m_battery[offset & (m_battery.size() - 1)]; - if (!m_prgram.empty()) - return m_prgram[offset & (m_prgram.size() - 1)]; - - return m_open_bus; -} - -WRITE8_MEMBER(device_nes_cart_interface::write_l) -{ -} - -WRITE8_MEMBER(device_nes_cart_interface::write_m) -{ - if (!m_battery.empty()) - m_battery[offset & (m_battery.size() - 1)] = data; - if (!m_prgram.empty()) - m_prgram[offset & (m_prgram.size() - 1)] = data; -} - -WRITE8_MEMBER(device_nes_cart_interface::write_h) -{ -} - - -void device_nes_cart_interface::pcb_start(running_machine &machine, UINT8 *ciram_ptr, bool cart_mounted) -{ - // HACK: to reduce tagmap lookups for PPU-related IRQs, we add a hook to the - // main NES CPU here, even if it does not belong to this device. - m_maincpu = machine.device("maincpu"); - - if (cart_mounted) // disksys expansion can arrive here without the memory banks! - { - // Setup PRG - m_prg_bank_mem[0] = machine.root_device().membank("prg0"); - m_prg_bank_mem[1] = machine.root_device().membank("prg1"); - m_prg_bank_mem[2] = machine.root_device().membank("prg2"); - m_prg_bank_mem[3] = machine.root_device().membank("prg3"); - for (int i = 0; i < 4; i++) - { - if (m_prg_bank_mem[i]) - { - m_prg_bank_mem[i]->configure_entries(0, m_prg_size / 0x2000, m_prg, 0x2000); - m_prg_bank_mem[i]->set_entry(i); - m_prg_bank[i] = i; - } - } - } - - // Setup CHR (VRAM can be present also without PRG rom) - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - chr8(0, m_chr_source); - - // Setup NT - m_ciram = ciram_ptr; - - if (m_four_screen_vram) - { - m_ext_ntram.resize(0x2000); - device().save_item(NAME(m_ext_ntram)); - } - - // at loading time we have configured m_mirroring, now setup NT pages - set_nt_mirroring(m_mirroring); - - // save the on-cart RAM pointers - if (!m_prgram.empty()) - device().save_item(NAME(m_prgram)); - if (!m_vram.empty()) - device().save_item(NAME(m_vram)); - if (!m_battery.empty()) - device().save_item(NAME(m_battery)); -} - -void device_nes_cart_interface::pcb_reg_postload(running_machine &machine) -{ - machine.save().register_postload(save_prepost_delegate(FUNC(device_nes_cart_interface::nes_banks_restore), this)); -} - -void device_nes_cart_interface::nes_banks_restore() -{ - for (int i = 0; i < 4; i++) - m_prg_bank_mem[i]->set_entry(m_prg_bank[i]); - - for (int i = 0; i < 8; i++) - chr1_x(i, m_chr_orig[i] / 0x400, m_chr_src[i]); - - for (int i = 0; i < 4; i++) - set_nt_page(i, m_nt_src[i], m_nt_orig[i] / 0x400, m_nt_writable[i]); -} - - -//************************************************************************** -// LIVE DEVICE -//************************************************************************** - -//------------------------------------------------- -// nes_cart_slot_device - constructor -//------------------------------------------------- -nes_cart_slot_device::nes_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : - device_t(mconfig, NES_CART_SLOT, "NES Cartridge Slot", tag, owner, clock, "nes_cart_slot", __FILE__), - device_image_interface(mconfig, *this), - device_slot_interface(mconfig, *this), - m_crc_hack(0), - m_pcb_id(NO_BOARD), - m_must_be_loaded(1) -{ -} - -//------------------------------------------------- -// nes_cart_slot_device - destructor -//------------------------------------------------- - -nes_cart_slot_device::~nes_cart_slot_device() -{ -} - -//------------------------------------------------- -// device_start - device-specific startup -//------------------------------------------------- - -void nes_cart_slot_device::device_start() -{ - m_cart = dynamic_cast(get_card_device()); -} - -//------------------------------------------------- -// device_config_complete - perform any -// operations now that the configuration is -// complete -//------------------------------------------------- - -void nes_cart_slot_device::device_config_complete() -{ - // set brief and instance name - update_names(); -} - - -void nes_cart_slot_device::pcb_start(UINT8 *ciram_ptr) -{ - if (m_cart) - m_cart->pcb_start(machine(), ciram_ptr, exists()); -} - -void nes_cart_slot_device::pcb_reset() -{ - if (m_cart) - m_cart->pcb_reset(); -} - -/*------------------------------------------------- - call load - -------------------------------------------------*/ - - -/*------------------------------------------------- - - Load from xml list and identify the required slot device - - -------------------------------------------------*/ - -/* Include emulation of NES PCBs for softlist */ -#include "nes_pcb.inc" - - -/*------------------------------------------------- - - Load .unf files (UNIF boards) and identify the required slot device - - -------------------------------------------------*/ - -/* Include emulation of UNIF Boards for .unf files */ -#include "nes_unif.inc" - - -/*------------------------------------------------- - - Load .nes files (iNES mappers) and identify the required slot devices - - -------------------------------------------------*/ - -/* Include emulation of iNES Mappers for .nes files */ -#include "nes_ines.inc" - - -bool nes_cart_slot_device::call_load() -{ - if (m_cart) - { - if (software_entry() == NULL) - { - char magic[4]; - - /* Check first 4 bytes of the image to decide if it is UNIF or iNES */ - /* Unfortunately, many .unf files have been released as .nes, so we cannot rely on extensions only */ - fread(magic, 4); - - if ((magic[0] == 'N') && (magic[1] == 'E') && (magic[2] == 'S')) /* If header starts with 'NES' it is iNES */ - { - if (length() <= 0x10) - { - logerror("%s only contains the iNES header and no data.\n", filename()); - return IMAGE_INIT_FAIL; - } - - call_load_ines(); - } - else if ((magic[0] == 'U') && (magic[1] == 'N') && (magic[2] == 'I') && (magic[3] == 'F')) /* If header starts with 'UNIF' it is UNIF */ - { - if (length() <= 0x20) - { - logerror("%s only contains the UNIF header and no data.\n", filename()); - return IMAGE_INIT_FAIL; - } - - call_load_unif(); - } - else - { - logerror("%s is NOT a file in either iNES or UNIF format.\n", filename()); - return IMAGE_INIT_FAIL; - } - } - else - call_load_pcb(); - } - - return IMAGE_INIT_PASS; -} - - -/*------------------------------------------------- - call_unload - -------------------------------------------------*/ - -void nes_cart_slot_device::call_unload() -{ - if (m_cart) - { - if (m_cart->get_battery_size() || m_cart->get_mapper_sram_size()) - { - UINT32 tot_size = m_cart->get_battery_size() + m_cart->get_mapper_sram_size(); - dynamic_buffer temp_nvram(tot_size); - if (m_cart->get_battery_size()) - memcpy(&temp_nvram[0], m_cart->get_battery_base(), m_cart->get_battery_size()); - if (m_cart->get_mapper_sram_size()) - memcpy(&temp_nvram[m_cart->get_battery_size()], m_cart->get_mapper_sram_base(), m_cart->get_mapper_sram_size()); - - battery_save(&temp_nvram[0], tot_size); - } - } -} - - -/*------------------------------------------------- - call softlist load - -------------------------------------------------*/ - -bool nes_cart_slot_device::call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry) -{ - load_software_part_region(*this, swlist, swname, start_entry); - return TRUE; -} - -/*------------------------------------------------- - get default card software - -------------------------------------------------*/ - -void nes_cart_slot_device::get_default_card_software(std::string &result) -{ - if (open_image_file(mconfig().options())) - { - const char *slot_string = "nrom"; - UINT32 len = core_fsize(m_file); - dynamic_buffer rom(len); - - core_fread(m_file, &rom[0], len); - - if ((rom[0] == 'N') && (rom[1] == 'E') && (rom[2] == 'S')) - slot_string = get_default_card_ines(&rom[0], len); - - if ((rom[0] == 'U') && (rom[1] == 'N') && (rom[2] == 'I') && (rom[3] == 'F')) - slot_string = get_default_card_unif(&rom[0], len); - - clear(); - - result.assign(slot_string); - } - else - software_get_default_slot(result, "nrom"); -} - - -/*------------------------------------------------- - read - -------------------------------------------------*/ - -READ8_MEMBER(nes_cart_slot_device::read_l) -{ - if (m_cart) - { - UINT8 val = m_cart->read_l(space, offset); - // update open bus - m_cart->set_open_bus(((offset + 0x4100) & 0xff00) >> 8); - return val; - } - else - return 0xff; -} - -READ8_MEMBER(nes_cart_slot_device::read_m) -{ - if (m_cart) - { - UINT8 val = m_cart->read_m(space, offset); - // update open bus - m_cart->set_open_bus(((offset + 0x6000) & 0xff00) >> 8); - return val; - } - else - return 0xff; -} - -READ8_MEMBER(nes_cart_slot_device::read_h) -{ - if (m_cart) - { - UINT8 val = m_cart->read_h(space, offset); - // update open bus - m_cart->set_open_bus(((offset + 0x8000) & 0xff00) >> 8); - return val; - } - else - return 0xff; -} - -READ8_MEMBER(nes_cart_slot_device::read_ex) -{ - if (m_cart) - { - UINT8 val = m_cart->read_ex(space, offset); - // update open bus - m_cart->set_open_bus(((offset + 0x4020) & 0xff00) >> 8); - return val; - } - else - return 0xff; -} - - -/*------------------------------------------------- - write - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_cart_slot_device::write_l) -{ - if (m_cart) - { - m_cart->write_l(space, offset, data); - // update open bus - m_cart->set_open_bus(((offset + 0x4100) & 0xff00) >> 8); - } -} - -WRITE8_MEMBER(nes_cart_slot_device::write_m) -{ - if (m_cart) - { - m_cart->write_m(space, offset, data); - // update open bus - m_cart->set_open_bus(((offset + 0x6000) & 0xff00) >> 8); - } -} - -WRITE8_MEMBER(nes_cart_slot_device::write_h) -{ - if (m_cart) - { - m_cart->write_h(space, offset, data); - // update open bus - m_cart->set_open_bus(((offset + 0x8000) & 0xff00) >> 8); - } -} - -WRITE8_MEMBER(nes_cart_slot_device::write_ex) -{ - if (m_cart) - { - m_cart->write_ex(space, offset, data); - // update open bus - m_cart->set_open_bus(((offset + 0x4020) & 0xff00) >> 8); - } -} - - -//------------------------------------------------- -// partial hash function to be used by -// device_image_partialhash_func -//------------------------------------------------- - -void nes_partialhash(hash_collection &dest, const unsigned char *data, - unsigned long length, const char *functions) -{ - if (length <= 16) - return; - dest.compute(&data[16], length - 16, functions); -} diff --git a/src/devices/bus/nes/nes_slot.cpp b/src/devices/bus/nes/nes_slot.cpp new file mode 100644 index 00000000000..ec1b1f5f4af --- /dev/null +++ b/src/devices/bus/nes/nes_slot.cpp @@ -0,0 +1,1053 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + Nintendo NES/FC cart emulation + (through slot devices) + + The driver exposes address ranges + 0x4100-0x5fff to read_l/write_l + 0x6000-0x7fff to read_m/write_m (here are *usually* installed NVRAM & WRAM, if any) + 0x8000-0xffff to write_h (reads are directed to 4 x 8K PRG banks) + Default implementations of these handlers are available here, to be rewritten by PCB-specific ones when needed. + + Additional handlers are available, but have to be manually installed at machine_start + * read_ex/write_ex for address range 0x4020-0x40ff + * read_h for address range 0x8000-0xffff when a cart does some protection or address scramble before reading ROM + + PPU exposes address ranges + 0x0000-0x1fff to chr_r/chr_w + 0x2000-0x3eff to nt_r/nt_w + Default implementations of these handlers are available here, to be rewritten by PCB-specific ones when needed. + + Plus a few of latch functions are available: ppu_latch (see MMC2), hblank_irq and scanline_irq (see e.g. MMC3), + but these might be subject to future changes when the PPU is revisited. + + Notes: + - Differently from later systems (like SNES or MD), it is uncommon to find PRG ROMs of NES games which are not a + power of 2K, so we do not perform any mirroring by default. + A bunch of pcb types, though, come with 1.5MB of PRG (some Waixing translations) or with multiple PRG chips + having peculiar size (32K + 16K, 32K + 8K, 32K + 2K). Hence, if such a configuration is detected, we provide + a m_prg_bank_map array to handle internally PRG mirroring up to the next power of 2K, as long as the size is + a multiple of 8K (i.e. the unit chunk for standard PRG). + For the case of PRG chips which are not-multiple of 8K (e.g. UNL-MARIO2-MALEE pcb), the handling has to be + handled in the pcb-specific code! + - Our open bus emulation is very sketchy, by simply returning the higher 8bits of the accessed address. This seems + enough for most games (only two sets have issues with this). A slightly better implementation is almost ready + to fix these two remaining cases, but I plan to revisit the whole implementation in an accurate way at a later + stage + - Bus conflict is implemented based on latest tests by Blargg. There is some uncertainty about AxROM behavior + (some AOROM pcbs suffers from bus conflict, some do not... since no AOROM game is known to glitch due to lack + of bus conflict it seems safe to emulate the board without bus conflict, but eventually it would be good to + differentiate the real variants) + + + Many information about the mappers/pcbs come from the wonderful doc written by Disch. + Current info (when used) are based on v0.6.1 of his docs. + You can find the latest version of the doc at http://www.romhacking.net/docs/362/ + + A lot of details have been based on the researches carried on at NesDev forums (by Blargg, Quietust and many more) + and collected on the NesDev Wiki http://wiki.nesdev.com/ + + Particular thanks go to + - Martin Freij for his work on NEStopia + - Cah4e3 for his efforts on FCEUMM and the reverse engineering of pirate boards + - BootGod, lidnariq and naruko for the PCB tests which made possible + + + ***********************************************************************************************************/ + +/***************************************************************************************** + + A few Mappers suffer of hardware conflict: original dumpers have used the same mapper number for more than + a kind of boards. In these cases (and only in these cases) we exploit nes.hsi to set up accordingly + emulation. Games which requires this hack are the following: + * 032 - Major League needs hardwired mirroring (missing windows and glitched field in top view, otherwise) + * 034 - Impossible Mission II is not like BxROM games (it writes to 0x7ffd-0x7fff, instead of 0x8000). It is still + unplayable though (see above) + * 071 - Fire Hawk is different from other Camerica games (no hardwired mirroring). Without crc_hack no helicopter graphics + * 078 - Cosmo Carrier needs a different mirroring than Holy Diver + * 113 - HES 6-in-1 requires mirroring (check Bookyman playfield), while other games break with this (check AV Soccer) + * 153 - Famicom Jump II uses a different board (or the same in a very different way) + * 242 - DQ8 has no mirroring (missing graphics is due to other reasons though) + + crc_hacks have been added also to handle a few wiring settings which would require submappers: + * CHR protection pins for mapper 185 + * VRC-2, VRC-4 and VRC-6 line wiring + + Remember that the MMC # does not equal the mapper #. In particular, Mapper 4 is + in fact MMC3, Mapper 9 is MMC2 and Mapper 10 is MMC4. Makes perfect sense, right? + + ****************************************************************************************/ + + +#include "emu.h" +#include "hashfile.h" +#include "nes_slot.h" + +#define NES_BATTERY_SIZE 0x2000 + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type NES_CART_SLOT = &device_creator; + + +//************************************************************************** +// NES cartridges Interface +//************************************************************************** + +//------------------------------------------------- +// device_nes_cart_interface - constructor +//------------------------------------------------- + +device_nes_cart_interface::device_nes_cart_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig, device), + m_prg(NULL), + m_vrom(NULL), + m_ciram(NULL), + m_prg_size(0), + m_vrom_size(0), + m_mapper_sram(NULL), + m_mapper_sram_size(0), + m_ce_mask(0), + m_ce_state(0), + m_vrc_ls_prg_a(0), + m_vrc_ls_prg_b(0), + m_vrc_ls_chr(0), + m_mirroring(PPU_MIRROR_NONE), + m_pcb_ctrl_mirror(FALSE), + m_four_screen_vram(FALSE), + m_has_trainer(FALSE), + m_x1_005_alt_mirroring(FALSE), + m_bus_conflict(TRUE), + m_open_bus(0), + m_prg_chunks(0), + m_prg_mask(0xffff), + m_chr_source(CHRRAM), + m_vrom_chunks(0), + m_vram_chunks(0) +{ +} + + +//------------------------------------------------- +// ~device_nes_cart_interface - destructor +//------------------------------------------------- + +device_nes_cart_interface::~device_nes_cart_interface() +{ +} + +//------------------------------------------------- +// pointer allocators +//------------------------------------------------- + +void device_nes_cart_interface::prg_alloc(size_t size, const char *tag) +{ + if (m_prg == NULL) + { + m_prg = device().machine().memory().region_alloc(std::string(tag).append(NESSLOT_PRGROM_REGION_TAG).c_str(), size, 1, ENDIANNESS_LITTLE)->base(); + m_prg_size = size; + m_prg_chunks = size / 0x4000; + if (size % 0x2000) + { + // A few pirate carts have PRG made of 32K + 2K or some weird similar config + // in this case we treat the banking as if this 'extra' PRG is not present and + // the pcb code has to handle it by accessing directly m_prg! + printf("Warning! The loaded PRG has size not a multiple of 8KB (0x%X)\n", (UINT32)size); + m_prg_chunks--; + } + + m_prg_mask = ((m_prg_chunks << 1) - 1); + +// printf("first mask %x!\n", m_prg_mask); + if ((m_prg_chunks << 1) & m_prg_mask) + { + int mask_bits = 0, temp = (m_prg_chunks << 1), mapsize; + // contrary to what happens with later systems, like e.g. SNES or MD, + // only half a dozen of NES carts have PRG which is not a power of 2 + // so we use this bank_map only as an exception +// printf("uneven rom!\n"); + + // 1. redefine mask as (next power of 2)-1 + for (; temp; ) + { + mask_bits++; + temp >>= 1; + } + m_prg_mask = (1 << mask_bits) - 1; +// printf("new mask %x!\n", m_prg_mask); + mapsize = (1 << mask_bits)/2; + + // 2. create a bank_map for banks in the range mask/2 -> mask + m_prg_bank_map.resize(mapsize); + + // 3. fill the bank_map accounting for mirrors + int j; + for (j = mapsize; j < (m_prg_chunks << 1); j++) + m_prg_bank_map[j - mapsize] = j; + + while (j % mapsize) + { + int k = 0, repeat_banks; + while ((j % (mapsize >> k)) && k < mask_bits) + k++; + repeat_banks = j % (mapsize >> (k - 1)); + for (int l = 0; l < repeat_banks; l++) + m_prg_bank_map[(j - mapsize) + l] = m_prg_bank_map[(j - mapsize) + l - repeat_banks]; + j += repeat_banks; + } + + // check bank map! +// for (int i = 0; i < mapsize; i++) +// { +// printf("bank %3d = %3d\t", i, m_prg_bank_map[i]); +// if ((i%8) == 7) +// printf("\n"); +// } + } + } +} + +void device_nes_cart_interface::vrom_alloc(size_t size, const char *tag) +{ + if (m_vrom == NULL) + { + std::string tempstring(tag); + tempstring.append(NESSLOT_CHRROM_REGION_TAG); + m_vrom = device().machine().memory().region_alloc(tempstring.c_str(), size, 1, ENDIANNESS_LITTLE)->base(); + m_vrom_size = size; + m_vrom_chunks = size / 0x2000; + } +} + +void device_nes_cart_interface::prgram_alloc(size_t size) +{ + m_prgram.resize(size); +} + +void device_nes_cart_interface::vram_alloc(size_t size) +{ + m_vram.resize(size); + m_vram_chunks = size / 0x2000; +} + +void device_nes_cart_interface::battery_alloc(size_t size) +{ + m_battery.resize(size); +} + + +//------------------------------------------------- +// PRG helpers +//------------------------------------------------- + +inline int device_nes_cart_interface::prg_8k_bank_num(int bank_8k) +{ + if (m_prg_mask == ((m_prg_chunks << 1) - 1)) + return bank_8k & m_prg_mask; + + // only a few pirate games (less than a dozen) have PRG which is not power of 2 + // so we treat it here separately, rather than forcing all games to use m_prg_bank_map + + // case 1: if we are accessing a bank before the end of the image, just return that bank + if (bank_8k < ((m_prg_chunks << 1) - 1)) + return bank_8k; + + // case 2: otherwise return a mirror using the bank_map! +// UINT8 temp = bank_8k; + bank_8k &= m_prg_mask; + bank_8k -= (m_prg_mask/2 + 1); +// printf("bank: accessed %x (top: %x), returned %x\n", temp, (m_prg_chunks << 1) - 1, m_prg_bank_map[bank_8k]); + return m_prg_bank_map[bank_8k]; +} + +inline void device_nes_cart_interface::update_prg_banks(int prg_bank_start, int prg_bank_end) +{ + for (int prg_bank = prg_bank_start; prg_bank <= prg_bank_end; prg_bank++) + { + assert(prg_bank >= 0); + assert(prg_bank < ARRAY_LENGTH(m_prg_bank)); + assert(prg_bank < ARRAY_LENGTH(m_prg_bank_mem)); + + m_prg_bank_mem[prg_bank]->set_entry(m_prg_bank[prg_bank]); + } +} + +void device_nes_cart_interface::prg32(int bank) +{ + /* if there is only 16k PRG, return */ + if (!(m_prg_chunks >> 1)) + return; + + /* assumes that bank references a 32k chunk */ + bank = prg_8k_bank_num(bank * 4); + + m_prg_bank[0] = bank + 0; + m_prg_bank[1] = bank + 1; + m_prg_bank[2] = bank + 2; + m_prg_bank[3] = bank + 3; + update_prg_banks(0, 3); +} + +void device_nes_cart_interface::prg16_89ab(int bank) +{ + /* assumes that bank references a 16k chunk */ + bank = prg_8k_bank_num(bank * 2); + + m_prg_bank[0] = bank + 0; + m_prg_bank[1] = bank + 1; + update_prg_banks(0, 1); +} + +void device_nes_cart_interface::prg16_cdef(int bank) +{ + /* assumes that bank references a 16k chunk */ + bank = prg_8k_bank_num(bank * 2); + + m_prg_bank[2] = bank + 0; + m_prg_bank[3] = bank + 1; + update_prg_banks(2, 3); +} + +void device_nes_cart_interface::prg8_89(int bank) +{ + /* assumes that bank references an 8k chunk */ + bank = prg_8k_bank_num(bank); + + m_prg_bank[0] = bank; + update_prg_banks(0, 0); +} + +void device_nes_cart_interface::prg8_ab(int bank) +{ + /* assumes that bank references an 8k chunk */ + bank = prg_8k_bank_num(bank); + + m_prg_bank[1] = bank; + update_prg_banks(1, 1); +} + +void device_nes_cart_interface::prg8_cd(int bank) +{ + /* assumes that bank references an 8k chunk */ + bank = prg_8k_bank_num(bank); + + m_prg_bank[2] = bank; + update_prg_banks(2, 2); +} + +void device_nes_cart_interface::prg8_ef(int bank) +{ + /* assumes that bank references an 8k chunk */ + bank = prg_8k_bank_num(bank); + + m_prg_bank[3] = bank; + update_prg_banks(3, 3); +} + +/* We also define an additional helper to map 8k PRG-ROM to one of the banks (passed as parameter) */ +void device_nes_cart_interface::prg8_x(int start, int bank) +{ + assert(start < 4); + + /* assumes that bank references an 8k chunk */ + bank = prg_8k_bank_num(bank); + + m_prg_bank[start] = bank; + update_prg_banks(start, start); +} + +//------------------------------------------------- +// CHR helpers +//------------------------------------------------- + +inline void device_nes_cart_interface::chr_sanity_check( int source ) +{ + if (source == CHRRAM && m_vram.empty()) + fatalerror("CHRRAM bankswitch with no VRAM\n"); + + if (source == CHRROM && m_vrom == NULL) + fatalerror("CHRROM bankswitch with no VROM\n"); +} + +void device_nes_cart_interface::chr8(int bank, int source) +{ + chr_sanity_check(source); + + if (source == CHRRAM) + { + bank &= (m_vram_chunks - 1); + for (int i = 0; i < 8; i++) + { + m_chr_src[i] = source; + m_chr_orig[i] = (bank * 0x2000) + (i * 0x400); // for save state uses! + m_chr_access[i] = &m_vram[m_chr_orig[i]]; + } + } + else + { + bank &= (m_vrom_chunks - 1); + for (int i = 0; i < 8; i++) + { + m_chr_src[i] = source; + m_chr_orig[i] = (bank * 0x2000) + (i * 0x400); // for save state uses! + m_chr_access[i] = &m_vrom[m_chr_orig[i]]; + } + } +} + +void device_nes_cart_interface::chr4_x(int start, int bank, int source) +{ + chr_sanity_check(source); + + if (source == CHRRAM) + { + bank &= ((m_vram_chunks << 1) - 1); + for (int i = 0; i < 4; i++) + { + m_chr_src[i + start] = source; + m_chr_orig[i + start] = (bank * 0x1000) + (i * 0x400); // for save state uses! + m_chr_access[i + start] = &m_vram[m_chr_orig[i + start]]; + } + } + else + { + bank &= ((m_vrom_chunks << 1) - 1); + for (int i = 0; i < 4; i++) + { + m_chr_src[i + start] = source; + m_chr_orig[i + start] = (bank * 0x1000) + (i * 0x400); // for save state uses! + m_chr_access[i + start] = &m_vrom[m_chr_orig[i + start]]; + } + } +} + +void device_nes_cart_interface::chr2_x(int start, int bank, int source) +{ + chr_sanity_check(source); + + if (source == CHRRAM) + { + bank &= ((m_vram_chunks << 2) - 1); + for (int i = 0; i < 2; i++) + { + m_chr_src[i + start] = source; + m_chr_orig[i + start] = (bank * 0x800) + (i * 0x400); // for save state uses! + m_chr_access[i + start] = &m_vram[m_chr_orig[i + start]]; + } + } + else + { + bank &= ((m_vrom_chunks << 2) - 1); + for (int i = 0; i < 2; i++) + { + m_chr_src[i + start] = source; + m_chr_orig[i + start] = (bank * 0x800) + (i * 0x400); // for save state uses! + m_chr_access[i + start] = &m_vrom[m_chr_orig[i + start]]; + } + } +} + +void device_nes_cart_interface::chr1_x(int start, int bank, int source) +{ + chr_sanity_check(source); + + if (source == CHRRAM) + { + bank &= ((m_vram_chunks << 3) - 1); + m_chr_src[start] = source; + m_chr_orig[start] = (bank * 0x400); // for save state uses! + m_chr_access[start] = &m_vram[m_chr_orig[start]]; + } + else + { + bank &= ((m_vrom_chunks << 3) - 1); + m_chr_src[start] = source; + m_chr_orig[start] = (bank * 0x400); // for save state uses! + m_chr_access[start] = &m_vrom[m_chr_orig[start]]; + } +} + +//------------------------------------------------- +// NT & Mirroring helpers +//------------------------------------------------- + +void device_nes_cart_interface::set_nt_page(int page, int source, int bank, int writable) +{ + UINT8* base_ptr; + + switch (source) + { + case CART_NTRAM: + base_ptr = &m_ext_ntram[0]; + break; + case VROM: + bank &= ((m_vrom_chunks << 3) - 1); + base_ptr = m_vrom; + break; + case EXRAM: + case MMC5FILL: + base_ptr = NULL; + break; + case CIRAM: + default: + base_ptr = m_ciram; + break; + } + + page &= 3; /* mask down to the 4 logical pages */ + m_nt_src[page] = source; + + if (base_ptr) + { + m_nt_orig[page] = bank * 0x400; + m_nt_access[page] = base_ptr + m_nt_orig[page]; + } + + m_nt_writable[page] = writable; +} + +void device_nes_cart_interface::set_nt_mirroring(int mirroring) +{ + /* setup our videomem handlers based on mirroring */ + switch (mirroring) + { + case PPU_MIRROR_VERT: + set_nt_page(0, CIRAM, 0, 1); + set_nt_page(1, CIRAM, 1, 1); + set_nt_page(2, CIRAM, 0, 1); + set_nt_page(3, CIRAM, 1, 1); + break; + + case PPU_MIRROR_HORZ: + set_nt_page(0, CIRAM, 0, 1); + set_nt_page(1, CIRAM, 0, 1); + set_nt_page(2, CIRAM, 1, 1); + set_nt_page(3, CIRAM, 1, 1); + break; + + case PPU_MIRROR_HIGH: + set_nt_page(0, CIRAM, 1, 1); + set_nt_page(1, CIRAM, 1, 1); + set_nt_page(2, CIRAM, 1, 1); + set_nt_page(3, CIRAM, 1, 1); + break; + + case PPU_MIRROR_LOW: + set_nt_page(0, CIRAM, 0, 1); + set_nt_page(1, CIRAM, 0, 1); + set_nt_page(2, CIRAM, 0, 1); + set_nt_page(3, CIRAM, 0, 1); + break; + + case PPU_MIRROR_4SCREEN: + if (m_ext_ntram.empty()) fatalerror("4-screen mirroring without on-cart NTRAM!\n"); + set_nt_page(0, CART_NTRAM, 0, 1); + set_nt_page(1, CART_NTRAM, 1, 1); + set_nt_page(2, CART_NTRAM, 2, 1); + set_nt_page(3, CART_NTRAM, 3, 1); + break; + + case PPU_MIRROR_NONE: + default: + set_nt_page(0, CIRAM, 0, 1); + set_nt_page(1, CIRAM, 0, 1); + set_nt_page(2, CIRAM, 1, 1); + set_nt_page(3, CIRAM, 1, 1); + break; + } +} + +//------------------------------------------------- +// Other helpers +//------------------------------------------------- + +// Helper function for the few mappers reading from 0x8000-0xffff for protection +// so that they can access the ROM after the protection handling (which overwrites +// the memory banks) +UINT8 device_nes_cart_interface::hi_access_rom(UINT32 offset) +{ + int bank = (offset & 0x6000) >> 13; + return m_prg[m_prg_bank[bank] * 0x2000 + (offset & 0x1fff)]; +} + +// Helper function for the few mappers subject to bus conflict at write. +// Tests by blargg showed that in many of the boards suffering of CPU/ROM +// conflicts the behaviour can be accurately emulated by writing not the +// original data, but data & rom[offset] +UINT8 device_nes_cart_interface::account_bus_conflict(UINT32 offset, UINT8 data) +{ + // pirate variants of boards subject to bus conflict are often not subject to it + // so we allow to set m_bus_conflict to FALSE at loading time when necessary + if (m_bus_conflict) + return data & hi_access_rom(offset); + else + return data; +} + + +//------------------------------------------------- +// PPU accessors +//------------------------------------------------- + +WRITE8_MEMBER(device_nes_cart_interface::chr_w) +{ + int bank = offset >> 10; + + if (m_chr_src[bank] == CHRRAM) + m_chr_access[bank][offset & 0x3ff] = data; +} + +READ8_MEMBER(device_nes_cart_interface::chr_r) +{ + int bank = offset >> 10; + return m_chr_access[bank][offset & 0x3ff]; +} + + +WRITE8_MEMBER(device_nes_cart_interface::nt_w) +{ + int page = ((offset & 0xc00) >> 10); + + if (!m_nt_writable[page]) + return; + + m_nt_access[page][offset & 0x3ff] = data; +} + +READ8_MEMBER(device_nes_cart_interface::nt_r) +{ + int page = ((offset & 0xc00) >> 10); + return m_nt_access[page][offset & 0x3ff]; +} + + +//------------------------------------------------- +// Base memory accessors (emulating open bus +// behaviour and/or WRAM accesses) +// Open bus emulation is defective, but it should +// be enough for the few cases known to rely on +// this (more in the comments at the top of the +// source) +//------------------------------------------------- + +READ8_MEMBER(device_nes_cart_interface::read_l) +{ + return m_open_bus; +} + +READ8_MEMBER(device_nes_cart_interface::read_m) +{ + if (!m_battery.empty()) + return m_battery[offset & (m_battery.size() - 1)]; + if (!m_prgram.empty()) + return m_prgram[offset & (m_prgram.size() - 1)]; + + return m_open_bus; +} + +WRITE8_MEMBER(device_nes_cart_interface::write_l) +{ +} + +WRITE8_MEMBER(device_nes_cart_interface::write_m) +{ + if (!m_battery.empty()) + m_battery[offset & (m_battery.size() - 1)] = data; + if (!m_prgram.empty()) + m_prgram[offset & (m_prgram.size() - 1)] = data; +} + +WRITE8_MEMBER(device_nes_cart_interface::write_h) +{ +} + + +void device_nes_cart_interface::pcb_start(running_machine &machine, UINT8 *ciram_ptr, bool cart_mounted) +{ + // HACK: to reduce tagmap lookups for PPU-related IRQs, we add a hook to the + // main NES CPU here, even if it does not belong to this device. + m_maincpu = machine.device("maincpu"); + + if (cart_mounted) // disksys expansion can arrive here without the memory banks! + { + // Setup PRG + m_prg_bank_mem[0] = machine.root_device().membank("prg0"); + m_prg_bank_mem[1] = machine.root_device().membank("prg1"); + m_prg_bank_mem[2] = machine.root_device().membank("prg2"); + m_prg_bank_mem[3] = machine.root_device().membank("prg3"); + for (int i = 0; i < 4; i++) + { + if (m_prg_bank_mem[i]) + { + m_prg_bank_mem[i]->configure_entries(0, m_prg_size / 0x2000, m_prg, 0x2000); + m_prg_bank_mem[i]->set_entry(i); + m_prg_bank[i] = i; + } + } + } + + // Setup CHR (VRAM can be present also without PRG rom) + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + chr8(0, m_chr_source); + + // Setup NT + m_ciram = ciram_ptr; + + if (m_four_screen_vram) + { + m_ext_ntram.resize(0x2000); + device().save_item(NAME(m_ext_ntram)); + } + + // at loading time we have configured m_mirroring, now setup NT pages + set_nt_mirroring(m_mirroring); + + // save the on-cart RAM pointers + if (!m_prgram.empty()) + device().save_item(NAME(m_prgram)); + if (!m_vram.empty()) + device().save_item(NAME(m_vram)); + if (!m_battery.empty()) + device().save_item(NAME(m_battery)); +} + +void device_nes_cart_interface::pcb_reg_postload(running_machine &machine) +{ + machine.save().register_postload(save_prepost_delegate(FUNC(device_nes_cart_interface::nes_banks_restore), this)); +} + +void device_nes_cart_interface::nes_banks_restore() +{ + for (int i = 0; i < 4; i++) + m_prg_bank_mem[i]->set_entry(m_prg_bank[i]); + + for (int i = 0; i < 8; i++) + chr1_x(i, m_chr_orig[i] / 0x400, m_chr_src[i]); + + for (int i = 0; i < 4; i++) + set_nt_page(i, m_nt_src[i], m_nt_orig[i] / 0x400, m_nt_writable[i]); +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// nes_cart_slot_device - constructor +//------------------------------------------------- +nes_cart_slot_device::nes_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, NES_CART_SLOT, "NES Cartridge Slot", tag, owner, clock, "nes_cart_slot", __FILE__), + device_image_interface(mconfig, *this), + device_slot_interface(mconfig, *this), + m_crc_hack(0), + m_pcb_id(NO_BOARD), + m_must_be_loaded(1) +{ +} + +//------------------------------------------------- +// nes_cart_slot_device - destructor +//------------------------------------------------- + +nes_cart_slot_device::~nes_cart_slot_device() +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void nes_cart_slot_device::device_start() +{ + m_cart = dynamic_cast(get_card_device()); +} + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void nes_cart_slot_device::device_config_complete() +{ + // set brief and instance name + update_names(); +} + + +void nes_cart_slot_device::pcb_start(UINT8 *ciram_ptr) +{ + if (m_cart) + m_cart->pcb_start(machine(), ciram_ptr, exists()); +} + +void nes_cart_slot_device::pcb_reset() +{ + if (m_cart) + m_cart->pcb_reset(); +} + +/*------------------------------------------------- + call load + -------------------------------------------------*/ + + +/*------------------------------------------------- + + Load from xml list and identify the required slot device + + -------------------------------------------------*/ + +/* Include emulation of NES PCBs for softlist */ +#include "nes_pcb.inc" + + +/*------------------------------------------------- + + Load .unf files (UNIF boards) and identify the required slot device + + -------------------------------------------------*/ + +/* Include emulation of UNIF Boards for .unf files */ +#include "nes_unif.inc" + + +/*------------------------------------------------- + + Load .nes files (iNES mappers) and identify the required slot devices + + -------------------------------------------------*/ + +/* Include emulation of iNES Mappers for .nes files */ +#include "nes_ines.inc" + + +bool nes_cart_slot_device::call_load() +{ + if (m_cart) + { + if (software_entry() == NULL) + { + char magic[4]; + + /* Check first 4 bytes of the image to decide if it is UNIF or iNES */ + /* Unfortunately, many .unf files have been released as .nes, so we cannot rely on extensions only */ + fread(magic, 4); + + if ((magic[0] == 'N') && (magic[1] == 'E') && (magic[2] == 'S')) /* If header starts with 'NES' it is iNES */ + { + if (length() <= 0x10) + { + logerror("%s only contains the iNES header and no data.\n", filename()); + return IMAGE_INIT_FAIL; + } + + call_load_ines(); + } + else if ((magic[0] == 'U') && (magic[1] == 'N') && (magic[2] == 'I') && (magic[3] == 'F')) /* If header starts with 'UNIF' it is UNIF */ + { + if (length() <= 0x20) + { + logerror("%s only contains the UNIF header and no data.\n", filename()); + return IMAGE_INIT_FAIL; + } + + call_load_unif(); + } + else + { + logerror("%s is NOT a file in either iNES or UNIF format.\n", filename()); + return IMAGE_INIT_FAIL; + } + } + else + call_load_pcb(); + } + + return IMAGE_INIT_PASS; +} + + +/*------------------------------------------------- + call_unload + -------------------------------------------------*/ + +void nes_cart_slot_device::call_unload() +{ + if (m_cart) + { + if (m_cart->get_battery_size() || m_cart->get_mapper_sram_size()) + { + UINT32 tot_size = m_cart->get_battery_size() + m_cart->get_mapper_sram_size(); + dynamic_buffer temp_nvram(tot_size); + if (m_cart->get_battery_size()) + memcpy(&temp_nvram[0], m_cart->get_battery_base(), m_cart->get_battery_size()); + if (m_cart->get_mapper_sram_size()) + memcpy(&temp_nvram[m_cart->get_battery_size()], m_cart->get_mapper_sram_base(), m_cart->get_mapper_sram_size()); + + battery_save(&temp_nvram[0], tot_size); + } + } +} + + +/*------------------------------------------------- + call softlist load + -------------------------------------------------*/ + +bool nes_cart_slot_device::call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry) +{ + load_software_part_region(*this, swlist, swname, start_entry); + return TRUE; +} + +/*------------------------------------------------- + get default card software + -------------------------------------------------*/ + +void nes_cart_slot_device::get_default_card_software(std::string &result) +{ + if (open_image_file(mconfig().options())) + { + const char *slot_string = "nrom"; + UINT32 len = core_fsize(m_file); + dynamic_buffer rom(len); + + core_fread(m_file, &rom[0], len); + + if ((rom[0] == 'N') && (rom[1] == 'E') && (rom[2] == 'S')) + slot_string = get_default_card_ines(&rom[0], len); + + if ((rom[0] == 'U') && (rom[1] == 'N') && (rom[2] == 'I') && (rom[3] == 'F')) + slot_string = get_default_card_unif(&rom[0], len); + + clear(); + + result.assign(slot_string); + } + else + software_get_default_slot(result, "nrom"); +} + + +/*------------------------------------------------- + read + -------------------------------------------------*/ + +READ8_MEMBER(nes_cart_slot_device::read_l) +{ + if (m_cart) + { + UINT8 val = m_cart->read_l(space, offset); + // update open bus + m_cart->set_open_bus(((offset + 0x4100) & 0xff00) >> 8); + return val; + } + else + return 0xff; +} + +READ8_MEMBER(nes_cart_slot_device::read_m) +{ + if (m_cart) + { + UINT8 val = m_cart->read_m(space, offset); + // update open bus + m_cart->set_open_bus(((offset + 0x6000) & 0xff00) >> 8); + return val; + } + else + return 0xff; +} + +READ8_MEMBER(nes_cart_slot_device::read_h) +{ + if (m_cart) + { + UINT8 val = m_cart->read_h(space, offset); + // update open bus + m_cart->set_open_bus(((offset + 0x8000) & 0xff00) >> 8); + return val; + } + else + return 0xff; +} + +READ8_MEMBER(nes_cart_slot_device::read_ex) +{ + if (m_cart) + { + UINT8 val = m_cart->read_ex(space, offset); + // update open bus + m_cart->set_open_bus(((offset + 0x4020) & 0xff00) >> 8); + return val; + } + else + return 0xff; +} + + +/*------------------------------------------------- + write + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_cart_slot_device::write_l) +{ + if (m_cart) + { + m_cart->write_l(space, offset, data); + // update open bus + m_cart->set_open_bus(((offset + 0x4100) & 0xff00) >> 8); + } +} + +WRITE8_MEMBER(nes_cart_slot_device::write_m) +{ + if (m_cart) + { + m_cart->write_m(space, offset, data); + // update open bus + m_cart->set_open_bus(((offset + 0x6000) & 0xff00) >> 8); + } +} + +WRITE8_MEMBER(nes_cart_slot_device::write_h) +{ + if (m_cart) + { + m_cart->write_h(space, offset, data); + // update open bus + m_cart->set_open_bus(((offset + 0x8000) & 0xff00) >> 8); + } +} + +WRITE8_MEMBER(nes_cart_slot_device::write_ex) +{ + if (m_cart) + { + m_cart->write_ex(space, offset, data); + // update open bus + m_cart->set_open_bus(((offset + 0x4020) & 0xff00) >> 8); + } +} + + +//------------------------------------------------- +// partial hash function to be used by +// device_image_partialhash_func +//------------------------------------------------- + +void nes_partialhash(hash_collection &dest, const unsigned char *data, + unsigned long length, const char *functions) +{ + if (length <= 16) + return; + dest.compute(&data[16], length - 16, functions); +} diff --git a/src/devices/bus/nes/ntdec.c b/src/devices/bus/nes/ntdec.c deleted file mode 100644 index 4dd7e56a842..00000000000 --- a/src/devices/bus/nes/ntdec.c +++ /dev/null @@ -1,186 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Fabio Priuli -/*********************************************************************************************************** - - - NES/Famicom cartridge emulation for NTDEC PCBs - - - Here we emulate the following PCBs - - * NTDEC ASDER [mapper 112] - * NTDEC Fighting Hero [mapper 193] - - TODO: - - why is Master Shooter not working? - - ***********************************************************************************************************/ - - -#include "emu.h" -#include "ntdec.h" - - -#ifdef NES_PCB_DEBUG -#define VERBOSE 1 -#else -#define VERBOSE 0 -#endif - -#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) - - -//------------------------------------------------- -// constructor -//------------------------------------------------- - -const device_type NES_NTDEC_ASDER = &device_creator; -const device_type NES_NTDEC_FH = &device_creator; - - -nes_ntdec_asder_device::nes_ntdec_asder_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_NTDEC_ASDER, "NES Cart NTDEC Asder PCB", tag, owner, clock, "nes_ntdec_asder", __FILE__) -{ -} - -nes_ntdec_fh_device::nes_ntdec_fh_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_NTDEC_FH, "NES Cart NTDEC Fighting Hero PCB", tag, owner, clock, "nes_ntdec_fh", __FILE__) -{ -} - - - - -void nes_ntdec_asder_device::device_start() -{ - common_start(); - save_item(NAME(m_latch)); -} - -void nes_ntdec_asder_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(0); - prg16_cdef(m_prg_chunks - 1); - chr8(0, m_chr_source); - - m_latch = 0; -} - -void nes_ntdec_fh_device::device_start() -{ - common_start(); -} - -void nes_ntdec_fh_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32((m_prg_chunks - 1) >> 1); - chr8(0, m_chr_source); - set_nt_mirroring(PPU_MIRROR_VERT); -} - - - - - -/*------------------------------------------------- - mapper specific handlers - -------------------------------------------------*/ - -/*------------------------------------------------- - - NTDEC ASDER Bootleg Board - - Games: Cobra Mission, Fighting Hero III, Huang Di, Master - Shooter - - iNES: mapper 112 - - In MESS: Supported. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_ntdec_asder_device::write_h) -{ - LOG_MMC(("ntdec_asder write_h, offset: %04x, data: %02x\n", offset, data)); - - switch (offset) - { - case 0x0000: - m_latch = data & 0x07; - break; - case 0x2000: - switch (m_latch) - { - case 0: - prg8_89(data); - break; - case 1: - prg8_ab(data); - break; - case 2: - data &= 0xfe; - chr1_0(data, CHRROM); - chr1_1(data + 1, CHRROM); - break; - case 3: - data &= 0xfe; - chr1_2(data, CHRROM); - chr1_3(data + 1, CHRROM); - break; - case 4: - chr1_4(data, CHRROM); - break; - case 5: - chr1_5(data, CHRROM); - break; - case 6: - chr1_6(data, CHRROM); - break; - case 7: - chr1_7(data, CHRROM); - break; - } - break; - case 0x6000: - set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); - break; - } -} - -/*------------------------------------------------- - - Bootleg Board by NTDEC for Fighting Hero - - Games: Fighting Hero - - Very simple mapper: writes to 0x6000-0x7fff swap PRG and - CHR banks. - - iNES: mapper 193 - - In MESS: Supported. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_ntdec_fh_device::write_m) -{ - LOG_MMC(("ntdec_fh write_m, offset: %04x, data: %02x\n", offset, data)); - - switch (offset & 0x03) - { - case 0: - chr4_0(data >> 2, CHRROM); - break; - case 1: - chr2_4(data >> 1, CHRROM); - break; - case 2: - chr2_6(data >> 1 , CHRROM); - break; - case 3: - prg8_89(data); - break; - } -} diff --git a/src/devices/bus/nes/ntdec.cpp b/src/devices/bus/nes/ntdec.cpp new file mode 100644 index 00000000000..4dd7e56a842 --- /dev/null +++ b/src/devices/bus/nes/ntdec.cpp @@ -0,0 +1,186 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for NTDEC PCBs + + + Here we emulate the following PCBs + + * NTDEC ASDER [mapper 112] + * NTDEC Fighting Hero [mapper 193] + + TODO: + - why is Master Shooter not working? + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "ntdec.h" + + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_NTDEC_ASDER = &device_creator; +const device_type NES_NTDEC_FH = &device_creator; + + +nes_ntdec_asder_device::nes_ntdec_asder_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_NTDEC_ASDER, "NES Cart NTDEC Asder PCB", tag, owner, clock, "nes_ntdec_asder", __FILE__) +{ +} + +nes_ntdec_fh_device::nes_ntdec_fh_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_NTDEC_FH, "NES Cart NTDEC Fighting Hero PCB", tag, owner, clock, "nes_ntdec_fh", __FILE__) +{ +} + + + + +void nes_ntdec_asder_device::device_start() +{ + common_start(); + save_item(NAME(m_latch)); +} + +void nes_ntdec_asder_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + + m_latch = 0; +} + +void nes_ntdec_fh_device::device_start() +{ + common_start(); +} + +void nes_ntdec_fh_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32((m_prg_chunks - 1) >> 1); + chr8(0, m_chr_source); + set_nt_mirroring(PPU_MIRROR_VERT); +} + + + + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + NTDEC ASDER Bootleg Board + + Games: Cobra Mission, Fighting Hero III, Huang Di, Master + Shooter + + iNES: mapper 112 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_ntdec_asder_device::write_h) +{ + LOG_MMC(("ntdec_asder write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset) + { + case 0x0000: + m_latch = data & 0x07; + break; + case 0x2000: + switch (m_latch) + { + case 0: + prg8_89(data); + break; + case 1: + prg8_ab(data); + break; + case 2: + data &= 0xfe; + chr1_0(data, CHRROM); + chr1_1(data + 1, CHRROM); + break; + case 3: + data &= 0xfe; + chr1_2(data, CHRROM); + chr1_3(data + 1, CHRROM); + break; + case 4: + chr1_4(data, CHRROM); + break; + case 5: + chr1_5(data, CHRROM); + break; + case 6: + chr1_6(data, CHRROM); + break; + case 7: + chr1_7(data, CHRROM); + break; + } + break; + case 0x6000: + set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + break; + } +} + +/*------------------------------------------------- + + Bootleg Board by NTDEC for Fighting Hero + + Games: Fighting Hero + + Very simple mapper: writes to 0x6000-0x7fff swap PRG and + CHR banks. + + iNES: mapper 193 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_ntdec_fh_device::write_m) +{ + LOG_MMC(("ntdec_fh write_m, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x03) + { + case 0: + chr4_0(data >> 2, CHRROM); + break; + case 1: + chr2_4(data >> 1, CHRROM); + break; + case 2: + chr2_6(data >> 1 , CHRROM); + break; + case 3: + prg8_89(data); + break; + } +} diff --git a/src/devices/bus/nes/nxrom.c b/src/devices/bus/nes/nxrom.c deleted file mode 100644 index 431d384e7f1..00000000000 --- a/src/devices/bus/nes/nxrom.c +++ /dev/null @@ -1,583 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Fabio Priuli -/*********************************************************************************************************** - - - NES/Famicom cartridge emulation for Nintendo xxROM PCBs - - - Here we emulate the following PCBs - - * Nintendo NROM [mapper 0] - * Nintendo AxROM [mapper 7] - * Nintendo BxROM [mapper 34] - * Nintendo CNROM [mapper 3 & 185] - * Nintendo CPROM [mapper 13] - * Nintendo GxROM/MxROM [mapper 66] - * Nintendo UxROM [mapper 2] + Crazy Climbers variant [mapper 180] - * Nintendo UN1ROM [mapper 94] - - Known issues on specific mappers: - - * 000 F1 Race requires more precise PPU timing. It currently has plenty of 1-line glitches. - * 003 Firehouse Rescue has flashing graphics (same PPU issue as Back to the Future 2 & 3?) - * 007 Marble Madness has small graphics corruptions - * 034 Titanic 1912 (pirate BxROM) has missing gfx (same PPU issue of many Waixing titles almost for sure) - - ***********************************************************************************************************/ - - -#include "emu.h" -#include "nxrom.h" - -#include "sound/samples.h" - -#ifdef NES_PCB_DEBUG -#define VERBOSE 1 -#else -#define VERBOSE 0 -#endif - -#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) - - -//------------------------------------------------- -// constructor -//------------------------------------------------- - -const device_type NES_NROM = &device_creator; -const device_type NES_NROM368 = &device_creator; -const device_type NES_FCBASIC = &device_creator; -const device_type NES_AXROM = &device_creator; -const device_type NES_BXROM = &device_creator; -const device_type NES_CNROM = &device_creator; -const device_type NES_CPROM = &device_creator; -const device_type NES_GXROM = &device_creator; -const device_type NES_UXROM = &device_creator; -const device_type NES_UXROM_CC = &device_creator; -const device_type NES_UN1ROM = &device_creator; -const device_type NES_NOCHR = &device_creator; - - -nes_nrom_device::nes_nrom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) - : device_t(mconfig, type, name, tag, owner, clock, shortname, source), - device_nes_cart_interface( mconfig, *this ) -{ -} - -nes_nrom_device::nes_nrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : device_t(mconfig, NES_NROM, "NES Cart NROM PCB", tag, owner, clock, "nes_nrom", __FILE__), - device_nes_cart_interface( mconfig, *this ) -{ -} - -nes_nrom368_device::nes_nrom368_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_NROM368, "NES Cart NROM-368 PCB", tag, owner, clock, "nes_nrom368", __FILE__) -{ -} - -nes_fcbasic_device::nes_fcbasic_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_FCBASIC, "NES Cart Famicom BASIC PCB", tag, owner, clock, "nes_fcbasic", __FILE__) -{ -} - -nes_axrom_device::nes_axrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_AXROM, "NES Cart AxROM PCB", tag, owner, clock, "nes_axrom", __FILE__) -{ -} - -nes_bxrom_device::nes_bxrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_BXROM, "NES Cart BxROM PCB", tag, owner, clock, "nes_bxrom", __FILE__) -{ -} - -nes_cnrom_device::nes_cnrom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) - : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source) -{ -} - -nes_cnrom_device::nes_cnrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_CNROM, "NES Cart CNROM PCB", tag, owner, clock, "nes_cnrom", __FILE__) -{ -} - -nes_cprom_device::nes_cprom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_CPROM, "NES Cart CPROM PCB", tag, owner, clock, "nes_cprom", __FILE__) -{ -} - -nes_gxrom_device::nes_gxrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_GXROM, "NES Cart GxROM PCB", tag, owner, clock, "nes_gxrom", __FILE__) -{ -} - -nes_uxrom_device::nes_uxrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_UXROM, "NES Cart UxROM PCB", tag, owner, clock, "nes_uxrom", __FILE__) -{ -} - -nes_uxrom_cc_device::nes_uxrom_cc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_UXROM_CC, "NES Cart UNROM M5 PCB (Crazy Climber)", tag, owner, clock, "nes_uxrom_cc", __FILE__) -{ -} - -nes_un1rom_device::nes_un1rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_UN1ROM, "NES Cart UN1ROM PCB", tag, owner, clock, "nes_un1rom", __FILE__) -{ -} - -nes_nochr_device::nes_nochr_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_NOCHR, "NES Cart NoCash NOCHR PCB", tag, owner, clock, "nes_nochr", __FILE__) -{ -} - - -void nes_nrom_device::common_start() -{ - // PRG - save_item(NAME(m_prg_bank)); - - // CHR - save_item(NAME(m_chr_source)); - save_item(NAME(m_chr_src)); - save_item(NAME(m_chr_orig)); - - // NT - save_item(NAME(m_mirroring)); - save_item(NAME(m_nt_src)); - save_item(NAME(m_nt_orig)); - save_item(NAME(m_nt_writable)); - - // open bus - save_item(NAME(m_open_bus)); -} - -void nes_nrom_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0); - chr8(0, m_chr_source); -} - -void nes_axrom_device::device_start() -{ - common_start(); -} - -void nes_axrom_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0); - chr8(0, m_chr_source); - - set_nt_mirroring(PPU_MIRROR_LOW); -} - -void nes_bxrom_device::device_start() -{ - common_start(); -} - -void nes_bxrom_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0); - chr8(0, m_chr_source); -} - -void nes_cnrom_device::device_start() -{ - common_start(); - save_item(NAME(m_chr_open_bus)); -} - -void nes_cnrom_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0); - chr8(0, m_chr_source); - - m_chr_open_bus = 0; -} - -void nes_cprom_device::device_start() -{ - common_start(); -} - -void nes_cprom_device::pcb_reset() -{ - m_chr_source = CHRRAM; - prg32(0); - chr4_0(0, m_chr_source); - chr4_4(0, m_chr_source); -} - -void nes_gxrom_device::device_start() -{ - common_start(); -} - -void nes_gxrom_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0); - chr8(0, m_chr_source); -} - -void nes_uxrom_device::device_start() -{ - common_start(); -} - -void nes_uxrom_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(0); - prg16_cdef(m_prg_chunks - 1); - chr8(0, m_chr_source); -} - -void nes_uxrom_cc_device::device_start() -{ - common_start(); -} - -void nes_uxrom_cc_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0); - chr8(0, m_chr_source); -} - -void nes_un1rom_device::device_start() -{ - common_start(); -} - -void nes_un1rom_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(0); - prg16_cdef(m_prg_chunks - 1); - chr8(0, m_chr_source); -} - - -/*------------------------------------------------- - mapper specific handlers - -------------------------------------------------*/ - -/*------------------------------------------------- - - NROM board emulation - - Games: Mario Bros., Super Mario Bros., Tennis and most of - the first generation games - - iNES: mapper 0 - - In MESS: Supported, no need of specific handlers or IRQ - - -------------------------------------------------*/ - -/*------------------------------------------------- - - NROM-368 board emulation - - iNES: mapper 0 with 3xPRG banks - This is an homebrew extension to map linearly 46KB - or PRG in boards with no PRG bankswitch logic - - In MESS: Supported - - -------------------------------------------------*/ - -READ8_MEMBER(nes_nrom368_device::read_l) -{ - LOG_MMC(("nrom368 read_l, offset: %04x\n", offset)); - offset += 0x100; - if (offset >= 0x800) - return m_prg[offset - 0x800]; - else - return m_open_bus; -} - -READ8_MEMBER(nes_nrom368_device::read_m) -{ - LOG_MMC(("nrom368 read_m, offset: %04x\n", offset)); - return m_prg[0x1800 + (offset & 0x1fff)]; -} - -READ8_MEMBER(nes_nrom368_device::read_h) -{ - LOG_MMC(("nrom368 read_h, offset: %04x\n", offset)); - return m_prg[0x3800 + (offset & 0x7fff)]; -} - -/*------------------------------------------------- - - AxROM board emulation - - Games: Arch Rivals, Battletoads, Cabal, Commando, Solstice - - writes to 0x8000-0xffff change PRG banks + sets mirroring - - AMROM has bus conflict - AOROM has generally bus conflict too, but some later pcbs - added some discrete component to disable ROM and avoid - conflicts. No AOROM games is known to glitch due to lack of - bus conflict, so it seems safe to emulate AOROM - without bus conflict. - - iNES: mapper 7 - - In MESS: Supported - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_axrom_device::write_h) -{ - LOG_MMC(("axrom write_h, offset: %04x, data: %02x\n", offset, data)); - - // this pcb is subject to bus conflict - data = account_bus_conflict(offset, data); - - set_nt_mirroring(BIT(data, 4) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW); - prg32(data); -} - -/*------------------------------------------------- - - BxROM board emulation - - writes to 0x8000-0xffff change PRG banks - - iNES: mapper 34 - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_bxrom_device::write_h) -{ - /* This portion of the mapper is nearly identical to Mapper 7, except no one-screen mirroring */ - /* Deadly Towers is really a BxROM game - the demo screens look wrong using mapper 7. */ - LOG_MMC(("bxrom write_h, offset: %04x, data: %02x\n", offset, data)); - - // this pcb is subject to bus conflict, but the same is not true for some pirate variants - data = account_bus_conflict(offset, data); - - prg32(data); -} - -/*------------------------------------------------- - - CNROM board emulation - - Games: B-Wings, Mighty Bomb Jack, Seicross, Spy vs. Spy, - Adventure Island, Flipull, Friday 13th, GeGeGe no - Kitarou, Ghostbusters, Gradius, Hokuto no Ken, Milon's - Secret Castle - - writes to 0x8000-0xffff change CHR 8K banks - - missing BC? - - iNES: mappers 3 & 185 (the latter for games using Pins as - protection) - - Notice that BANDAI_PT554 board (Aerobics Studio) uses very - similar hardware but with an additional sound chip which - gets writes to 0x6000 (currently unemulated in MESS) - - In MESS: Supported - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_cnrom_device::write_h) -{ - LOG_MMC(("cxrom write_h, offset: %04x, data: %02x\n", offset, data)); - - // this pcb is subject to bus conflict, but the same is not true for some pirate variants - data = account_bus_conflict(offset, data); - - if (m_ce_mask) - { - //printf("mask %x state %x\n", m_ce_mask, m_ce_state); - chr8(data & ~m_ce_mask, CHRROM); - - if ((data & m_ce_mask) == m_ce_state) - m_chr_open_bus = 0; - else - m_chr_open_bus = 1; - } - else - chr8(data, CHRROM); -} - -READ8_MEMBER(nes_cnrom_device::chr_r) -{ - int bank = offset >> 10; - - // a few CNROM boards contained copy protection schemes through - // suitably configured diodes, so that subsequent CHR reads can - // give actual VROM content or open bus values. - // For most boards, chr_open_bus remains always zero. - if (m_chr_open_bus) - return m_open_bus; - - return m_chr_access[bank][offset & 0x3ff]; -} - - -/*------------------------------------------------- - - CPROM board emulation - - Games: Videomation - - writes to 0x8000-0xffff change CHR 4K lower banks - - iNES: mapper 13 - - In MESS: Supported - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_cprom_device::write_h) -{ - LOG_MMC(("cprom write_h, offset: %04x, data: %02x\n", offset, data)); - - // this pcb is subject to bus conflict - data = account_bus_conflict(offset, data); - - chr4_4(data, CHRRAM); -} - - -/*------------------------------------------------- - - GxROM/MxROM board emulation - - writes to 0x8000-0xffff change PRG and CHR banks - - iNES: mapper 66 - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_gxrom_device::write_h) -{ - LOG_MMC(("gxrom write_h, offset %04x, data: %02x\n", offset, data)); - - // this pcb is subject to bus conflict - data = account_bus_conflict(offset, data); - - prg32((data & 0xf0) >> 4); - chr8(data & 0x0f, CHRROM); -} - -/*------------------------------------------------- - - UxROM board emulation - - Games: Castlevania, Dragon Quest II, Duck Tales, MegaMan, - Metal Gear - - writes to 0x8000-0xffff change PRG 16K lower banks - - iNES: mapper 2 - - In MESS: Supported. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_uxrom_device::write_h) -{ - LOG_MMC(("uxrom write_h, offset: %04x, data: %02x\n", offset, data)); - - // this pcb is subject to bus conflict - data = account_bus_conflict(offset, data); - - prg16_89ab(data); -} - -/*------------------------------------------------- - - Nihon Bussan UNROM M5 - - Games: Crazy Climber Jpn - - Very simple mapper: prg16_89ab is always set to bank 0, - while prg16_cdef is set by writes to 0x8000-0xffff. The game - uses a custom controller. - - iNES: mapper 180 - - In MESS: Supported. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_uxrom_cc_device::write_h) -{ - LOG_MMC(("uxrom_cc write_h, offset: %04x, data: %02x\n", offset, data)); - - prg16_cdef(data); -} - -/*------------------------------------------------- - - UN1ROM board emulation - - Games: Senjou no Okami - - writes to 0x8000-0xffff change PRG 16K lower banks - - iNES: mapper 94 - - In MESS: Supported. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_un1rom_device::write_h) -{ - LOG_MMC(("un1rom write_h, offset: %04x, data: %02x\n", offset, data)); - - // this pcb is subject to bus conflict - data = account_bus_conflict(offset, data); - - prg16_89ab(data >> 2); -} - -/*------------------------------------------------- - - NoCash NOCHR board emulation - - This is an homebrew PCB design on a single chip - (+possibly CIC) which uses the NTRAM as CHRRAM! - - iNES: mapper 218 - - In MESS: Supported. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_nochr_device::chr_w) -{ - int mirr = get_mirroring(); - if (mirr == PPU_MIRROR_HIGH) - m_ciram[(offset & 0x3ff) + 0x000] = data; - else if (mirr == PPU_MIRROR_LOW) - m_ciram[(offset & 0x3ff) + 0x400] = data; - else - m_ciram[offset & 0x7ff] = data; // not sure here, since there is no software to test... -} - -READ8_MEMBER(nes_nochr_device::chr_r) -{ - int mirr = get_mirroring(); - if (mirr == PPU_MIRROR_HIGH) - return m_ciram[(offset & 0x3ff) + 0x000]; - else if (mirr == PPU_MIRROR_LOW) - return m_ciram[(offset & 0x3ff) + 0x400]; - else - return m_ciram[offset & 0x7ff]; // not sure here, since there is no software to test... -} diff --git a/src/devices/bus/nes/nxrom.cpp b/src/devices/bus/nes/nxrom.cpp new file mode 100644 index 00000000000..431d384e7f1 --- /dev/null +++ b/src/devices/bus/nes/nxrom.cpp @@ -0,0 +1,583 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for Nintendo xxROM PCBs + + + Here we emulate the following PCBs + + * Nintendo NROM [mapper 0] + * Nintendo AxROM [mapper 7] + * Nintendo BxROM [mapper 34] + * Nintendo CNROM [mapper 3 & 185] + * Nintendo CPROM [mapper 13] + * Nintendo GxROM/MxROM [mapper 66] + * Nintendo UxROM [mapper 2] + Crazy Climbers variant [mapper 180] + * Nintendo UN1ROM [mapper 94] + + Known issues on specific mappers: + + * 000 F1 Race requires more precise PPU timing. It currently has plenty of 1-line glitches. + * 003 Firehouse Rescue has flashing graphics (same PPU issue as Back to the Future 2 & 3?) + * 007 Marble Madness has small graphics corruptions + * 034 Titanic 1912 (pirate BxROM) has missing gfx (same PPU issue of many Waixing titles almost for sure) + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "nxrom.h" + +#include "sound/samples.h" + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_NROM = &device_creator; +const device_type NES_NROM368 = &device_creator; +const device_type NES_FCBASIC = &device_creator; +const device_type NES_AXROM = &device_creator; +const device_type NES_BXROM = &device_creator; +const device_type NES_CNROM = &device_creator; +const device_type NES_CPROM = &device_creator; +const device_type NES_GXROM = &device_creator; +const device_type NES_UXROM = &device_creator; +const device_type NES_UXROM_CC = &device_creator; +const device_type NES_UN1ROM = &device_creator; +const device_type NES_NOCHR = &device_creator; + + +nes_nrom_device::nes_nrom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_nes_cart_interface( mconfig, *this ) +{ +} + +nes_nrom_device::nes_nrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, NES_NROM, "NES Cart NROM PCB", tag, owner, clock, "nes_nrom", __FILE__), + device_nes_cart_interface( mconfig, *this ) +{ +} + +nes_nrom368_device::nes_nrom368_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_NROM368, "NES Cart NROM-368 PCB", tag, owner, clock, "nes_nrom368", __FILE__) +{ +} + +nes_fcbasic_device::nes_fcbasic_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_FCBASIC, "NES Cart Famicom BASIC PCB", tag, owner, clock, "nes_fcbasic", __FILE__) +{ +} + +nes_axrom_device::nes_axrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_AXROM, "NES Cart AxROM PCB", tag, owner, clock, "nes_axrom", __FILE__) +{ +} + +nes_bxrom_device::nes_bxrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_BXROM, "NES Cart BxROM PCB", tag, owner, clock, "nes_bxrom", __FILE__) +{ +} + +nes_cnrom_device::nes_cnrom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +nes_cnrom_device::nes_cnrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_CNROM, "NES Cart CNROM PCB", tag, owner, clock, "nes_cnrom", __FILE__) +{ +} + +nes_cprom_device::nes_cprom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_CPROM, "NES Cart CPROM PCB", tag, owner, clock, "nes_cprom", __FILE__) +{ +} + +nes_gxrom_device::nes_gxrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_GXROM, "NES Cart GxROM PCB", tag, owner, clock, "nes_gxrom", __FILE__) +{ +} + +nes_uxrom_device::nes_uxrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_UXROM, "NES Cart UxROM PCB", tag, owner, clock, "nes_uxrom", __FILE__) +{ +} + +nes_uxrom_cc_device::nes_uxrom_cc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_UXROM_CC, "NES Cart UNROM M5 PCB (Crazy Climber)", tag, owner, clock, "nes_uxrom_cc", __FILE__) +{ +} + +nes_un1rom_device::nes_un1rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_UN1ROM, "NES Cart UN1ROM PCB", tag, owner, clock, "nes_un1rom", __FILE__) +{ +} + +nes_nochr_device::nes_nochr_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_NOCHR, "NES Cart NoCash NOCHR PCB", tag, owner, clock, "nes_nochr", __FILE__) +{ +} + + +void nes_nrom_device::common_start() +{ + // PRG + save_item(NAME(m_prg_bank)); + + // CHR + save_item(NAME(m_chr_source)); + save_item(NAME(m_chr_src)); + save_item(NAME(m_chr_orig)); + + // NT + save_item(NAME(m_mirroring)); + save_item(NAME(m_nt_src)); + save_item(NAME(m_nt_orig)); + save_item(NAME(m_nt_writable)); + + // open bus + save_item(NAME(m_open_bus)); +} + +void nes_nrom_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + +void nes_axrom_device::device_start() +{ + common_start(); +} + +void nes_axrom_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); + + set_nt_mirroring(PPU_MIRROR_LOW); +} + +void nes_bxrom_device::device_start() +{ + common_start(); +} + +void nes_bxrom_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + +void nes_cnrom_device::device_start() +{ + common_start(); + save_item(NAME(m_chr_open_bus)); +} + +void nes_cnrom_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); + + m_chr_open_bus = 0; +} + +void nes_cprom_device::device_start() +{ + common_start(); +} + +void nes_cprom_device::pcb_reset() +{ + m_chr_source = CHRRAM; + prg32(0); + chr4_0(0, m_chr_source); + chr4_4(0, m_chr_source); +} + +void nes_gxrom_device::device_start() +{ + common_start(); +} + +void nes_gxrom_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + +void nes_uxrom_device::device_start() +{ + common_start(); +} + +void nes_uxrom_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); +} + +void nes_uxrom_cc_device::device_start() +{ + common_start(); +} + +void nes_uxrom_cc_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + +void nes_un1rom_device::device_start() +{ + common_start(); +} + +void nes_un1rom_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); +} + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + NROM board emulation + + Games: Mario Bros., Super Mario Bros., Tennis and most of + the first generation games + + iNES: mapper 0 + + In MESS: Supported, no need of specific handlers or IRQ + + -------------------------------------------------*/ + +/*------------------------------------------------- + + NROM-368 board emulation + + iNES: mapper 0 with 3xPRG banks + This is an homebrew extension to map linearly 46KB + or PRG in boards with no PRG bankswitch logic + + In MESS: Supported + + -------------------------------------------------*/ + +READ8_MEMBER(nes_nrom368_device::read_l) +{ + LOG_MMC(("nrom368 read_l, offset: %04x\n", offset)); + offset += 0x100; + if (offset >= 0x800) + return m_prg[offset - 0x800]; + else + return m_open_bus; +} + +READ8_MEMBER(nes_nrom368_device::read_m) +{ + LOG_MMC(("nrom368 read_m, offset: %04x\n", offset)); + return m_prg[0x1800 + (offset & 0x1fff)]; +} + +READ8_MEMBER(nes_nrom368_device::read_h) +{ + LOG_MMC(("nrom368 read_h, offset: %04x\n", offset)); + return m_prg[0x3800 + (offset & 0x7fff)]; +} + +/*------------------------------------------------- + + AxROM board emulation + + Games: Arch Rivals, Battletoads, Cabal, Commando, Solstice + + writes to 0x8000-0xffff change PRG banks + sets mirroring + + AMROM has bus conflict + AOROM has generally bus conflict too, but some later pcbs + added some discrete component to disable ROM and avoid + conflicts. No AOROM games is known to glitch due to lack of + bus conflict, so it seems safe to emulate AOROM + without bus conflict. + + iNES: mapper 7 + + In MESS: Supported + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_axrom_device::write_h) +{ + LOG_MMC(("axrom write_h, offset: %04x, data: %02x\n", offset, data)); + + // this pcb is subject to bus conflict + data = account_bus_conflict(offset, data); + + set_nt_mirroring(BIT(data, 4) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW); + prg32(data); +} + +/*------------------------------------------------- + + BxROM board emulation + + writes to 0x8000-0xffff change PRG banks + + iNES: mapper 34 + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_bxrom_device::write_h) +{ + /* This portion of the mapper is nearly identical to Mapper 7, except no one-screen mirroring */ + /* Deadly Towers is really a BxROM game - the demo screens look wrong using mapper 7. */ + LOG_MMC(("bxrom write_h, offset: %04x, data: %02x\n", offset, data)); + + // this pcb is subject to bus conflict, but the same is not true for some pirate variants + data = account_bus_conflict(offset, data); + + prg32(data); +} + +/*------------------------------------------------- + + CNROM board emulation + + Games: B-Wings, Mighty Bomb Jack, Seicross, Spy vs. Spy, + Adventure Island, Flipull, Friday 13th, GeGeGe no + Kitarou, Ghostbusters, Gradius, Hokuto no Ken, Milon's + Secret Castle + + writes to 0x8000-0xffff change CHR 8K banks + + missing BC? + + iNES: mappers 3 & 185 (the latter for games using Pins as + protection) + + Notice that BANDAI_PT554 board (Aerobics Studio) uses very + similar hardware but with an additional sound chip which + gets writes to 0x6000 (currently unemulated in MESS) + + In MESS: Supported + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_cnrom_device::write_h) +{ + LOG_MMC(("cxrom write_h, offset: %04x, data: %02x\n", offset, data)); + + // this pcb is subject to bus conflict, but the same is not true for some pirate variants + data = account_bus_conflict(offset, data); + + if (m_ce_mask) + { + //printf("mask %x state %x\n", m_ce_mask, m_ce_state); + chr8(data & ~m_ce_mask, CHRROM); + + if ((data & m_ce_mask) == m_ce_state) + m_chr_open_bus = 0; + else + m_chr_open_bus = 1; + } + else + chr8(data, CHRROM); +} + +READ8_MEMBER(nes_cnrom_device::chr_r) +{ + int bank = offset >> 10; + + // a few CNROM boards contained copy protection schemes through + // suitably configured diodes, so that subsequent CHR reads can + // give actual VROM content or open bus values. + // For most boards, chr_open_bus remains always zero. + if (m_chr_open_bus) + return m_open_bus; + + return m_chr_access[bank][offset & 0x3ff]; +} + + +/*------------------------------------------------- + + CPROM board emulation + + Games: Videomation + + writes to 0x8000-0xffff change CHR 4K lower banks + + iNES: mapper 13 + + In MESS: Supported + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_cprom_device::write_h) +{ + LOG_MMC(("cprom write_h, offset: %04x, data: %02x\n", offset, data)); + + // this pcb is subject to bus conflict + data = account_bus_conflict(offset, data); + + chr4_4(data, CHRRAM); +} + + +/*------------------------------------------------- + + GxROM/MxROM board emulation + + writes to 0x8000-0xffff change PRG and CHR banks + + iNES: mapper 66 + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_gxrom_device::write_h) +{ + LOG_MMC(("gxrom write_h, offset %04x, data: %02x\n", offset, data)); + + // this pcb is subject to bus conflict + data = account_bus_conflict(offset, data); + + prg32((data & 0xf0) >> 4); + chr8(data & 0x0f, CHRROM); +} + +/*------------------------------------------------- + + UxROM board emulation + + Games: Castlevania, Dragon Quest II, Duck Tales, MegaMan, + Metal Gear + + writes to 0x8000-0xffff change PRG 16K lower banks + + iNES: mapper 2 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_uxrom_device::write_h) +{ + LOG_MMC(("uxrom write_h, offset: %04x, data: %02x\n", offset, data)); + + // this pcb is subject to bus conflict + data = account_bus_conflict(offset, data); + + prg16_89ab(data); +} + +/*------------------------------------------------- + + Nihon Bussan UNROM M5 + + Games: Crazy Climber Jpn + + Very simple mapper: prg16_89ab is always set to bank 0, + while prg16_cdef is set by writes to 0x8000-0xffff. The game + uses a custom controller. + + iNES: mapper 180 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_uxrom_cc_device::write_h) +{ + LOG_MMC(("uxrom_cc write_h, offset: %04x, data: %02x\n", offset, data)); + + prg16_cdef(data); +} + +/*------------------------------------------------- + + UN1ROM board emulation + + Games: Senjou no Okami + + writes to 0x8000-0xffff change PRG 16K lower banks + + iNES: mapper 94 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_un1rom_device::write_h) +{ + LOG_MMC(("un1rom write_h, offset: %04x, data: %02x\n", offset, data)); + + // this pcb is subject to bus conflict + data = account_bus_conflict(offset, data); + + prg16_89ab(data >> 2); +} + +/*------------------------------------------------- + + NoCash NOCHR board emulation + + This is an homebrew PCB design on a single chip + (+possibly CIC) which uses the NTRAM as CHRRAM! + + iNES: mapper 218 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_nochr_device::chr_w) +{ + int mirr = get_mirroring(); + if (mirr == PPU_MIRROR_HIGH) + m_ciram[(offset & 0x3ff) + 0x000] = data; + else if (mirr == PPU_MIRROR_LOW) + m_ciram[(offset & 0x3ff) + 0x400] = data; + else + m_ciram[offset & 0x7ff] = data; // not sure here, since there is no software to test... +} + +READ8_MEMBER(nes_nochr_device::chr_r) +{ + int mirr = get_mirroring(); + if (mirr == PPU_MIRROR_HIGH) + return m_ciram[(offset & 0x3ff) + 0x000]; + else if (mirr == PPU_MIRROR_LOW) + return m_ciram[(offset & 0x3ff) + 0x400]; + else + return m_ciram[offset & 0x7ff]; // not sure here, since there is no software to test... +} diff --git a/src/devices/bus/nes/pirate.c b/src/devices/bus/nes/pirate.c deleted file mode 100644 index 557831ed144..00000000000 --- a/src/devices/bus/nes/pirate.c +++ /dev/null @@ -1,1387 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Fabio Priuli -/*********************************************************************************************************** - - - NES/Famicom cartridge emulation for pirate cart PCBs - - - Here we emulate the various PCBs used by Asian & Korean pirate games - - TODO: - - Are the scrolling glitches (check status bar) in Magic Dragon correct? FWIW, NEStopia behaves similarly - - ***********************************************************************************************************/ - - -#include "emu.h" -#include "pirate.h" - -#include "cpu/m6502/m6502.h" -#include "video/ppu2c0x.h" // this has to be included so that IRQ functions can access PPU_BOTTOM_VISIBLE_SCANLINE - - -#ifdef NES_PCB_DEBUG -#define VERBOSE 1 -#else -#define VERBOSE 0 -#endif - -#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) - - -//------------------------------------------------- -// constructor -//------------------------------------------------- - -const device_type NES_AGCI_50282 = &device_creator; -const device_type NES_DREAMTECH01 = &device_creator; -const device_type NES_FUKUTAKE = &device_creator; -const device_type NES_FUTUREMEDIA = &device_creator; -const device_type NES_MAGSERIES = &device_creator; -const device_type NES_DAOU306 = &device_creator; -const device_type NES_SUBOR0 = &device_creator; -const device_type NES_SUBOR1 = &device_creator; -const device_type NES_CC21 = &device_creator; -const device_type NES_XIAOZY = &device_creator; -const device_type NES_EDU2K = &device_creator; -const device_type NES_T230 = &device_creator; -const device_type NES_MK2 = &device_creator; -const device_type NES_WHERO = &device_creator; -const device_type NES_43272 = &device_creator; -const device_type NES_TF1201 = &device_creator; -const device_type NES_CITYFIGHT = &device_creator; - - -nes_agci_device::nes_agci_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_AGCI_50282, "NES Cart AGCI 50282 PCB", tag, owner, clock, "nes_agci50282", __FILE__) -{ -} - -nes_dreamtech_device::nes_dreamtech_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_DREAMTECH01, "NES Cart Dreamtech01 PCB", tag, owner, clock, "nes_dreamtech", __FILE__) -{ -} - -nes_fukutake_device::nes_fukutake_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_FUKUTAKE, "NES Cart Fukutake Study Box PCB", tag, owner, clock, "nes_fukutake", __FILE__) -{ -} - -nes_futuremedia_device::nes_futuremedia_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_FUTUREMEDIA, "NES Cart FutureMedia PCB", tag, owner, clock, "nes_futuremedia", __FILE__) -{ -} - -nes_magseries_device::nes_magseries_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_MAGSERIES, "NES Cart Magical Series PCB", tag, owner, clock, "nes_magseries", __FILE__) -{ -} - -nes_daou306_device::nes_daou306_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_DAOU306, "NES Cart Daou 306 PCB", tag, owner, clock, "nes_daou306", __FILE__) -{ -} - -nes_subor0_device::nes_subor0_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_SUBOR0, "NES Cart Subor Type 0 PCB", tag, owner, clock, "nes_subor0", __FILE__) -{ -} - -nes_subor1_device::nes_subor1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_SUBOR1, "NES Cart Subor Type 1 PCB", tag, owner, clock, "nes_subor1", __FILE__) -{ -} - -nes_cc21_device::nes_cc21_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_CC21, "NES Cart CC-21 PCB", tag, owner, clock, "nes_cc21", __FILE__) -{ -} - -nes_xiaozy_device::nes_xiaozy_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_XIAOZY, "NES Cart Xiao Zhuan Yuan PCB", tag, owner, clock, "nes_xiaozy", __FILE__) -{ -} - -nes_edu2k_device::nes_edu2k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_EDU2K, "NES Cart Educational Computer 2000 PCB", tag, owner, clock, "nes_edu2k", __FILE__) -{ -} - -nes_t230_device::nes_t230_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_T230, "NES Cart T-230 PCB", tag, owner, clock, "nes_t230", __FILE__) -{ -} - -nes_mk2_device::nes_mk2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_MK2, "NES Cart Mortal Kombat 2 PCB", tag, owner, clock, "nes_mk2", __FILE__) -{ -} - -nes_whero_device::nes_whero_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_WHERO, "NES Cart World Heroes PCB", tag, owner, clock, "nes_whero", __FILE__) -{ -} - -nes_43272_device::nes_43272_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_43272, "NES Cart UNL-43272 PCB", tag, owner, clock, "nes_43272", __FILE__) -{ -} - -nes_tf1201_device::nes_tf1201_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_TF1201, "NES Cart UNL-TF1201 PCB", tag, owner, clock, "nes_tf1201", __FILE__) -{ -} - -nes_cityfight_device::nes_cityfight_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_TF1201, "NES Cart City Fighter PCB", tag, owner, clock, "nes_cityfight", __FILE__) -{ -} - - - - -void nes_agci_device::device_start() -{ - common_start(); -} - -void nes_agci_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0); - chr8(0, m_chr_source); -} - -void nes_dreamtech_device::device_start() -{ - common_start(); -} - -void nes_dreamtech_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(0); - prg16_cdef(8); - chr8(0, m_chr_source); -} - -void nes_fukutake_device::device_start() -{ - common_start(); - save_item(NAME(m_latch)); - - // 2816 (?) bytes of RAM - save_item(NAME(m_ram)); -} - -void nes_fukutake_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(0); - prg16_cdef(0); - chr8(0, m_chr_source); - - m_latch = 0; -} - -void nes_futuremedia_device::device_start() -{ - common_start(); - save_item(NAME(m_irq_clear)); - save_item(NAME(m_irq_enable)); - save_item(NAME(m_irq_count)); - save_item(NAME(m_irq_count_latch)); -} - -void nes_futuremedia_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(0); - prg16_cdef(m_prg_chunks - 1); - chr8(0, m_chr_source); - - m_irq_clear = 0; - m_irq_enable = 0; - m_irq_count = m_irq_count_latch = 0; -} - -void nes_magseries_device::device_start() -{ - common_start(); -} - -void nes_magseries_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0); - chr8(0, m_chr_source); -} - -void nes_daou306_device::device_start() -{ - common_start(); - save_item(NAME(m_reg)); -} - -void nes_daou306_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(m_prg_chunks - 2); - prg16_cdef(m_prg_chunks - 1); - chr8(0, m_chr_source); - set_nt_mirroring(PPU_MIRROR_LOW); - - memset(m_reg, 0, sizeof(m_reg)); -} - -void nes_subor0_device::device_start() -{ - common_start(); - save_item(NAME(m_reg)); -} - -void nes_subor0_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(0); - prg16_cdef(0x20); - chr8(0, m_chr_source); - - memset(m_reg, 0, sizeof(m_reg)); -} - -void nes_subor1_device::device_start() -{ - common_start(); - save_item(NAME(m_reg)); -} - -void nes_subor1_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(0); - prg16_cdef(0x07); - chr8(0, m_chr_source); - - memset(m_reg, 0, sizeof(m_reg)); -} - -void nes_cc21_device::device_start() -{ - common_start(); -} - -void nes_cc21_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0); - chr8(0, m_chr_source); -} - -void nes_xiaozy_device::device_start() -{ - common_start(); -} - -void nes_xiaozy_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32((m_prg_chunks - 1) >> 1); - chr8(0, m_chr_source); -} - -void nes_edu2k_device::device_start() -{ - common_start(); - save_item(NAME(m_latch)); -} - -void nes_edu2k_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0); - chr8(0, m_chr_source); - - m_latch = 0; -} - -void nes_t230_device::device_start() -{ - common_start(); - save_item(NAME(m_irq_mode)); - save_item(NAME(m_irq_enable)); - save_item(NAME(m_irq_enable_latch)); - save_item(NAME(m_irq_count)); - save_item(NAME(m_irq_count_latch)); - save_item(NAME(m_mmc_vrom_bank)); -} - -void nes_t230_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(0); - prg16_cdef(m_prg_chunks - 1); - chr8(0, m_chr_source); - - m_irq_mode = 0; - m_irq_enable = m_irq_enable_latch = 0; - m_irq_count = m_irq_count_latch = 0; - - memset(m_mmc_vrom_bank, 0, sizeof(m_mmc_vrom_bank)); -} - -void nes_mk2_device::device_start() -{ - common_start(); - save_item(NAME(m_irq_clear)); - save_item(NAME(m_irq_enable)); - save_item(NAME(m_irq_count)); - save_item(NAME(m_irq_count_latch)); -} - -void nes_mk2_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(m_prg_chunks - 1); - prg16_cdef(m_prg_chunks - 1); - chr8(0, m_chr_source); - set_nt_mirroring(PPU_MIRROR_VERT); - - m_irq_clear = 0; - m_irq_enable = 0; - m_irq_count = m_irq_count_latch = 0; -} - - -void nes_whero_device::device_start() -{ - common_start(); - save_item(NAME(m_irq_enable)); - save_item(NAME(m_irq_enable_latch)); - save_item(NAME(m_irq_count)); - save_item(NAME(m_irq_count_latch)); - save_item(NAME(m_reg)); - save_item(NAME(m_mmc_vrom_bank)); -} - -void nes_whero_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(0); - prg16_cdef(m_prg_chunks - 1); - chr8(0x100, m_chr_source); - - m_irq_enable = 0; - m_irq_enable_latch = 0; - m_irq_count = 0; - m_irq_count_latch = 0; - - m_reg = 0; - memset(m_mmc_vrom_bank, 0, sizeof(m_mmc_vrom_bank)); -} - -void nes_43272_device::device_start() -{ - common_start(); - save_item(NAME(m_latch)); -} - -void nes_43272_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32((m_prg_chunks - 1) >> 1); - chr8(0, m_chr_source); - - m_latch = 0x81; -} - -void nes_tf1201_device::device_start() -{ - common_start(); - save_item(NAME(m_prg)); - save_item(NAME(m_swap)); - save_item(NAME(m_irq_enable)); - save_item(NAME(m_irq_enable_latch)); - save_item(NAME(m_irq_count)); - save_item(NAME(m_mmc_vrom_bank)); -} - -void nes_tf1201_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(0); - prg16_cdef(m_prg_chunks - 1); - chr8(0, m_chr_source); - - memset(m_mmc_vrom_bank, 0, sizeof(m_mmc_vrom_bank)); - m_prg = 0; - m_swap = 0; - m_irq_enable = 0; - m_irq_enable_latch = 0; - m_irq_count = 0; -} - -void nes_cityfight_device::device_start() -{ - common_start(); - irq_timer = timer_alloc(TIMER_IRQ); - irq_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1)); - - save_item(NAME(m_prg_reg)); - save_item(NAME(m_prg_mode)); - save_item(NAME(m_irq_enable)); - save_item(NAME(m_irq_count)); - save_item(NAME(m_mmc_vrom_bank)); -} - -void nes_cityfight_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(0); - prg16_cdef(m_prg_chunks - 1); - chr8(0, m_chr_source); - - memset(m_mmc_vrom_bank, 0, sizeof(m_mmc_vrom_bank)); - m_prg_reg = 0; - m_prg_mode = 0; - m_irq_enable = 0; - m_irq_count = 0; -} - - - -/*------------------------------------------------- - mapper specific handlers - -------------------------------------------------*/ - -/*------------------------------------------------- - - AGCI 50282 bootleg board emulation - - Games: Death Race - - iNES: mapper 144 - - In MESS: Supported. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_agci_device::write_h) -{ - LOG_MMC(("agci write_h, offset: %04x, data: %02x\n", offset, data)); - - // this pcb is subject to bus conflict - UINT8 temp = account_bus_conflict(offset, 0xff); - data = (data & temp) | (temp & 1); - - chr8(data >> 4, CHRROM); - prg32(data); -} - -/*------------------------------------------------- - - Board DREAMTECH01 - - Games: Korean Igo - - In MESS: Supported - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_dreamtech_device::write_l) -{ - LOG_MMC(("dreamtech write_l, offset: %04x, data: %02x\n", offset, data)); - offset += 0x100; - - if (offset == 0x1020) /* 0x5020 */ - prg16_89ab(data); -} - -/*------------------------------------------------- - - Bootleg Board by Fukutake - - Games: Study Box - - iNES: mapper 186 - - In MESS: Unsupported. - - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_fukutake_device::write_l) -{ - LOG_MMC(("fukutake write_l, offset: %04x, data: %02x\n", offset, data)); - offset += 0x100; - - if (offset >= 0x200 && offset < 0x400) - { - if (offset & 1) - prg16_89ab(data); - else - m_latch = data >> 6; - } - else if (offset >= 0x400 && offset < 0xf00) - m_ram[offset - 0x400] = data; -} - -READ8_MEMBER(nes_fukutake_device::read_l) -{ - LOG_MMC(("fukutake read_l, offset: %04x\n", offset)); - offset += 0x100; - - if (offset >= 0x200 && offset < 0x400) - { - if (offset == 0x200 || offset == 0x201 || offset == 0x203) - return 0x00; - else if (offset == 0x202) - return 0x40; - else - return 0xff; - } - else if (offset >= 0x400 && offset < 0xf00) - return m_ram[offset - 0x400]; - - return 0; -} - -WRITE8_MEMBER(nes_fukutake_device::write_m) -{ - LOG_MMC(("fukutake write_m, offset: %04x, data: %02x\n", offset, data)); - m_prgram[((m_latch * 0x2000) + offset) & (m_prgram.size() - 1)] = data; -} - -READ8_MEMBER(nes_fukutake_device::read_m) -{ - LOG_MMC(("fukutake read_m, offset: %04x\n", offset)); - return m_prgram[((m_latch * 0x2000) + offset) & (m_prgram.size() - 1)]; -} - -/*------------------------------------------------- - - Bootleg Board by Future Media - - Games: Crayon Shin-chan (C), San Guo Zhi 4 - Chi Bi Feng Yun - - iNES: mapper 117 - - In MESS: Unsupported. - - -------------------------------------------------*/ - -void nes_futuremedia_device::hblank_irq(int scanline, int vblank, int blanked) -{ - // if (scanline < PPU_BOTTOM_VISIBLE_SCANLINE) - { - if (m_irq_enable && m_irq_count) - { - m_irq_count--; - if (!m_irq_count) - m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE); - } - } -} - -WRITE8_MEMBER(nes_futuremedia_device::write_h) -{ - LOG_MMC(("futuremedia write_h, offset: %04x, data: %02x\n", offset, data)); - - switch (offset) - { - case 0x0000: - prg8_89(data); - break; - case 0x0001: - prg8_ab(data); - break; - case 0x0002: - prg8_cd(data); - break; - case 0x0003: - prg8_ef(data); - break; - case 0x2000: - case 0x2001: - case 0x2002: - case 0x2003: - case 0x2004: - case 0x2005: - case 0x2006: - case 0x2007: - chr1_x(offset & 0x07, data, CHRROM); - break; - - case 0x5000: - set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); - break; - - case 0x4001: - m_irq_count_latch = data; - break; - case 0x4002: - // IRQ cleared - break; - case 0x4003: - m_irq_count = m_irq_count_latch; - break; - case 0x6000: - m_irq_enable = data & 0x01; - break; - } -} - -/*------------------------------------------------- - - Bootleg Board by Magic Series - - Games: Magic Dragon - - Very simple mapper: writes to 0x8000-0xffff set prg32 and chr8 - banks - - iNES: mapper 107 - - In MESS: Supported. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_magseries_device::write_h) -{ - LOG_MMC(("magseries write_h, offset: %04x, data: %02x\n", offset, data)); - - prg32(data >> 1); - chr8(data, CHRROM); -} - -/*------------------------------------------------- - - Open Corp DAOU306 board - - Games: Metal Force (K) - - iNES: mapper 156 - - In MESS: Supported. - - Notes: Metal Force and Buzz & Waldog only use the first 4 - regs and no mirroring. Janggun ui Adeul uses all features - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_daou306_device::write_h) -{ - LOG_MMC(("daou306 write_h, offset: %04x, data: %02x\n", offset, data)); - int reg = BIT(offset, 2) ? 8 : 0; - - switch (offset) - { - case 0x4000: - case 0x4004: - m_reg[reg + 0] = data; - chr1_0(m_reg[0] | (m_reg[8] << 8), CHRROM); - break; - case 0x4001: - case 0x4005: - m_reg[reg + 1] = data; - chr1_1(m_reg[1] | (m_reg[9] << 8), CHRROM); - break; - case 0x4002: - case 0x4006: - m_reg[reg + 2] = data; - chr1_2(m_reg[2] | (m_reg[10] << 8), CHRROM); - break; - case 0x4003: - case 0x4007: - m_reg[reg + 3] = data; - chr1_3(m_reg[3] | (m_reg[11] << 8), CHRROM); - break; - case 0x4008: - case 0x400c: - m_reg[reg + 4] = data; - chr1_4(m_reg[4] | (m_reg[12] << 8), CHRROM); - break; - case 0x4009: - case 0x400d: - m_reg[reg + 5] = data; - chr1_5(m_reg[5] | (m_reg[13] << 8), CHRROM); - break; - case 0x400a: - case 0x400e: - m_reg[reg + 6] = data; - chr1_6(m_reg[6] | (m_reg[14] << 8), CHRROM); - break; - case 0x400b: - case 0x400f: - m_reg[reg + 7] = data; - chr1_7(m_reg[7] | (m_reg[15] << 8), CHRROM); - break; - case 0x4010: - prg16_89ab(data); - break; - case 0x4014: - if (data & 1) - set_nt_mirroring(PPU_MIRROR_HORZ); - else - set_nt_mirroring(PPU_MIRROR_VERT); - break; - } -} - -/*------------------------------------------------- - - Subor bootleg board Type 0 - - iNES: mapper 167 - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_subor0_device::write_h) -{ - UINT8 subor_helper1, subor_helper2; - LOG_MMC(("subor0 write_h, offset: %04x, data: %02x\n", offset, data)); - - m_reg[(offset >> 13) & 0x03] = data; - subor_helper1 = ((m_reg[0] ^ m_reg[1]) << 1) & 0x20; - subor_helper2 = ((m_reg[2] ^ m_reg[3]) << 0) & 0x1f; - - if (m_reg[1] & 0x08) - { - subor_helper1 += subor_helper2 & 0xfe; - subor_helper2 = subor_helper1; - subor_helper1 += 1; - } - else if (m_reg[1] & 0x04) - { - subor_helper2 += subor_helper1; - subor_helper1 = 0x1f; - } - else - { - subor_helper1 += subor_helper2; - subor_helper2 = 0x20; - } - - prg16_89ab(subor_helper1); - prg16_cdef(subor_helper2); -} - -/*------------------------------------------------- - - Subor bootleg board Type 1 - - iNES: mapper 166 - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_subor1_device::write_h) -{ - UINT8 subor_helper1, subor_helper2; - LOG_MMC(("subor1 write_h, offset: %04x, data: %02x\n", offset, data)); - - m_reg[(offset >> 13) & 0x03] = data; - subor_helper1 = ((m_reg[0] ^ m_reg[1]) << 1) & 0x20; - subor_helper2 = ((m_reg[2] ^ m_reg[3]) << 0) & 0x1f; - - if (m_reg[1] & 0x08) - { - subor_helper1 += subor_helper2 & 0xfe; - subor_helper2 = subor_helper1; - subor_helper2 += 1; - } - else if (m_reg[1] & 0x04) - { - subor_helper2 += subor_helper1; - subor_helper1 = 0x1f; - } - else - { - subor_helper1 += subor_helper2; - subor_helper2 = 0x07; - } - - prg16_89ab(subor_helper1); - prg16_cdef(subor_helper2); -} - -/*------------------------------------------------- - - Board UNL-CC-21 - - Games: Mi Hun Che - - In MESS: Supported - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_cc21_device::write_h) -{ - LOG_MMC(("cc21 write_h, offset: %04x, data: %02x\n", offset, data)); - - set_nt_mirroring(BIT(offset, 1) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW); - chr8((offset & 0x01), CHRROM); -} - -/*------------------------------------------------- - - Bootleg Board for Xiao Zhuan Yuan - - Games: Shu Qi Yu - Zhi Li Xiao Zhuan Yuan - - Very simple mapper: writes to 0x5ff1 set prg32 (to data>>1), - while writes to 0x5ff2 set chr8 - - iNES: mapper 176 - - In MESS: Supported. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_xiaozy_device::write_l) -{ - LOG_MMC(("xiaozy write_l, offset: %04x, data: %02x\n", offset, data)); - - switch (offset) - { - case 0x1ef1: /* 0x5ff1 */ - prg32(data >> 1); - break; - case 0x1ef2: /* 0x5ff2 */ - chr8(data, CHRROM); - break; - } -} - -/*------------------------------------------------- - - UNL-EDU2000 - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_edu2k_device::write_h) -{ - LOG_MMC(("edu2k write_h, offset: %04x, data: %02x\n", offset, data)); - - prg32(data & 0x1f); - m_latch = (data & 0xc0) >> 6; -} - -WRITE8_MEMBER(nes_edu2k_device::write_m) -{ - LOG_MMC(("edu2k write_m, offset: %04x, data: %02x\n", offset, data)); - m_prgram[((m_latch * 0x2000) + offset) & (m_prgram.size() - 1)] = data; -} - -READ8_MEMBER(nes_edu2k_device::read_m) -{ - LOG_MMC(("edu2k read_m, offset: %04x\n", offset)); - return m_prgram[((m_latch * 0x2000) + offset) & (m_prgram.size() - 1)]; -} - -/*------------------------------------------------- - - Board UNL-T-230 - - Games: Dragon Ball Z IV (Unl) - - This mapper appears to be similar to Konami VRC-2 - but the game has no VROM and only 1 VRAM bank, so we - completely skip the chr bankswitch. If other games - using the same board and using CHR should surface, - we need to investigate this... - - In MESS: Supported - - -------------------------------------------------*/ - -// Identical to Konami IRQ -void nes_t230_device::hblank_irq(int scanline, int vblank, int blanked) -{ - /* Increment & check the IRQ scanline counter */ - if (m_irq_enable && (++m_irq_count == 0x100)) - { - m_irq_count = m_irq_count_latch; - m_irq_enable = m_irq_enable_latch; - m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE); - } -} - -WRITE8_MEMBER(nes_t230_device::write_h) -{ - LOG_MMC(("t230 write_h, offset: %04x, data: %02x\n", offset, data)); - - switch (offset & 0x700c) - { - case 0x0000: - break; - case 0x2000: - prg16_89ab(data); - break; - case 0x1000: - case 0x1004: - case 0x1008: - case 0x100c: - switch (data & 0x03) - { - case 0x00: set_nt_mirroring(PPU_MIRROR_VERT); break; - case 0x01: set_nt_mirroring(PPU_MIRROR_HORZ); break; - case 0x02: set_nt_mirroring(PPU_MIRROR_LOW); break; - case 0x03: set_nt_mirroring(PPU_MIRROR_HIGH); break; - } - break; - - case 0x7000: - m_irq_count_latch &= ~0x0f; - m_irq_count_latch |= data & 0x0f; - break; - case 0x7004: - m_irq_count_latch &= ~0xf0; - m_irq_count_latch |= (data << 4) & 0xf0; - break; - case 0x7008: - m_irq_mode = data & 0x04; // currently not implemented: 0 = prescaler mode / 1 = CPU mode - m_irq_enable = data & 0x02; - m_irq_enable_latch = data & 0x01; - if (data & 0x02) - m_irq_count = m_irq_count_latch; - break; - - default: - logerror("unl_t230_w uncaught offset: %04x value: %02x\n", offset, data); - break; - } -} - -/*------------------------------------------------- - - Bootleg Board for MK2 - - Games: Mortal Kombat II, Street Fighter III, Super Mario - Kart Rider - - This board uses an IRQ system very similar to MMC3. We indeed - use mapper4_irq, but there is some small glitch! - - iNES: mapper 91 - - In MESS: Supported. - - -------------------------------------------------*/ - -// Same IRQ as MMC3 -void nes_mk2_device::hblank_irq( int scanline, int vblank, int blanked ) -{ - if (scanline < PPU_BOTTOM_VISIBLE_SCANLINE) - { - int prior_count = m_irq_count; - if ((m_irq_count == 0) || m_irq_clear) - m_irq_count = m_irq_count_latch; - else - m_irq_count--; - - if (m_irq_enable && !blanked && (m_irq_count == 0) && (prior_count || m_irq_clear)) - { - LOG_MMC(("irq fired, scanline: %d (MAME %d, beam pos: %d)\n", scanline, - machine().first_screen()->vpos(), machine().first_screen()->hpos())); - m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE); - } - } - m_irq_clear = 0; -} - -WRITE8_MEMBER(nes_mk2_device::write_m) -{ - LOG_MMC(("mk2 write_m, offset: %04x, data: %02x\n", offset, data)); - - switch (offset & 0x1000) - { - case 0x0000: - switch (offset & 0x03) - { - case 0x00: chr2_0(data, CHRROM); break; - case 0x01: chr2_2(data, CHRROM); break; - case 0x02: chr2_4(data, CHRROM); break; - case 0x03: chr2_6(data, CHRROM); break; - } - break; - case 0x1000: - switch (offset & 0x03) - { - case 0x00: prg8_89(data); break; - case 0x01: prg8_ab(data); break; - case 0x02: m_irq_enable = 0; m_irq_count = 0; break; - case 0x03: m_irq_enable = 1; m_irq_count = 7; break; - } - break; - default: - logerror("mk2 write_m, uncaught addr: %04x value: %02x\n", offset + 0x6000, data); - break; - } -} - - -/*------------------------------------------------- - - UNL-WOLRDHERO board emulation - - - iNES: - - -------------------------------------------------*/ - -// Same as Konami VRC IRQ... -void nes_whero_device::hblank_irq(int scanline, int vblank, int blanked) -{ - /* Increment & check the IRQ scanline counter */ - if (m_irq_enable && (++m_irq_count == 0x100)) - { - m_irq_count = m_irq_count_latch; - m_irq_enable = m_irq_enable_latch; - m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE); - } -} - -WRITE8_MEMBER(nes_whero_device::write_h) -{ - int bank, shift, mask1, mask2; - LOG_MMC(("World Hero write_h, offset: %04x, data: %02x\n", offset, data)); - - switch (offset & 0x70c3) - { - case 0x0000: - if (!m_reg) - prg8_89(data); - else - prg8_cd(data); - break; - - case 0x1000: - switch (data & 0x03) - { - case 0x00: set_nt_mirroring(PPU_MIRROR_VERT); break; - case 0x01: set_nt_mirroring(PPU_MIRROR_HORZ); break; - case 0x02: set_nt_mirroring(PPU_MIRROR_LOW); break; - case 0x03: set_nt_mirroring(PPU_MIRROR_HIGH); break; - } - break; - - case 0x1002: - case 0x1080: - if (m_reg != (data & 2)) - { - m_reg = data & 2; - // swap banks! - prg8_89(m_prg_bank[2]); - prg8_cd(m_prg_bank[0]); - } - break; - - case 0x2000: - prg8_ab(data); - break; - - case 0x3000: case 0x3001: case 0x3002: case 0x3003: - case 0x4000: case 0x4001: case 0x4002: case 0x4003: - case 0x5000: case 0x5001: case 0x5002: case 0x5003: - case 0x6000: case 0x6001: case 0x6002: case 0x6003: - bank = ((offset & 0x7000) - 0x3000) / 0x0800 + BIT(offset, 1); - shift = (offset & 1) << 2; - mask1 = shift ? 0x00f : 0xff0; - mask2 = shift ? 0xff0 : 0x00f; - m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & mask1) | ((data << shift) & mask2); - chr1_x(bank, m_mmc_vrom_bank[bank], CHRROM); - break; - - case 0x7000: - m_irq_count_latch = (m_irq_count_latch & 0xf0) | (data & 0x0f); - break; - - case 0x7001: - m_irq_count_latch = (m_irq_count_latch & 0x0f) | ((data & 0x0f) << 4); - break; - - case 0x7002: - // m_irq_mode = data & 0x04; // currently not implemented: 0 = prescaler mode / 1 = CPU mode - m_irq_enable = data & 0x02; - m_irq_enable_latch = data & 0x01; - if (data & 0x02) - m_irq_count = m_irq_count_latch; - break; - - case 0x7003: - m_irq_enable = m_irq_enable_latch; - break; - } -} - - -/*------------------------------------------------- - - UNL-43272 - - Games: Gaau Hok Gwong Cheung - - In MESS: Preliminary Supported - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_43272_device::write_h) -{ - LOG_MMC(("unl_43272 write_h, offset: %04x, data: %02x\n", offset, data)); - - if ((m_latch & 0x81) == 0x81) - prg32((m_latch & 0x38) >> 3); - - m_latch = offset & 0xffff; -} - - -READ8_MEMBER(nes_43272_device::read_h) -{ - UINT8 mask = (m_latch & 0x400) ? 0xfe : 0xff; - LOG_MMC(("unl_43272 read_h, offset: %04x\n", offset)); - - return hi_access_rom(offset & mask); -} - - -/*------------------------------------------------- - - UNL-TF1201 - - Games: - - In MESS: Preliminary Supported - - -------------------------------------------------*/ - -void nes_tf1201_device::hblank_irq(int scanline, int vblank, int blanked) -{ - if (m_irq_enable_latch != m_irq_enable && scanline < 240) - m_irq_count -= 8; - - if (m_irq_enable) - { - m_irq_count++; - if ((m_irq_count & 0xff) == 238) - m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE); - } -} - -void nes_tf1201_device::update_prg() -{ - prg8_89(m_swap ? 0xff : m_prg); - prg8_cd(m_swap ? m_prg : 0xff ); -} - -WRITE8_MEMBER(nes_tf1201_device::write_h) -{ - int bank; - LOG_MMC(("unl_tf1201 write_h, offset: %04x, data: %02x\n", offset, data)); - - offset = (offset & 0x7003) | ((offset & 0x0c) >> 2); // nestopia does not OR here... - - switch (offset & 0x7003) - { - case 0x0000: - m_prg = data; - update_prg(); - break; - case 0x1000: - set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); - break; - case 0x1001: - m_swap = data & 0x03; - update_prg(); - break; - case 0x2000: - prg8_ab(data); - break; - case 0x3000: case 0x3001: case 0x3002: case 0x3003: - case 0x4000: case 0x4001: case 0x4002: case 0x4003: - case 0x5000: case 0x5001: case 0x5002: case 0x5003: - case 0x6000: case 0x6001: case 0x6002: case 0x6003: - bank = (((offset - 0x3000) >> 11) | (offset & 0x1)) & 0x7; - if (offset & 2) - m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0x0f) | ((data & 0x0f) << 4); - else - m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0xf0) | ((data & 0x0f) << 0); - chr1_x(bank, m_mmc_vrom_bank[bank], m_chr_source); - break; - case 0x7000: - m_irq_count = (m_irq_count & 0xf0) | (data & 0x0f); - break; - case 0x7001: - case 0x7003: - m_irq_enable_latch = m_irq_enable; - m_irq_enable = BIT(data, 1); - break; - case 0x7002: - m_irq_count = (m_irq_count & 0x0f) | ((data & 0x0f) << 4); - break; - } -} - - -/*------------------------------------------------- - - UNL-CITYFIGHT - - Games: - - Additional audio register not emulated yet! - - In MESS: Preliminary Supported - - -------------------------------------------------*/ - -void nes_cityfight_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) -{ - if (id == TIMER_IRQ) - { - if (m_irq_enable) - { - if (!m_irq_count) - { - m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE); - m_irq_count = 0xffff; - } - else - m_irq_count--; - } - } -} - -void nes_cityfight_device::update_prg() -{ - prg32(m_prg_reg >> 2); - if (!m_prg_mode) - prg8_cd(m_prg_reg); -} - -WRITE8_MEMBER(nes_cityfight_device::write_h) -{ - int bank; - LOG_MMC(("unl_cityfight write_h, offset: %04x, data: %02x\n", offset, data)); - - switch (offset & 0x700c) - { - case 0x1000: - switch (data & 0x03) - { - case 0x00: set_nt_mirroring(PPU_MIRROR_VERT); break; - case 0x01: set_nt_mirroring(PPU_MIRROR_HORZ); break; - case 0x02: set_nt_mirroring(PPU_MIRROR_LOW); break; - case 0x03: set_nt_mirroring(PPU_MIRROR_HIGH); break; - } - m_prg_reg = data & 0xc; - break; - case 0x1004: - case 0x1008: - case 0x100c: - if (offset & 0x800) - LOG_MMC(("Extended Audio write, data %x!", data & 0x0f));//pcmwrite(0x4011, (V & 0xf) << 3); - else - m_prg_reg = data & 0xc; - break; - - - case 0x2000: case 0x2004: case 0x2008: case 0x200c: - bank = 2 + BIT(offset, 3); - if (offset & 4) - m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0x0f) | ((data & 0x0f) << 4); - else - m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0xf0) | ((data & 0x0f) << 0); - chr1_x(bank, m_mmc_vrom_bank[bank], m_chr_source); - break; - case 0x3000: case 0x3004: case 0x3008: case 0x300c: - bank = 4 + BIT(offset, 3); - if (offset & 4) - m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0x0f) | ((data & 0x0f) << 4); - else - m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0xf0) | ((data & 0x0f) << 0); - chr1_x(bank, m_mmc_vrom_bank[bank], m_chr_source); - break; - case 0x5000: case 0x5004: case 0x5008: case 0x500c: - bank = 0 + BIT(offset, 3); - if (offset & 4) - m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0x0f) | ((data & 0x0f) << 4); - else - m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0xf0) | ((data & 0x0f) << 0); - chr1_x(bank, m_mmc_vrom_bank[bank], m_chr_source); - break; - case 0x6000: case 0x6004: case 0x6008: case 0x600c: - bank = 6 + BIT(offset, 3); - if (offset & 4) - m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0x0f) | ((data & 0x0f) << 4); - else - m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0xf0) | ((data & 0x0f) << 0); - chr1_x(bank, m_mmc_vrom_bank[bank], m_chr_source); - break; - - case 0x4000: - case 0x4004: - case 0x4008: - case 0x400c: - m_prg_mode = data & 1; - - case 0x7000: - m_irq_count = (m_irq_count & 0x1e0) | ((data & 0x0f) << 1); - break; - case 0x7004: - m_irq_count = (m_irq_count & 0x1e) | ((data & 0x0f) << 5); - break; - case 0x7008: - m_irq_enable = BIT(data, 1); - break; - } -} - - -#ifdef UNUSED_FUNCTION -/*------------------------------------------------- - - FUJIYA Board - mapper 170 according to NEStopia - - Is this possibly for the Fujiya Famikase series - of educational titles? Is there any dump around? - - -------------------------------------------------*/ - -void nes_fujiya_device::device_start() -{ - common_start(); - save_item(NAME(m_latch)); -} - -void nes_fujiya_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(0); - prg16_cdef(0); - chr8(0, m_chr_source); - - m_latch = 0; -} - -WRITE8_MEMBER(nes_fujiya_device::write_m) -{ - LOG_MMC(("fujiya write_m, offset: %04x, data: %02x\n", offset, data)); - offset += 0x6000; - - if (offset == 0x6502 || offset == 0x7000) - m_latch = (data & 0x40) << 1; -} - -READ8_MEMBER(nes_fujiya_device::read_m) -{ - LOG_MMC(("fujiya read_m, offset: %04x\n", offset)); - offset += 0x6000; - - if (offset == 0x7001 || offset == 0x7777) - return m_latch | ((offset >> 8) & 0x7f); - - return m_open_bus; // open bus -} -#endif diff --git a/src/devices/bus/nes/pirate.cpp b/src/devices/bus/nes/pirate.cpp new file mode 100644 index 00000000000..557831ed144 --- /dev/null +++ b/src/devices/bus/nes/pirate.cpp @@ -0,0 +1,1387 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for pirate cart PCBs + + + Here we emulate the various PCBs used by Asian & Korean pirate games + + TODO: + - Are the scrolling glitches (check status bar) in Magic Dragon correct? FWIW, NEStopia behaves similarly + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "pirate.h" + +#include "cpu/m6502/m6502.h" +#include "video/ppu2c0x.h" // this has to be included so that IRQ functions can access PPU_BOTTOM_VISIBLE_SCANLINE + + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_AGCI_50282 = &device_creator; +const device_type NES_DREAMTECH01 = &device_creator; +const device_type NES_FUKUTAKE = &device_creator; +const device_type NES_FUTUREMEDIA = &device_creator; +const device_type NES_MAGSERIES = &device_creator; +const device_type NES_DAOU306 = &device_creator; +const device_type NES_SUBOR0 = &device_creator; +const device_type NES_SUBOR1 = &device_creator; +const device_type NES_CC21 = &device_creator; +const device_type NES_XIAOZY = &device_creator; +const device_type NES_EDU2K = &device_creator; +const device_type NES_T230 = &device_creator; +const device_type NES_MK2 = &device_creator; +const device_type NES_WHERO = &device_creator; +const device_type NES_43272 = &device_creator; +const device_type NES_TF1201 = &device_creator; +const device_type NES_CITYFIGHT = &device_creator; + + +nes_agci_device::nes_agci_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_AGCI_50282, "NES Cart AGCI 50282 PCB", tag, owner, clock, "nes_agci50282", __FILE__) +{ +} + +nes_dreamtech_device::nes_dreamtech_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_DREAMTECH01, "NES Cart Dreamtech01 PCB", tag, owner, clock, "nes_dreamtech", __FILE__) +{ +} + +nes_fukutake_device::nes_fukutake_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_FUKUTAKE, "NES Cart Fukutake Study Box PCB", tag, owner, clock, "nes_fukutake", __FILE__) +{ +} + +nes_futuremedia_device::nes_futuremedia_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_FUTUREMEDIA, "NES Cart FutureMedia PCB", tag, owner, clock, "nes_futuremedia", __FILE__) +{ +} + +nes_magseries_device::nes_magseries_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_MAGSERIES, "NES Cart Magical Series PCB", tag, owner, clock, "nes_magseries", __FILE__) +{ +} + +nes_daou306_device::nes_daou306_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_DAOU306, "NES Cart Daou 306 PCB", tag, owner, clock, "nes_daou306", __FILE__) +{ +} + +nes_subor0_device::nes_subor0_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_SUBOR0, "NES Cart Subor Type 0 PCB", tag, owner, clock, "nes_subor0", __FILE__) +{ +} + +nes_subor1_device::nes_subor1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_SUBOR1, "NES Cart Subor Type 1 PCB", tag, owner, clock, "nes_subor1", __FILE__) +{ +} + +nes_cc21_device::nes_cc21_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_CC21, "NES Cart CC-21 PCB", tag, owner, clock, "nes_cc21", __FILE__) +{ +} + +nes_xiaozy_device::nes_xiaozy_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_XIAOZY, "NES Cart Xiao Zhuan Yuan PCB", tag, owner, clock, "nes_xiaozy", __FILE__) +{ +} + +nes_edu2k_device::nes_edu2k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_EDU2K, "NES Cart Educational Computer 2000 PCB", tag, owner, clock, "nes_edu2k", __FILE__) +{ +} + +nes_t230_device::nes_t230_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_T230, "NES Cart T-230 PCB", tag, owner, clock, "nes_t230", __FILE__) +{ +} + +nes_mk2_device::nes_mk2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_MK2, "NES Cart Mortal Kombat 2 PCB", tag, owner, clock, "nes_mk2", __FILE__) +{ +} + +nes_whero_device::nes_whero_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_WHERO, "NES Cart World Heroes PCB", tag, owner, clock, "nes_whero", __FILE__) +{ +} + +nes_43272_device::nes_43272_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_43272, "NES Cart UNL-43272 PCB", tag, owner, clock, "nes_43272", __FILE__) +{ +} + +nes_tf1201_device::nes_tf1201_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_TF1201, "NES Cart UNL-TF1201 PCB", tag, owner, clock, "nes_tf1201", __FILE__) +{ +} + +nes_cityfight_device::nes_cityfight_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_TF1201, "NES Cart City Fighter PCB", tag, owner, clock, "nes_cityfight", __FILE__) +{ +} + + + + +void nes_agci_device::device_start() +{ + common_start(); +} + +void nes_agci_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + +void nes_dreamtech_device::device_start() +{ + common_start(); +} + +void nes_dreamtech_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(8); + chr8(0, m_chr_source); +} + +void nes_fukutake_device::device_start() +{ + common_start(); + save_item(NAME(m_latch)); + + // 2816 (?) bytes of RAM + save_item(NAME(m_ram)); +} + +void nes_fukutake_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(0); + chr8(0, m_chr_source); + + m_latch = 0; +} + +void nes_futuremedia_device::device_start() +{ + common_start(); + save_item(NAME(m_irq_clear)); + save_item(NAME(m_irq_enable)); + save_item(NAME(m_irq_count)); + save_item(NAME(m_irq_count_latch)); +} + +void nes_futuremedia_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + + m_irq_clear = 0; + m_irq_enable = 0; + m_irq_count = m_irq_count_latch = 0; +} + +void nes_magseries_device::device_start() +{ + common_start(); +} + +void nes_magseries_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + +void nes_daou306_device::device_start() +{ + common_start(); + save_item(NAME(m_reg)); +} + +void nes_daou306_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(m_prg_chunks - 2); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + set_nt_mirroring(PPU_MIRROR_LOW); + + memset(m_reg, 0, sizeof(m_reg)); +} + +void nes_subor0_device::device_start() +{ + common_start(); + save_item(NAME(m_reg)); +} + +void nes_subor0_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(0x20); + chr8(0, m_chr_source); + + memset(m_reg, 0, sizeof(m_reg)); +} + +void nes_subor1_device::device_start() +{ + common_start(); + save_item(NAME(m_reg)); +} + +void nes_subor1_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(0x07); + chr8(0, m_chr_source); + + memset(m_reg, 0, sizeof(m_reg)); +} + +void nes_cc21_device::device_start() +{ + common_start(); +} + +void nes_cc21_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + +void nes_xiaozy_device::device_start() +{ + common_start(); +} + +void nes_xiaozy_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32((m_prg_chunks - 1) >> 1); + chr8(0, m_chr_source); +} + +void nes_edu2k_device::device_start() +{ + common_start(); + save_item(NAME(m_latch)); +} + +void nes_edu2k_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); + + m_latch = 0; +} + +void nes_t230_device::device_start() +{ + common_start(); + save_item(NAME(m_irq_mode)); + save_item(NAME(m_irq_enable)); + save_item(NAME(m_irq_enable_latch)); + save_item(NAME(m_irq_count)); + save_item(NAME(m_irq_count_latch)); + save_item(NAME(m_mmc_vrom_bank)); +} + +void nes_t230_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + + m_irq_mode = 0; + m_irq_enable = m_irq_enable_latch = 0; + m_irq_count = m_irq_count_latch = 0; + + memset(m_mmc_vrom_bank, 0, sizeof(m_mmc_vrom_bank)); +} + +void nes_mk2_device::device_start() +{ + common_start(); + save_item(NAME(m_irq_clear)); + save_item(NAME(m_irq_enable)); + save_item(NAME(m_irq_count)); + save_item(NAME(m_irq_count_latch)); +} + +void nes_mk2_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(m_prg_chunks - 1); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + set_nt_mirroring(PPU_MIRROR_VERT); + + m_irq_clear = 0; + m_irq_enable = 0; + m_irq_count = m_irq_count_latch = 0; +} + + +void nes_whero_device::device_start() +{ + common_start(); + save_item(NAME(m_irq_enable)); + save_item(NAME(m_irq_enable_latch)); + save_item(NAME(m_irq_count)); + save_item(NAME(m_irq_count_latch)); + save_item(NAME(m_reg)); + save_item(NAME(m_mmc_vrom_bank)); +} + +void nes_whero_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0x100, m_chr_source); + + m_irq_enable = 0; + m_irq_enable_latch = 0; + m_irq_count = 0; + m_irq_count_latch = 0; + + m_reg = 0; + memset(m_mmc_vrom_bank, 0, sizeof(m_mmc_vrom_bank)); +} + +void nes_43272_device::device_start() +{ + common_start(); + save_item(NAME(m_latch)); +} + +void nes_43272_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32((m_prg_chunks - 1) >> 1); + chr8(0, m_chr_source); + + m_latch = 0x81; +} + +void nes_tf1201_device::device_start() +{ + common_start(); + save_item(NAME(m_prg)); + save_item(NAME(m_swap)); + save_item(NAME(m_irq_enable)); + save_item(NAME(m_irq_enable_latch)); + save_item(NAME(m_irq_count)); + save_item(NAME(m_mmc_vrom_bank)); +} + +void nes_tf1201_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + + memset(m_mmc_vrom_bank, 0, sizeof(m_mmc_vrom_bank)); + m_prg = 0; + m_swap = 0; + m_irq_enable = 0; + m_irq_enable_latch = 0; + m_irq_count = 0; +} + +void nes_cityfight_device::device_start() +{ + common_start(); + irq_timer = timer_alloc(TIMER_IRQ); + irq_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1)); + + save_item(NAME(m_prg_reg)); + save_item(NAME(m_prg_mode)); + save_item(NAME(m_irq_enable)); + save_item(NAME(m_irq_count)); + save_item(NAME(m_mmc_vrom_bank)); +} + +void nes_cityfight_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + + memset(m_mmc_vrom_bank, 0, sizeof(m_mmc_vrom_bank)); + m_prg_reg = 0; + m_prg_mode = 0; + m_irq_enable = 0; + m_irq_count = 0; +} + + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + AGCI 50282 bootleg board emulation + + Games: Death Race + + iNES: mapper 144 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_agci_device::write_h) +{ + LOG_MMC(("agci write_h, offset: %04x, data: %02x\n", offset, data)); + + // this pcb is subject to bus conflict + UINT8 temp = account_bus_conflict(offset, 0xff); + data = (data & temp) | (temp & 1); + + chr8(data >> 4, CHRROM); + prg32(data); +} + +/*------------------------------------------------- + + Board DREAMTECH01 + + Games: Korean Igo + + In MESS: Supported + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_dreamtech_device::write_l) +{ + LOG_MMC(("dreamtech write_l, offset: %04x, data: %02x\n", offset, data)); + offset += 0x100; + + if (offset == 0x1020) /* 0x5020 */ + prg16_89ab(data); +} + +/*------------------------------------------------- + + Bootleg Board by Fukutake + + Games: Study Box + + iNES: mapper 186 + + In MESS: Unsupported. + + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_fukutake_device::write_l) +{ + LOG_MMC(("fukutake write_l, offset: %04x, data: %02x\n", offset, data)); + offset += 0x100; + + if (offset >= 0x200 && offset < 0x400) + { + if (offset & 1) + prg16_89ab(data); + else + m_latch = data >> 6; + } + else if (offset >= 0x400 && offset < 0xf00) + m_ram[offset - 0x400] = data; +} + +READ8_MEMBER(nes_fukutake_device::read_l) +{ + LOG_MMC(("fukutake read_l, offset: %04x\n", offset)); + offset += 0x100; + + if (offset >= 0x200 && offset < 0x400) + { + if (offset == 0x200 || offset == 0x201 || offset == 0x203) + return 0x00; + else if (offset == 0x202) + return 0x40; + else + return 0xff; + } + else if (offset >= 0x400 && offset < 0xf00) + return m_ram[offset - 0x400]; + + return 0; +} + +WRITE8_MEMBER(nes_fukutake_device::write_m) +{ + LOG_MMC(("fukutake write_m, offset: %04x, data: %02x\n", offset, data)); + m_prgram[((m_latch * 0x2000) + offset) & (m_prgram.size() - 1)] = data; +} + +READ8_MEMBER(nes_fukutake_device::read_m) +{ + LOG_MMC(("fukutake read_m, offset: %04x\n", offset)); + return m_prgram[((m_latch * 0x2000) + offset) & (m_prgram.size() - 1)]; +} + +/*------------------------------------------------- + + Bootleg Board by Future Media + + Games: Crayon Shin-chan (C), San Guo Zhi 4 - Chi Bi Feng Yun + + iNES: mapper 117 + + In MESS: Unsupported. + + -------------------------------------------------*/ + +void nes_futuremedia_device::hblank_irq(int scanline, int vblank, int blanked) +{ + // if (scanline < PPU_BOTTOM_VISIBLE_SCANLINE) + { + if (m_irq_enable && m_irq_count) + { + m_irq_count--; + if (!m_irq_count) + m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE); + } + } +} + +WRITE8_MEMBER(nes_futuremedia_device::write_h) +{ + LOG_MMC(("futuremedia write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset) + { + case 0x0000: + prg8_89(data); + break; + case 0x0001: + prg8_ab(data); + break; + case 0x0002: + prg8_cd(data); + break; + case 0x0003: + prg8_ef(data); + break; + case 0x2000: + case 0x2001: + case 0x2002: + case 0x2003: + case 0x2004: + case 0x2005: + case 0x2006: + case 0x2007: + chr1_x(offset & 0x07, data, CHRROM); + break; + + case 0x5000: + set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + break; + + case 0x4001: + m_irq_count_latch = data; + break; + case 0x4002: + // IRQ cleared + break; + case 0x4003: + m_irq_count = m_irq_count_latch; + break; + case 0x6000: + m_irq_enable = data & 0x01; + break; + } +} + +/*------------------------------------------------- + + Bootleg Board by Magic Series + + Games: Magic Dragon + + Very simple mapper: writes to 0x8000-0xffff set prg32 and chr8 + banks + + iNES: mapper 107 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_magseries_device::write_h) +{ + LOG_MMC(("magseries write_h, offset: %04x, data: %02x\n", offset, data)); + + prg32(data >> 1); + chr8(data, CHRROM); +} + +/*------------------------------------------------- + + Open Corp DAOU306 board + + Games: Metal Force (K) + + iNES: mapper 156 + + In MESS: Supported. + + Notes: Metal Force and Buzz & Waldog only use the first 4 + regs and no mirroring. Janggun ui Adeul uses all features + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_daou306_device::write_h) +{ + LOG_MMC(("daou306 write_h, offset: %04x, data: %02x\n", offset, data)); + int reg = BIT(offset, 2) ? 8 : 0; + + switch (offset) + { + case 0x4000: + case 0x4004: + m_reg[reg + 0] = data; + chr1_0(m_reg[0] | (m_reg[8] << 8), CHRROM); + break; + case 0x4001: + case 0x4005: + m_reg[reg + 1] = data; + chr1_1(m_reg[1] | (m_reg[9] << 8), CHRROM); + break; + case 0x4002: + case 0x4006: + m_reg[reg + 2] = data; + chr1_2(m_reg[2] | (m_reg[10] << 8), CHRROM); + break; + case 0x4003: + case 0x4007: + m_reg[reg + 3] = data; + chr1_3(m_reg[3] | (m_reg[11] << 8), CHRROM); + break; + case 0x4008: + case 0x400c: + m_reg[reg + 4] = data; + chr1_4(m_reg[4] | (m_reg[12] << 8), CHRROM); + break; + case 0x4009: + case 0x400d: + m_reg[reg + 5] = data; + chr1_5(m_reg[5] | (m_reg[13] << 8), CHRROM); + break; + case 0x400a: + case 0x400e: + m_reg[reg + 6] = data; + chr1_6(m_reg[6] | (m_reg[14] << 8), CHRROM); + break; + case 0x400b: + case 0x400f: + m_reg[reg + 7] = data; + chr1_7(m_reg[7] | (m_reg[15] << 8), CHRROM); + break; + case 0x4010: + prg16_89ab(data); + break; + case 0x4014: + if (data & 1) + set_nt_mirroring(PPU_MIRROR_HORZ); + else + set_nt_mirroring(PPU_MIRROR_VERT); + break; + } +} + +/*------------------------------------------------- + + Subor bootleg board Type 0 + + iNES: mapper 167 + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_subor0_device::write_h) +{ + UINT8 subor_helper1, subor_helper2; + LOG_MMC(("subor0 write_h, offset: %04x, data: %02x\n", offset, data)); + + m_reg[(offset >> 13) & 0x03] = data; + subor_helper1 = ((m_reg[0] ^ m_reg[1]) << 1) & 0x20; + subor_helper2 = ((m_reg[2] ^ m_reg[3]) << 0) & 0x1f; + + if (m_reg[1] & 0x08) + { + subor_helper1 += subor_helper2 & 0xfe; + subor_helper2 = subor_helper1; + subor_helper1 += 1; + } + else if (m_reg[1] & 0x04) + { + subor_helper2 += subor_helper1; + subor_helper1 = 0x1f; + } + else + { + subor_helper1 += subor_helper2; + subor_helper2 = 0x20; + } + + prg16_89ab(subor_helper1); + prg16_cdef(subor_helper2); +} + +/*------------------------------------------------- + + Subor bootleg board Type 1 + + iNES: mapper 166 + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_subor1_device::write_h) +{ + UINT8 subor_helper1, subor_helper2; + LOG_MMC(("subor1 write_h, offset: %04x, data: %02x\n", offset, data)); + + m_reg[(offset >> 13) & 0x03] = data; + subor_helper1 = ((m_reg[0] ^ m_reg[1]) << 1) & 0x20; + subor_helper2 = ((m_reg[2] ^ m_reg[3]) << 0) & 0x1f; + + if (m_reg[1] & 0x08) + { + subor_helper1 += subor_helper2 & 0xfe; + subor_helper2 = subor_helper1; + subor_helper2 += 1; + } + else if (m_reg[1] & 0x04) + { + subor_helper2 += subor_helper1; + subor_helper1 = 0x1f; + } + else + { + subor_helper1 += subor_helper2; + subor_helper2 = 0x07; + } + + prg16_89ab(subor_helper1); + prg16_cdef(subor_helper2); +} + +/*------------------------------------------------- + + Board UNL-CC-21 + + Games: Mi Hun Che + + In MESS: Supported + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_cc21_device::write_h) +{ + LOG_MMC(("cc21 write_h, offset: %04x, data: %02x\n", offset, data)); + + set_nt_mirroring(BIT(offset, 1) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW); + chr8((offset & 0x01), CHRROM); +} + +/*------------------------------------------------- + + Bootleg Board for Xiao Zhuan Yuan + + Games: Shu Qi Yu - Zhi Li Xiao Zhuan Yuan + + Very simple mapper: writes to 0x5ff1 set prg32 (to data>>1), + while writes to 0x5ff2 set chr8 + + iNES: mapper 176 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_xiaozy_device::write_l) +{ + LOG_MMC(("xiaozy write_l, offset: %04x, data: %02x\n", offset, data)); + + switch (offset) + { + case 0x1ef1: /* 0x5ff1 */ + prg32(data >> 1); + break; + case 0x1ef2: /* 0x5ff2 */ + chr8(data, CHRROM); + break; + } +} + +/*------------------------------------------------- + + UNL-EDU2000 + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_edu2k_device::write_h) +{ + LOG_MMC(("edu2k write_h, offset: %04x, data: %02x\n", offset, data)); + + prg32(data & 0x1f); + m_latch = (data & 0xc0) >> 6; +} + +WRITE8_MEMBER(nes_edu2k_device::write_m) +{ + LOG_MMC(("edu2k write_m, offset: %04x, data: %02x\n", offset, data)); + m_prgram[((m_latch * 0x2000) + offset) & (m_prgram.size() - 1)] = data; +} + +READ8_MEMBER(nes_edu2k_device::read_m) +{ + LOG_MMC(("edu2k read_m, offset: %04x\n", offset)); + return m_prgram[((m_latch * 0x2000) + offset) & (m_prgram.size() - 1)]; +} + +/*------------------------------------------------- + + Board UNL-T-230 + + Games: Dragon Ball Z IV (Unl) + + This mapper appears to be similar to Konami VRC-2 + but the game has no VROM and only 1 VRAM bank, so we + completely skip the chr bankswitch. If other games + using the same board and using CHR should surface, + we need to investigate this... + + In MESS: Supported + + -------------------------------------------------*/ + +// Identical to Konami IRQ +void nes_t230_device::hblank_irq(int scanline, int vblank, int blanked) +{ + /* Increment & check the IRQ scanline counter */ + if (m_irq_enable && (++m_irq_count == 0x100)) + { + m_irq_count = m_irq_count_latch; + m_irq_enable = m_irq_enable_latch; + m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE); + } +} + +WRITE8_MEMBER(nes_t230_device::write_h) +{ + LOG_MMC(("t230 write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x700c) + { + case 0x0000: + break; + case 0x2000: + prg16_89ab(data); + break; + case 0x1000: + case 0x1004: + case 0x1008: + case 0x100c: + switch (data & 0x03) + { + case 0x00: set_nt_mirroring(PPU_MIRROR_VERT); break; + case 0x01: set_nt_mirroring(PPU_MIRROR_HORZ); break; + case 0x02: set_nt_mirroring(PPU_MIRROR_LOW); break; + case 0x03: set_nt_mirroring(PPU_MIRROR_HIGH); break; + } + break; + + case 0x7000: + m_irq_count_latch &= ~0x0f; + m_irq_count_latch |= data & 0x0f; + break; + case 0x7004: + m_irq_count_latch &= ~0xf0; + m_irq_count_latch |= (data << 4) & 0xf0; + break; + case 0x7008: + m_irq_mode = data & 0x04; // currently not implemented: 0 = prescaler mode / 1 = CPU mode + m_irq_enable = data & 0x02; + m_irq_enable_latch = data & 0x01; + if (data & 0x02) + m_irq_count = m_irq_count_latch; + break; + + default: + logerror("unl_t230_w uncaught offset: %04x value: %02x\n", offset, data); + break; + } +} + +/*------------------------------------------------- + + Bootleg Board for MK2 + + Games: Mortal Kombat II, Street Fighter III, Super Mario + Kart Rider + + This board uses an IRQ system very similar to MMC3. We indeed + use mapper4_irq, but there is some small glitch! + + iNES: mapper 91 + + In MESS: Supported. + + -------------------------------------------------*/ + +// Same IRQ as MMC3 +void nes_mk2_device::hblank_irq( int scanline, int vblank, int blanked ) +{ + if (scanline < PPU_BOTTOM_VISIBLE_SCANLINE) + { + int prior_count = m_irq_count; + if ((m_irq_count == 0) || m_irq_clear) + m_irq_count = m_irq_count_latch; + else + m_irq_count--; + + if (m_irq_enable && !blanked && (m_irq_count == 0) && (prior_count || m_irq_clear)) + { + LOG_MMC(("irq fired, scanline: %d (MAME %d, beam pos: %d)\n", scanline, + machine().first_screen()->vpos(), machine().first_screen()->hpos())); + m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE); + } + } + m_irq_clear = 0; +} + +WRITE8_MEMBER(nes_mk2_device::write_m) +{ + LOG_MMC(("mk2 write_m, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x1000) + { + case 0x0000: + switch (offset & 0x03) + { + case 0x00: chr2_0(data, CHRROM); break; + case 0x01: chr2_2(data, CHRROM); break; + case 0x02: chr2_4(data, CHRROM); break; + case 0x03: chr2_6(data, CHRROM); break; + } + break; + case 0x1000: + switch (offset & 0x03) + { + case 0x00: prg8_89(data); break; + case 0x01: prg8_ab(data); break; + case 0x02: m_irq_enable = 0; m_irq_count = 0; break; + case 0x03: m_irq_enable = 1; m_irq_count = 7; break; + } + break; + default: + logerror("mk2 write_m, uncaught addr: %04x value: %02x\n", offset + 0x6000, data); + break; + } +} + + +/*------------------------------------------------- + + UNL-WOLRDHERO board emulation + + + iNES: + + -------------------------------------------------*/ + +// Same as Konami VRC IRQ... +void nes_whero_device::hblank_irq(int scanline, int vblank, int blanked) +{ + /* Increment & check the IRQ scanline counter */ + if (m_irq_enable && (++m_irq_count == 0x100)) + { + m_irq_count = m_irq_count_latch; + m_irq_enable = m_irq_enable_latch; + m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE); + } +} + +WRITE8_MEMBER(nes_whero_device::write_h) +{ + int bank, shift, mask1, mask2; + LOG_MMC(("World Hero write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x70c3) + { + case 0x0000: + if (!m_reg) + prg8_89(data); + else + prg8_cd(data); + break; + + case 0x1000: + switch (data & 0x03) + { + case 0x00: set_nt_mirroring(PPU_MIRROR_VERT); break; + case 0x01: set_nt_mirroring(PPU_MIRROR_HORZ); break; + case 0x02: set_nt_mirroring(PPU_MIRROR_LOW); break; + case 0x03: set_nt_mirroring(PPU_MIRROR_HIGH); break; + } + break; + + case 0x1002: + case 0x1080: + if (m_reg != (data & 2)) + { + m_reg = data & 2; + // swap banks! + prg8_89(m_prg_bank[2]); + prg8_cd(m_prg_bank[0]); + } + break; + + case 0x2000: + prg8_ab(data); + break; + + case 0x3000: case 0x3001: case 0x3002: case 0x3003: + case 0x4000: case 0x4001: case 0x4002: case 0x4003: + case 0x5000: case 0x5001: case 0x5002: case 0x5003: + case 0x6000: case 0x6001: case 0x6002: case 0x6003: + bank = ((offset & 0x7000) - 0x3000) / 0x0800 + BIT(offset, 1); + shift = (offset & 1) << 2; + mask1 = shift ? 0x00f : 0xff0; + mask2 = shift ? 0xff0 : 0x00f; + m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & mask1) | ((data << shift) & mask2); + chr1_x(bank, m_mmc_vrom_bank[bank], CHRROM); + break; + + case 0x7000: + m_irq_count_latch = (m_irq_count_latch & 0xf0) | (data & 0x0f); + break; + + case 0x7001: + m_irq_count_latch = (m_irq_count_latch & 0x0f) | ((data & 0x0f) << 4); + break; + + case 0x7002: + // m_irq_mode = data & 0x04; // currently not implemented: 0 = prescaler mode / 1 = CPU mode + m_irq_enable = data & 0x02; + m_irq_enable_latch = data & 0x01; + if (data & 0x02) + m_irq_count = m_irq_count_latch; + break; + + case 0x7003: + m_irq_enable = m_irq_enable_latch; + break; + } +} + + +/*------------------------------------------------- + + UNL-43272 + + Games: Gaau Hok Gwong Cheung + + In MESS: Preliminary Supported + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_43272_device::write_h) +{ + LOG_MMC(("unl_43272 write_h, offset: %04x, data: %02x\n", offset, data)); + + if ((m_latch & 0x81) == 0x81) + prg32((m_latch & 0x38) >> 3); + + m_latch = offset & 0xffff; +} + + +READ8_MEMBER(nes_43272_device::read_h) +{ + UINT8 mask = (m_latch & 0x400) ? 0xfe : 0xff; + LOG_MMC(("unl_43272 read_h, offset: %04x\n", offset)); + + return hi_access_rom(offset & mask); +} + + +/*------------------------------------------------- + + UNL-TF1201 + + Games: + + In MESS: Preliminary Supported + + -------------------------------------------------*/ + +void nes_tf1201_device::hblank_irq(int scanline, int vblank, int blanked) +{ + if (m_irq_enable_latch != m_irq_enable && scanline < 240) + m_irq_count -= 8; + + if (m_irq_enable) + { + m_irq_count++; + if ((m_irq_count & 0xff) == 238) + m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE); + } +} + +void nes_tf1201_device::update_prg() +{ + prg8_89(m_swap ? 0xff : m_prg); + prg8_cd(m_swap ? m_prg : 0xff ); +} + +WRITE8_MEMBER(nes_tf1201_device::write_h) +{ + int bank; + LOG_MMC(("unl_tf1201 write_h, offset: %04x, data: %02x\n", offset, data)); + + offset = (offset & 0x7003) | ((offset & 0x0c) >> 2); // nestopia does not OR here... + + switch (offset & 0x7003) + { + case 0x0000: + m_prg = data; + update_prg(); + break; + case 0x1000: + set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + break; + case 0x1001: + m_swap = data & 0x03; + update_prg(); + break; + case 0x2000: + prg8_ab(data); + break; + case 0x3000: case 0x3001: case 0x3002: case 0x3003: + case 0x4000: case 0x4001: case 0x4002: case 0x4003: + case 0x5000: case 0x5001: case 0x5002: case 0x5003: + case 0x6000: case 0x6001: case 0x6002: case 0x6003: + bank = (((offset - 0x3000) >> 11) | (offset & 0x1)) & 0x7; + if (offset & 2) + m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0x0f) | ((data & 0x0f) << 4); + else + m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0xf0) | ((data & 0x0f) << 0); + chr1_x(bank, m_mmc_vrom_bank[bank], m_chr_source); + break; + case 0x7000: + m_irq_count = (m_irq_count & 0xf0) | (data & 0x0f); + break; + case 0x7001: + case 0x7003: + m_irq_enable_latch = m_irq_enable; + m_irq_enable = BIT(data, 1); + break; + case 0x7002: + m_irq_count = (m_irq_count & 0x0f) | ((data & 0x0f) << 4); + break; + } +} + + +/*------------------------------------------------- + + UNL-CITYFIGHT + + Games: + + Additional audio register not emulated yet! + + In MESS: Preliminary Supported + + -------------------------------------------------*/ + +void nes_cityfight_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (id == TIMER_IRQ) + { + if (m_irq_enable) + { + if (!m_irq_count) + { + m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE); + m_irq_count = 0xffff; + } + else + m_irq_count--; + } + } +} + +void nes_cityfight_device::update_prg() +{ + prg32(m_prg_reg >> 2); + if (!m_prg_mode) + prg8_cd(m_prg_reg); +} + +WRITE8_MEMBER(nes_cityfight_device::write_h) +{ + int bank; + LOG_MMC(("unl_cityfight write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x700c) + { + case 0x1000: + switch (data & 0x03) + { + case 0x00: set_nt_mirroring(PPU_MIRROR_VERT); break; + case 0x01: set_nt_mirroring(PPU_MIRROR_HORZ); break; + case 0x02: set_nt_mirroring(PPU_MIRROR_LOW); break; + case 0x03: set_nt_mirroring(PPU_MIRROR_HIGH); break; + } + m_prg_reg = data & 0xc; + break; + case 0x1004: + case 0x1008: + case 0x100c: + if (offset & 0x800) + LOG_MMC(("Extended Audio write, data %x!", data & 0x0f));//pcmwrite(0x4011, (V & 0xf) << 3); + else + m_prg_reg = data & 0xc; + break; + + + case 0x2000: case 0x2004: case 0x2008: case 0x200c: + bank = 2 + BIT(offset, 3); + if (offset & 4) + m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0x0f) | ((data & 0x0f) << 4); + else + m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0xf0) | ((data & 0x0f) << 0); + chr1_x(bank, m_mmc_vrom_bank[bank], m_chr_source); + break; + case 0x3000: case 0x3004: case 0x3008: case 0x300c: + bank = 4 + BIT(offset, 3); + if (offset & 4) + m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0x0f) | ((data & 0x0f) << 4); + else + m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0xf0) | ((data & 0x0f) << 0); + chr1_x(bank, m_mmc_vrom_bank[bank], m_chr_source); + break; + case 0x5000: case 0x5004: case 0x5008: case 0x500c: + bank = 0 + BIT(offset, 3); + if (offset & 4) + m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0x0f) | ((data & 0x0f) << 4); + else + m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0xf0) | ((data & 0x0f) << 0); + chr1_x(bank, m_mmc_vrom_bank[bank], m_chr_source); + break; + case 0x6000: case 0x6004: case 0x6008: case 0x600c: + bank = 6 + BIT(offset, 3); + if (offset & 4) + m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0x0f) | ((data & 0x0f) << 4); + else + m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0xf0) | ((data & 0x0f) << 0); + chr1_x(bank, m_mmc_vrom_bank[bank], m_chr_source); + break; + + case 0x4000: + case 0x4004: + case 0x4008: + case 0x400c: + m_prg_mode = data & 1; + + case 0x7000: + m_irq_count = (m_irq_count & 0x1e0) | ((data & 0x0f) << 1); + break; + case 0x7004: + m_irq_count = (m_irq_count & 0x1e) | ((data & 0x0f) << 5); + break; + case 0x7008: + m_irq_enable = BIT(data, 1); + break; + } +} + + +#ifdef UNUSED_FUNCTION +/*------------------------------------------------- + + FUJIYA Board - mapper 170 according to NEStopia + + Is this possibly for the Fujiya Famikase series + of educational titles? Is there any dump around? + + -------------------------------------------------*/ + +void nes_fujiya_device::device_start() +{ + common_start(); + save_item(NAME(m_latch)); +} + +void nes_fujiya_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(0); + chr8(0, m_chr_source); + + m_latch = 0; +} + +WRITE8_MEMBER(nes_fujiya_device::write_m) +{ + LOG_MMC(("fujiya write_m, offset: %04x, data: %02x\n", offset, data)); + offset += 0x6000; + + if (offset == 0x6502 || offset == 0x7000) + m_latch = (data & 0x40) << 1; +} + +READ8_MEMBER(nes_fujiya_device::read_m) +{ + LOG_MMC(("fujiya read_m, offset: %04x\n", offset)); + offset += 0x6000; + + if (offset == 0x7001 || offset == 0x7777) + return m_latch | ((offset >> 8) & 0x7f); + + return m_open_bus; // open bus +} +#endif diff --git a/src/devices/bus/nes/pt554.c b/src/devices/bus/nes/pt554.c deleted file mode 100644 index 4f6e843d8d1..00000000000 --- a/src/devices/bus/nes/pt554.c +++ /dev/null @@ -1,107 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Fabio Priuli -/*********************************************************************************************************** - - - NES/Famicom cartridge emulation for Bandai PT-554 PCBs - - - Here we emulate the following Bandai PT-554 PCB (a CNROM PCB + LPC / PARCOR speech synthesis chip) - - TODO: - - emulate the mat controller - - ***********************************************************************************************************/ - - -#include "emu.h" -#include "pt554.h" - - -#ifdef NES_PCB_DEBUG -#define VERBOSE 1 -#else -#define VERBOSE 0 -#endif - -#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) - - -//------------------------------------------------- -// constructor -//------------------------------------------------- - -const device_type NES_BANDAI_PT554 = &device_creator; - - -nes_bandai_pt554_device::nes_bandai_pt554_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_cnrom_device(mconfig, NES_BANDAI_PT554, "NES Cart Bandai PT-554 PCB", tag, owner, clock, "nes_bandai_pt554", __FILE__), - m_samples(*this, "samples") -{ -} - - - -/*------------------------------------------------- - mapper specific handlers - -------------------------------------------------*/ - -/*------------------------------------------------- - - Bandai PT-554 board emulation - - This is used by Aerobics Studio. It is basically a CNROM board - with an Mitsubishi M50805 LPC / PARCOR speech synthesis chip - with internal tables stored in ROM which have not yet been dumped. - - iNES: mapper 3? - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_bandai_pt554_device::write_m) -{ - LOG_MMC(("Bandai PT-554 Sound write, data: %02x\n", data)); - - if (!BIT(data, 6)) - m_samples->start(data & 0x07, data & 0x07); - else - m_samples->stop(data & 0x07); -} - -static const char *const pt554_sample_names[] = -{ - "*ftaerobi", - "00", - "01", - "02", - "03", - "04", - "05", - "06", - "07", - 0 -}; - -//------------------------------------------------- -// MACHINE_DRIVER -//------------------------------------------------- - -static MACHINE_CONFIG_FRAGMENT( pt554 ) - - // additional sound hardware - MCFG_SPEAKER_STANDARD_MONO("addon") - - MCFG_SOUND_ADD("samples", SAMPLES, 0) - MCFG_SAMPLES_CHANNELS(8) - MCFG_SAMPLES_NAMES(pt554_sample_names) - MCFG_SOUND_ROUTE(ALL_OUTPUTS, "addon", 0.50) -MACHINE_CONFIG_END - -//------------------------------------------------- -// machine_config_additions -//------------------------------------------------- - -machine_config_constructor nes_bandai_pt554_device::device_mconfig_additions() const -{ - return MACHINE_CONFIG_NAME( pt554 ); -} diff --git a/src/devices/bus/nes/pt554.cpp b/src/devices/bus/nes/pt554.cpp new file mode 100644 index 00000000000..4f6e843d8d1 --- /dev/null +++ b/src/devices/bus/nes/pt554.cpp @@ -0,0 +1,107 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for Bandai PT-554 PCBs + + + Here we emulate the following Bandai PT-554 PCB (a CNROM PCB + LPC / PARCOR speech synthesis chip) + + TODO: + - emulate the mat controller + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "pt554.h" + + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_BANDAI_PT554 = &device_creator; + + +nes_bandai_pt554_device::nes_bandai_pt554_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_cnrom_device(mconfig, NES_BANDAI_PT554, "NES Cart Bandai PT-554 PCB", tag, owner, clock, "nes_bandai_pt554", __FILE__), + m_samples(*this, "samples") +{ +} + + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + Bandai PT-554 board emulation + + This is used by Aerobics Studio. It is basically a CNROM board + with an Mitsubishi M50805 LPC / PARCOR speech synthesis chip + with internal tables stored in ROM which have not yet been dumped. + + iNES: mapper 3? + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_bandai_pt554_device::write_m) +{ + LOG_MMC(("Bandai PT-554 Sound write, data: %02x\n", data)); + + if (!BIT(data, 6)) + m_samples->start(data & 0x07, data & 0x07); + else + m_samples->stop(data & 0x07); +} + +static const char *const pt554_sample_names[] = +{ + "*ftaerobi", + "00", + "01", + "02", + "03", + "04", + "05", + "06", + "07", + 0 +}; + +//------------------------------------------------- +// MACHINE_DRIVER +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( pt554 ) + + // additional sound hardware + MCFG_SPEAKER_STANDARD_MONO("addon") + + MCFG_SOUND_ADD("samples", SAMPLES, 0) + MCFG_SAMPLES_CHANNELS(8) + MCFG_SAMPLES_NAMES(pt554_sample_names) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "addon", 0.50) +MACHINE_CONFIG_END + +//------------------------------------------------- +// machine_config_additions +//------------------------------------------------- + +machine_config_constructor nes_bandai_pt554_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( pt554 ); +} diff --git a/src/devices/bus/nes/racermate.c b/src/devices/bus/nes/racermate.c deleted file mode 100644 index 6989c2254cb..00000000000 --- a/src/devices/bus/nes/racermate.c +++ /dev/null @@ -1,92 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Fabio Priuli -/*********************************************************************************************************** - - - NES/Famicom cartridge emulation for RacerMate PCBs - - - Here we emulate the UNL-RACERMATE PCB [mapper 168] - - TODO: - - save VRAM - - emulate the bike controller? - - ***********************************************************************************************************/ - - -#include "emu.h" -#include "racermate.h" - - -#ifdef NES_PCB_DEBUG -#define VERBOSE 1 -#else -#define VERBOSE 0 -#endif - -#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) - - -//------------------------------------------------- -// constructor -//------------------------------------------------- - -const device_type NES_RACERMATE = &device_creator; - - -nes_racermate_device::nes_racermate_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_RACERMATE, "NES Cart Racermate PCB", tag, owner, clock, "nes_racermate", __FILE__) -{ -} - - - -void nes_racermate_device::device_start() -{ - common_start(); - save_item(NAME(m_latch)); -} - -void nes_racermate_device::pcb_reset() -{ -// m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(0); - prg16_cdef(m_prg_chunks - 1); - chr4_0(0, CHRRAM); - chr4_4(0, CHRRAM); - - m_latch = 0; -} - - - -/*------------------------------------------------- - mapper specific handlers - -------------------------------------------------*/ - -/*------------------------------------------------- - - Board UNL-RACERMATE - - In MESS: *VERY* preliminary support. Also, it seems that this - board saves to battery the CHRRAM!!! - - -------------------------------------------------*/ - -void nes_racermate_device::update_banks() -{ - chr4_4(m_latch & 0x0f, m_chr_source); - prg16_89ab(m_latch >> 6); -} - -WRITE8_MEMBER(nes_racermate_device::write_h) -{ - LOG_MMC(("racermate write_h, offset: %04x, data: %02x\n", offset, data)); - - if (offset == 0x3000) - { - m_latch = data; - update_banks(); - } -} diff --git a/src/devices/bus/nes/racermate.cpp b/src/devices/bus/nes/racermate.cpp new file mode 100644 index 00000000000..6989c2254cb --- /dev/null +++ b/src/devices/bus/nes/racermate.cpp @@ -0,0 +1,92 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for RacerMate PCBs + + + Here we emulate the UNL-RACERMATE PCB [mapper 168] + + TODO: + - save VRAM + - emulate the bike controller? + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "racermate.h" + + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_RACERMATE = &device_creator; + + +nes_racermate_device::nes_racermate_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_RACERMATE, "NES Cart Racermate PCB", tag, owner, clock, "nes_racermate", __FILE__) +{ +} + + + +void nes_racermate_device::device_start() +{ + common_start(); + save_item(NAME(m_latch)); +} + +void nes_racermate_device::pcb_reset() +{ +// m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr4_0(0, CHRRAM); + chr4_4(0, CHRRAM); + + m_latch = 0; +} + + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + Board UNL-RACERMATE + + In MESS: *VERY* preliminary support. Also, it seems that this + board saves to battery the CHRRAM!!! + + -------------------------------------------------*/ + +void nes_racermate_device::update_banks() +{ + chr4_4(m_latch & 0x0f, m_chr_source); + prg16_89ab(m_latch >> 6); +} + +WRITE8_MEMBER(nes_racermate_device::write_h) +{ + LOG_MMC(("racermate write_h, offset: %04x, data: %02x\n", offset, data)); + + if (offset == 0x3000) + { + m_latch = data; + update_banks(); + } +} diff --git a/src/devices/bus/nes/rcm.c b/src/devices/bus/nes/rcm.c deleted file mode 100644 index 28ec6e8277e..00000000000 --- a/src/devices/bus/nes/rcm.c +++ /dev/null @@ -1,303 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Fabio Priuli -/*********************************************************************************************************** - - - NES/Famicom cartridge emulation for RCM PCBs - - - Here we emulate the following PCBs - - * RCM GS2015 [mapper 216] - * RCM GS2004 - * RCM GS2013 - * RCM Tetris Family 9in1 [mapper 61] - * RCM 3D Block - - TODO: - - investigate why 3D Block does not work - - ***********************************************************************************************************/ - - -#include "emu.h" -#include "rcm.h" - -#include "cpu/m6502/m6502.h" - - -#ifdef NES_PCB_DEBUG -#define VERBOSE 1 -#else -#define VERBOSE 0 -#endif - -#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) - - -//------------------------------------------------- -// constructor -//------------------------------------------------- - -const device_type NES_GS2015 = &device_creator; -const device_type NES_GS2004 = &device_creator; -const device_type NES_GS2013 = &device_creator; -const device_type NES_TF9IN1 = &device_creator; -const device_type NES_3DBLOCK = &device_creator; - - -nes_gs2015_device::nes_gs2015_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_GS2015, "NES Cart RCM GS-2015 PCB", tag, owner, clock, "nes_gs2015", __FILE__) -{ -} - -nes_gs2004_device::nes_gs2004_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_GS2004, "NES Cart RCM GS-2004 PCB", tag, owner, clock, "nes_gs2004", __FILE__) -{ -} - -nes_gs2013_device::nes_gs2013_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_GS2013, "NES Cart RCM GS-2013 PCB", tag, owner, clock, "nes_gs2013", __FILE__) -{ -} - -nes_tf9_device::nes_tf9_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_TF9IN1, "NES Cart RCM Tetris Family 9 in 1 PCB", tag, owner, clock, "nes_tetrisfam", __FILE__) -{ -} - -nes_3dblock_device::nes_3dblock_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_3DBLOCK, "NES Cart RCM 3D Block PCB", tag, owner, clock, "nes_3dblock", __FILE__) -{ -} - - - - -void nes_gs2015_device::device_start() -{ - common_start(); -} - -void nes_gs2015_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0); - chr8(0, m_chr_source); -} - -void nes_gs2004_device::device_start() -{ - common_start(); -} - -void nes_gs2004_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0xff); - chr8(0, m_chr_source); -} - -void nes_gs2013_device::device_start() -{ - common_start(); -} - -void nes_gs2013_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0xff); - chr8(0, m_chr_source); -} - -void nes_tf9_device::device_start() -{ - common_start(); -} - -void nes_tf9_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0); - chr8(0, m_chr_source); -} - -void nes_3dblock_device::device_start() -{ - common_start(); - save_item(NAME(m_reg)); - save_item(NAME(m_irq_count)); -} - -void nes_3dblock_device::pcb_reset() -{ - prg32(0); - chr8(0, CHRRAM); - m_reg[0] = 0; - m_reg[1] = 0; - m_reg[2] = 0; - m_reg[3] = 0; - m_irq_count = 0; -} - - - - -/*------------------------------------------------- - mapper specific handlers - -------------------------------------------------*/ - -/*------------------------------------------------- - - RCM GS2015 Board - - Games: Bonza, Magic Jewelry 2 - - Very simple mapper: writes to 0x8000-0xffff sets prg32 - to offset and chr8 to offset>>1 (when chrrom is present) - - iNES: mapper 216 - - In MESS: Supported. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_gs2015_device::write_h) -{ - LOG_MMC(("gs2015 write_h, offset: %04x, data: %02x\n", offset, data)); - - prg32(offset); - chr8(offset >> 1, m_chr_source); -} - -READ8_MEMBER(nes_gs2015_device::read_m) -{ - LOG_MMC(("gs2015 read_m, offset: %04x\n", offset)); - return 0; // Videopoker Bonza needs this (sort of protection? or related to inputs?) -} - -/*------------------------------------------------- - - Board BMC-GS2004 - - Games: Tetris Family 6-in-1 - - In MESS: Preliminary Support. It also misses WRAM handling - (we need reads from 0x6000-0x7fff) - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_gs2004_device::write_h) -{ - LOG_MMC(("gs2004 write_h, offset: %04x, data: %02x\n", offset, data)); - - prg32(data); -} - -/*------------------------------------------------- - - Board BMC-GS2013 - - Games: Tetris Family 12-in-1 - - In MESS: Preliminary Support. It also misses WRAM handling - (we need reads from 0x6000-0x7fff) - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_gs2013_device::write_h) -{ - LOG_MMC(("gs2013 write_h, offset: %04x, data: %02x\n", offset, data)); - - if (data & 0x08) - prg32(data & 0x09); - else - prg32(data & 0x07); -} - -/*------------------------------------------------- - - Bootleg Board by RCM for Tetris Family - - Games: Tetris Family 9 in 1, 20 in 1 - - Simple Mapper: prg/chr/nt are swapped depending on the offset - of writes in 0x8000-0xffff. offset&0x80 set NT mirroring, - when (offset&0x30) is 0,3 prg32 is set; when it is 1,2 - two 16k prg banks are set. See below for the values used in - these banks. - - iNES: mapper 61 - - In MESS: Supported. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_tf9_device::write_h) -{ - LOG_MMC(("tetrisfam write_h, offset: %04x, data: %02x\n", offset, data)); - - switch (offset & 0x30) - { - case 0x00: - case 0x30: - prg32(offset & 0x0f); - break; - case 0x10: - case 0x20: - prg16_89ab(((offset & 0x0f) << 1) | ((offset & 0x20) >> 4)); - prg16_cdef(((offset & 0x0f) << 1) | ((offset & 0x20) >> 4)); - break; - } - set_nt_mirroring(BIT(data, 7) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); -} - -/*------------------------------------------------- - - Bootleg Board by RCM for 3-D Block - - Games: 3-D Block Hwang Shinwei version - - iNES: - - In MESS: Very Preliminary Support. What is the purpose - of the writes to $4800-$4900-$4a00? These writes - also happens on the RCM version, which however works - (probably an unused leftover code in that version) - - FCEUmm suggests it might be IRQ related, but - it does not seem to help much... - - -------------------------------------------------*/ - -void nes_3dblock_device::hblank_irq(int scanline, int vblank, int blanked) -{ - if (m_irq_count) - { - m_irq_count--; - if (!m_irq_count) - m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE); - } -} - -WRITE8_MEMBER(nes_3dblock_device::write_l) -{ - LOG_MMC(("3dblock write_l, offset: %04x, data: %02x\n", offset, data)); - offset += 0x100; - - switch (offset) - { - case 0x800: // $4800 - m_reg[0] = data; - break; - case 0x900: // $4900 - m_reg[1] = data; - break; - case 0xa00: // $4a00 - m_reg[2] = data; - break; - case 0xe00: // $4e00 - m_reg[3] = data; m_irq_count = 0x10; - break; - } -} diff --git a/src/devices/bus/nes/rcm.cpp b/src/devices/bus/nes/rcm.cpp new file mode 100644 index 00000000000..28ec6e8277e --- /dev/null +++ b/src/devices/bus/nes/rcm.cpp @@ -0,0 +1,303 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for RCM PCBs + + + Here we emulate the following PCBs + + * RCM GS2015 [mapper 216] + * RCM GS2004 + * RCM GS2013 + * RCM Tetris Family 9in1 [mapper 61] + * RCM 3D Block + + TODO: + - investigate why 3D Block does not work + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "rcm.h" + +#include "cpu/m6502/m6502.h" + + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_GS2015 = &device_creator; +const device_type NES_GS2004 = &device_creator; +const device_type NES_GS2013 = &device_creator; +const device_type NES_TF9IN1 = &device_creator; +const device_type NES_3DBLOCK = &device_creator; + + +nes_gs2015_device::nes_gs2015_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_GS2015, "NES Cart RCM GS-2015 PCB", tag, owner, clock, "nes_gs2015", __FILE__) +{ +} + +nes_gs2004_device::nes_gs2004_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_GS2004, "NES Cart RCM GS-2004 PCB", tag, owner, clock, "nes_gs2004", __FILE__) +{ +} + +nes_gs2013_device::nes_gs2013_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_GS2013, "NES Cart RCM GS-2013 PCB", tag, owner, clock, "nes_gs2013", __FILE__) +{ +} + +nes_tf9_device::nes_tf9_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_TF9IN1, "NES Cart RCM Tetris Family 9 in 1 PCB", tag, owner, clock, "nes_tetrisfam", __FILE__) +{ +} + +nes_3dblock_device::nes_3dblock_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_3DBLOCK, "NES Cart RCM 3D Block PCB", tag, owner, clock, "nes_3dblock", __FILE__) +{ +} + + + + +void nes_gs2015_device::device_start() +{ + common_start(); +} + +void nes_gs2015_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + +void nes_gs2004_device::device_start() +{ + common_start(); +} + +void nes_gs2004_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0xff); + chr8(0, m_chr_source); +} + +void nes_gs2013_device::device_start() +{ + common_start(); +} + +void nes_gs2013_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0xff); + chr8(0, m_chr_source); +} + +void nes_tf9_device::device_start() +{ + common_start(); +} + +void nes_tf9_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + +void nes_3dblock_device::device_start() +{ + common_start(); + save_item(NAME(m_reg)); + save_item(NAME(m_irq_count)); +} + +void nes_3dblock_device::pcb_reset() +{ + prg32(0); + chr8(0, CHRRAM); + m_reg[0] = 0; + m_reg[1] = 0; + m_reg[2] = 0; + m_reg[3] = 0; + m_irq_count = 0; +} + + + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + RCM GS2015 Board + + Games: Bonza, Magic Jewelry 2 + + Very simple mapper: writes to 0x8000-0xffff sets prg32 + to offset and chr8 to offset>>1 (when chrrom is present) + + iNES: mapper 216 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_gs2015_device::write_h) +{ + LOG_MMC(("gs2015 write_h, offset: %04x, data: %02x\n", offset, data)); + + prg32(offset); + chr8(offset >> 1, m_chr_source); +} + +READ8_MEMBER(nes_gs2015_device::read_m) +{ + LOG_MMC(("gs2015 read_m, offset: %04x\n", offset)); + return 0; // Videopoker Bonza needs this (sort of protection? or related to inputs?) +} + +/*------------------------------------------------- + + Board BMC-GS2004 + + Games: Tetris Family 6-in-1 + + In MESS: Preliminary Support. It also misses WRAM handling + (we need reads from 0x6000-0x7fff) + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_gs2004_device::write_h) +{ + LOG_MMC(("gs2004 write_h, offset: %04x, data: %02x\n", offset, data)); + + prg32(data); +} + +/*------------------------------------------------- + + Board BMC-GS2013 + + Games: Tetris Family 12-in-1 + + In MESS: Preliminary Support. It also misses WRAM handling + (we need reads from 0x6000-0x7fff) + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_gs2013_device::write_h) +{ + LOG_MMC(("gs2013 write_h, offset: %04x, data: %02x\n", offset, data)); + + if (data & 0x08) + prg32(data & 0x09); + else + prg32(data & 0x07); +} + +/*------------------------------------------------- + + Bootleg Board by RCM for Tetris Family + + Games: Tetris Family 9 in 1, 20 in 1 + + Simple Mapper: prg/chr/nt are swapped depending on the offset + of writes in 0x8000-0xffff. offset&0x80 set NT mirroring, + when (offset&0x30) is 0,3 prg32 is set; when it is 1,2 + two 16k prg banks are set. See below for the values used in + these banks. + + iNES: mapper 61 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_tf9_device::write_h) +{ + LOG_MMC(("tetrisfam write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x30) + { + case 0x00: + case 0x30: + prg32(offset & 0x0f); + break; + case 0x10: + case 0x20: + prg16_89ab(((offset & 0x0f) << 1) | ((offset & 0x20) >> 4)); + prg16_cdef(((offset & 0x0f) << 1) | ((offset & 0x20) >> 4)); + break; + } + set_nt_mirroring(BIT(data, 7) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); +} + +/*------------------------------------------------- + + Bootleg Board by RCM for 3-D Block + + Games: 3-D Block Hwang Shinwei version + + iNES: + + In MESS: Very Preliminary Support. What is the purpose + of the writes to $4800-$4900-$4a00? These writes + also happens on the RCM version, which however works + (probably an unused leftover code in that version) + + FCEUmm suggests it might be IRQ related, but + it does not seem to help much... + + -------------------------------------------------*/ + +void nes_3dblock_device::hblank_irq(int scanline, int vblank, int blanked) +{ + if (m_irq_count) + { + m_irq_count--; + if (!m_irq_count) + m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE); + } +} + +WRITE8_MEMBER(nes_3dblock_device::write_l) +{ + LOG_MMC(("3dblock write_l, offset: %04x, data: %02x\n", offset, data)); + offset += 0x100; + + switch (offset) + { + case 0x800: // $4800 + m_reg[0] = data; + break; + case 0x900: // $4900 + m_reg[1] = data; + break; + case 0xa00: // $4a00 + m_reg[2] = data; + break; + case 0xe00: // $4e00 + m_reg[3] = data; m_irq_count = 0x10; + break; + } +} diff --git a/src/devices/bus/nes/rexsoft.c b/src/devices/bus/nes/rexsoft.c deleted file mode 100644 index c0e261dc5fa..00000000000 --- a/src/devices/bus/nes/rexsoft.c +++ /dev/null @@ -1,262 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Fabio Priuli -/*********************************************************************************************************** - - - NES/Famicom cartridge emulation for Rex Soft PCBs - - - Here we emulate the following PCBs - - * Rex Soft DragonBall Z V [mapper 12] - * Rex Soft SL-1632 [mapper 14] - - TODO: - - fix 0x6000-0x7fff accesses, write_m/read_m - - check glitches in SL-1632 - - ***********************************************************************************************************/ - - -#include "emu.h" -#include "rexsoft.h" - - -#ifdef NES_PCB_DEBUG -#define VERBOSE 1 -#else -#define VERBOSE 0 -#endif - -#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) - - -//------------------------------------------------- -// constructor -//------------------------------------------------- - -const device_type NES_REX_DBZ5 = &device_creator; -const device_type NES_REX_SL1632 = &device_creator; - - -nes_rex_dbz5_device::nes_rex_dbz5_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_txrom_device(mconfig, NES_REX_DBZ5, "NES Cart Rex Soft DragonBall Z V PCB", tag, owner, clock, "nes_rex_dbz5", __FILE__) -{ -} - -nes_rex_sl1632_device::nes_rex_sl1632_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_txrom_device(mconfig, NES_REX_SL1632, "NES Cart Rex Soft SL-1632 PCB", tag, owner, clock, "nes_rex_sl1632", __FILE__) -{ -} - - - - -void nes_rex_dbz5_device::device_start() -{ - mmc3_start(); - save_item(NAME(m_extra)); -} - -void nes_rex_dbz5_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - m_extra = 0; - mmc3_common_initialize(0xff, 0xff, 0); -} - -void nes_rex_sl1632_device::device_start() -{ - mmc3_start(); - save_item(NAME(m_mode)); - save_item(NAME(m_mirror)); - save_item(NAME(m_extra_bank)); -} - -void nes_rex_sl1632_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - - m_mode = 0; - m_mirror = 0; - memset(m_extra_bank, 0, sizeof(m_extra_bank)); - m_extra_bank[2] = 0xfe; - m_extra_bank[3] = 0xff; - mmc3_common_initialize(0xff, 0xff, 0); -} - - - - - -/*------------------------------------------------- - mapper specific handlers - -------------------------------------------------*/ - -/*------------------------------------------------- - - Bootleg Board by Rex Soft - - Games: Dragon Ball Z 5, Dragon Ball Z Super - - MMC3 clone. Writes to 0x4100-0x5fff (or from 0x4020?) - possibly select higher VROM pages (to allow up to - 512 banks instead of 256 only): bit0 selects the - higher pages for PPU banks 0-3 (0x0000-0x0fff), while - bit4 selects the higher pages for PPU banks 4-7 (0x1000-0x1fff) - - iNES: mapper 12 - - In MESS: Supported - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_rex_dbz5_device::write_l) -{ - LOG_MMC(("rex_dbz write_l, offset: %04x, data: %02x\n", offset, data)); - - m_extra = data; - set_chr(m_chr_source, m_chr_base, m_chr_mask); -} - -/* we would need to use this read handler in 0x6000-0x7fff as well */ -READ8_MEMBER(nes_rex_dbz5_device::read_l) -{ - LOG_MMC(("rex_dbz read_l, offset: %04x\n", offset)); - return 0x01; -} - -void nes_rex_dbz5_device::chr_cb(int start, int bank, int source) -{ - int shift = (start < 4) ? 8 : 4; - - bank |= ((m_extra << shift) & 0x100); - chr1_x(start, bank, source); -} - -/*------------------------------------------------- - - Rex Soft SL1632 Board - - Games: Samurai Spirits - - MMC3 clone - - iNES: mapper 14 - - In MESS: Supported - - -------------------------------------------------*/ - -void nes_rex_sl1632_device::set_prg(int prg_base, int prg_mask) -{ - if (m_mode & 0x02) - { - // here standard MMC3 bankswitch - UINT8 prg_flip = (m_latch & 0x40) ? 2 : 0; - - prg_cb(0, prg_base | (m_mmc_prg_bank[0 ^ prg_flip] & prg_mask)); - prg_cb(1, prg_base | (m_mmc_prg_bank[1] & prg_mask)); - prg_cb(2, prg_base | (m_mmc_prg_bank[2 ^ prg_flip] & prg_mask)); - prg_cb(3, prg_base | (m_mmc_prg_bank[3] & prg_mask)); - } - else - { - prg8_89(m_extra_bank[0]); - prg8_ab(m_extra_bank[1]); - prg8_cd(m_extra_bank[2]); - prg8_ef(m_extra_bank[3]); - } -} - -void nes_rex_sl1632_device::set_chr(UINT8 chr, int chr_base, int chr_mask) -{ - static const UINT8 conv_table[8] = {5, 5, 5, 5, 3, 3, 1, 1}; - UINT8 chr_page = (m_latch & 0x80) >> 5; - UINT8 bank[8]; - UINT8 chr_base2[8]; - - if (m_mode & 0x02) - { - for (int i = 0; i < 8; i++) - { - // since the mapper acts on 1K CHR chunks, we have 8 banks which use the 6 m_mmc_vrom_bank from MMC3 base class - if (i < 4) - bank[i] = ((m_mmc_vrom_bank[i / 2] & 0xfe) | (i & 1)); - else - bank[i] = m_mmc_vrom_bank[i - 2]; - chr_base2[i] = chr_base | ((m_mode << conv_table[i]) & 0x100); - } - } - else - { - for (int i = 0; i < 8; i++) - { - bank[i] = m_extra_bank[i + 4]; // first 4 m_extra_banks are PRG - chr_base2[i] = chr_base; - } - } - - chr1_x(chr_page ^ 0, chr_base2[0] | (bank[0] & chr_mask), chr); - chr1_x(chr_page ^ 1, chr_base2[1] | (bank[1] & chr_mask), chr); - chr1_x(chr_page ^ 2, chr_base2[2] | (bank[2] & chr_mask), chr); - chr1_x(chr_page ^ 3, chr_base2[3] | (bank[3] & chr_mask), chr); - chr1_x(chr_page ^ 4, chr_base2[4] | (bank[4] & chr_mask), chr); - chr1_x(chr_page ^ 5, chr_base2[5] | (bank[5] & chr_mask), chr); - chr1_x(chr_page ^ 6, chr_base2[6] | (bank[6] & chr_mask), chr); - chr1_x(chr_page ^ 7, chr_base2[7] | (bank[7] & chr_mask), chr); -} - -WRITE8_MEMBER(nes_rex_sl1632_device::write_h) -{ - UINT8 helper1, helper2; - LOG_MMC(("rex_sl1632 write_h, offset: %04x, data: %02x\n", offset, data)); - - if (offset == 0x2131) - { - m_mode = data; - set_prg(m_prg_base, m_prg_mask); - set_chr(m_chr_source, m_chr_base, m_chr_mask); - - if (!(m_mode & 0x02)) - set_nt_mirroring(BIT(m_mirror, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); - } - - if (m_mode & 0x02) - { - switch (offset & 0x6001) - { - case 0x2000: - set_nt_mirroring(BIT(m_mirror, 0) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ); - break; - - default: - txrom_write(space, offset, data, mem_mask); - break; - } - } - else if (offset >= 0x3000 && offset <= 0x6003) - { - helper1 = (offset & 0x01) << 2; - offset = ((offset & 0x02) | (offset >> 10)) >> 1; - helper2 = ((offset + 2) & 0x07) + 4; // '+4' because first 4 m_extra_banks are for PRG! - m_extra_bank[helper2] = (m_extra_bank[helper2] & (0xf0 >> helper1)) | ((data & 0x0f) << helper1); - set_chr(m_chr_source, m_chr_base, m_chr_mask); - } - else - { - switch (offset & 0x7003) - { - case 0x0000: - case 0x2000: - m_extra_bank[offset >> 13] = data; - set_prg(m_prg_base, m_prg_mask); - break; - - case 0x1000: - m_mirror = data; - set_nt_mirroring(BIT(m_mirror, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); - break; - } - } -} diff --git a/src/devices/bus/nes/rexsoft.cpp b/src/devices/bus/nes/rexsoft.cpp new file mode 100644 index 00000000000..c0e261dc5fa --- /dev/null +++ b/src/devices/bus/nes/rexsoft.cpp @@ -0,0 +1,262 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for Rex Soft PCBs + + + Here we emulate the following PCBs + + * Rex Soft DragonBall Z V [mapper 12] + * Rex Soft SL-1632 [mapper 14] + + TODO: + - fix 0x6000-0x7fff accesses, write_m/read_m + - check glitches in SL-1632 + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "rexsoft.h" + + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_REX_DBZ5 = &device_creator; +const device_type NES_REX_SL1632 = &device_creator; + + +nes_rex_dbz5_device::nes_rex_dbz5_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_REX_DBZ5, "NES Cart Rex Soft DragonBall Z V PCB", tag, owner, clock, "nes_rex_dbz5", __FILE__) +{ +} + +nes_rex_sl1632_device::nes_rex_sl1632_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_REX_SL1632, "NES Cart Rex Soft SL-1632 PCB", tag, owner, clock, "nes_rex_sl1632", __FILE__) +{ +} + + + + +void nes_rex_dbz5_device::device_start() +{ + mmc3_start(); + save_item(NAME(m_extra)); +} + +void nes_rex_dbz5_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + m_extra = 0; + mmc3_common_initialize(0xff, 0xff, 0); +} + +void nes_rex_sl1632_device::device_start() +{ + mmc3_start(); + save_item(NAME(m_mode)); + save_item(NAME(m_mirror)); + save_item(NAME(m_extra_bank)); +} + +void nes_rex_sl1632_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + + m_mode = 0; + m_mirror = 0; + memset(m_extra_bank, 0, sizeof(m_extra_bank)); + m_extra_bank[2] = 0xfe; + m_extra_bank[3] = 0xff; + mmc3_common_initialize(0xff, 0xff, 0); +} + + + + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + Bootleg Board by Rex Soft + + Games: Dragon Ball Z 5, Dragon Ball Z Super + + MMC3 clone. Writes to 0x4100-0x5fff (or from 0x4020?) + possibly select higher VROM pages (to allow up to + 512 banks instead of 256 only): bit0 selects the + higher pages for PPU banks 0-3 (0x0000-0x0fff), while + bit4 selects the higher pages for PPU banks 4-7 (0x1000-0x1fff) + + iNES: mapper 12 + + In MESS: Supported + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_rex_dbz5_device::write_l) +{ + LOG_MMC(("rex_dbz write_l, offset: %04x, data: %02x\n", offset, data)); + + m_extra = data; + set_chr(m_chr_source, m_chr_base, m_chr_mask); +} + +/* we would need to use this read handler in 0x6000-0x7fff as well */ +READ8_MEMBER(nes_rex_dbz5_device::read_l) +{ + LOG_MMC(("rex_dbz read_l, offset: %04x\n", offset)); + return 0x01; +} + +void nes_rex_dbz5_device::chr_cb(int start, int bank, int source) +{ + int shift = (start < 4) ? 8 : 4; + + bank |= ((m_extra << shift) & 0x100); + chr1_x(start, bank, source); +} + +/*------------------------------------------------- + + Rex Soft SL1632 Board + + Games: Samurai Spirits + + MMC3 clone + + iNES: mapper 14 + + In MESS: Supported + + -------------------------------------------------*/ + +void nes_rex_sl1632_device::set_prg(int prg_base, int prg_mask) +{ + if (m_mode & 0x02) + { + // here standard MMC3 bankswitch + UINT8 prg_flip = (m_latch & 0x40) ? 2 : 0; + + prg_cb(0, prg_base | (m_mmc_prg_bank[0 ^ prg_flip] & prg_mask)); + prg_cb(1, prg_base | (m_mmc_prg_bank[1] & prg_mask)); + prg_cb(2, prg_base | (m_mmc_prg_bank[2 ^ prg_flip] & prg_mask)); + prg_cb(3, prg_base | (m_mmc_prg_bank[3] & prg_mask)); + } + else + { + prg8_89(m_extra_bank[0]); + prg8_ab(m_extra_bank[1]); + prg8_cd(m_extra_bank[2]); + prg8_ef(m_extra_bank[3]); + } +} + +void nes_rex_sl1632_device::set_chr(UINT8 chr, int chr_base, int chr_mask) +{ + static const UINT8 conv_table[8] = {5, 5, 5, 5, 3, 3, 1, 1}; + UINT8 chr_page = (m_latch & 0x80) >> 5; + UINT8 bank[8]; + UINT8 chr_base2[8]; + + if (m_mode & 0x02) + { + for (int i = 0; i < 8; i++) + { + // since the mapper acts on 1K CHR chunks, we have 8 banks which use the 6 m_mmc_vrom_bank from MMC3 base class + if (i < 4) + bank[i] = ((m_mmc_vrom_bank[i / 2] & 0xfe) | (i & 1)); + else + bank[i] = m_mmc_vrom_bank[i - 2]; + chr_base2[i] = chr_base | ((m_mode << conv_table[i]) & 0x100); + } + } + else + { + for (int i = 0; i < 8; i++) + { + bank[i] = m_extra_bank[i + 4]; // first 4 m_extra_banks are PRG + chr_base2[i] = chr_base; + } + } + + chr1_x(chr_page ^ 0, chr_base2[0] | (bank[0] & chr_mask), chr); + chr1_x(chr_page ^ 1, chr_base2[1] | (bank[1] & chr_mask), chr); + chr1_x(chr_page ^ 2, chr_base2[2] | (bank[2] & chr_mask), chr); + chr1_x(chr_page ^ 3, chr_base2[3] | (bank[3] & chr_mask), chr); + chr1_x(chr_page ^ 4, chr_base2[4] | (bank[4] & chr_mask), chr); + chr1_x(chr_page ^ 5, chr_base2[5] | (bank[5] & chr_mask), chr); + chr1_x(chr_page ^ 6, chr_base2[6] | (bank[6] & chr_mask), chr); + chr1_x(chr_page ^ 7, chr_base2[7] | (bank[7] & chr_mask), chr); +} + +WRITE8_MEMBER(nes_rex_sl1632_device::write_h) +{ + UINT8 helper1, helper2; + LOG_MMC(("rex_sl1632 write_h, offset: %04x, data: %02x\n", offset, data)); + + if (offset == 0x2131) + { + m_mode = data; + set_prg(m_prg_base, m_prg_mask); + set_chr(m_chr_source, m_chr_base, m_chr_mask); + + if (!(m_mode & 0x02)) + set_nt_mirroring(BIT(m_mirror, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + } + + if (m_mode & 0x02) + { + switch (offset & 0x6001) + { + case 0x2000: + set_nt_mirroring(BIT(m_mirror, 0) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ); + break; + + default: + txrom_write(space, offset, data, mem_mask); + break; + } + } + else if (offset >= 0x3000 && offset <= 0x6003) + { + helper1 = (offset & 0x01) << 2; + offset = ((offset & 0x02) | (offset >> 10)) >> 1; + helper2 = ((offset + 2) & 0x07) + 4; // '+4' because first 4 m_extra_banks are for PRG! + m_extra_bank[helper2] = (m_extra_bank[helper2] & (0xf0 >> helper1)) | ((data & 0x0f) << helper1); + set_chr(m_chr_source, m_chr_base, m_chr_mask); + } + else + { + switch (offset & 0x7003) + { + case 0x0000: + case 0x2000: + m_extra_bank[offset >> 13] = data; + set_prg(m_prg_base, m_prg_mask); + break; + + case 0x1000: + m_mirror = data; + set_nt_mirroring(BIT(m_mirror, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + break; + } + } +} diff --git a/src/devices/bus/nes/sachen.c b/src/devices/bus/nes/sachen.c deleted file mode 100644 index 87edbc6a700..00000000000 --- a/src/devices/bus/nes/sachen.c +++ /dev/null @@ -1,695 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Fabio Priuli -/*********************************************************************************************************** - - - NES/Famicom cartridge emulation for Sachen PCBs - - - Here we emulate the following PCBs - - * Sachen SA-009 [mapper 160] - * Sachen SA-0036 [mapper 148] - * Sachen SA-0037 [mapper 149] - * Sachen SA-72007 [mapper 145] - * Sachen SA-72008 [mapper 133] - * Sachen TCA-01 [mapper 143] - * Sachen TCU-01 [mapper 147] - * Sachen TCU-02 [mapper 136] - * Sachen Discrete PCBs [mapper 150 & 243] - * Sachen 8259 [mapper 141 (A), 138 (B), 139 (C), 137 (D)] - - Known issues on specific mappers: - - * 133 Qi Wang starts with corrupted graphics (ingame seems better) - - - ***********************************************************************************************************/ - - -#include "emu.h" -#include "sachen.h" - - -#ifdef NES_PCB_DEBUG -#define VERBOSE 1 -#else -#define VERBOSE 0 -#endif - -#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) - - -//------------------------------------------------- -// constructor -//------------------------------------------------- - -const device_type NES_SACHEN_SA009 = &device_creator; -const device_type NES_SACHEN_SA0036 = &device_creator; -const device_type NES_SACHEN_SA0037 = &device_creator; -const device_type NES_SACHEN_SA72007 = &device_creator; -const device_type NES_SACHEN_SA72008 = &device_creator; -const device_type NES_SACHEN_TCA01 = &device_creator; -const device_type NES_SACHEN_TCU01 = &device_creator; -const device_type NES_SACHEN_TCU02 = &device_creator; -const device_type NES_SACHEN_74X374 = &device_creator; -const device_type NES_SACHEN_74X374_ALT = &device_creator; -const device_type NES_SACHEN_8259A = &device_creator; -const device_type NES_SACHEN_8259B = &device_creator; -const device_type NES_SACHEN_8259C = &device_creator; -const device_type NES_SACHEN_8259D = &device_creator; - - -nes_sachen_sa009_device::nes_sachen_sa009_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_SACHEN_SA009, "NES Cart Sachen SA009 PCB", tag, owner, clock, "nes_sa009", __FILE__) -{ -} - -nes_sachen_sa0036_device::nes_sachen_sa0036_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_SACHEN_SA0036, "NES Cart Sachen sa0036 PCB", tag, owner, clock, "nes_sa0036", __FILE__) -{ -} - -nes_sachen_sa0037_device::nes_sachen_sa0037_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_SACHEN_SA0037, "NES Cart Sachen sa0037 PCB", tag, owner, clock, "nes_sa0037", __FILE__) -{ -} - -nes_sachen_sa72007_device::nes_sachen_sa72007_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_SACHEN_SA72007, "NES Cart Sachen SA72007 PCB", tag, owner, clock, "nes_sa72007", __FILE__) -{ -} - -nes_sachen_sa72008_device::nes_sachen_sa72008_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_SACHEN_SA72008, "NES Cart Sachen SA72008 PCB", tag, owner, clock, "nes_sa72008", __FILE__) -{ -} - -nes_sachen_tca01_device::nes_sachen_tca01_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_SACHEN_TCA01, "NES Cart Sachen TCA-01 PCB", tag, owner, clock, "nes_tca01", __FILE__) -{ -} - -nes_sachen_tcu01_device::nes_sachen_tcu01_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_SACHEN_TCU01, "NES Cart Sachen TCU-01 PCB", tag, owner, clock, "nes_tcu01", __FILE__) -{ -} - -nes_sachen_tcu02_device::nes_sachen_tcu02_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_SACHEN_TCU02, "NES Cart Sachen TCU-02 PCB", tag, owner, clock, "nes_tcu02", __FILE__) -{ -} - -nes_sachen_74x374_device::nes_sachen_74x374_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) - : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source) -{ -} - -nes_sachen_74x374_device::nes_sachen_74x374_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_SACHEN_74X374, "NES Cart Sachen 74*374 PCB", tag, owner, clock, "nes_s74x34", __FILE__) -{ -} - -nes_sachen_74x374_alt_device::nes_sachen_74x374_alt_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_sachen_74x374_device(mconfig, NES_SACHEN_74X374_ALT, "NES Cart Sachen 74*374 Alt PCB", tag, owner, clock, "nes_s74x34a", __FILE__) -{ -} - -nes_sachen_8259a_device::nes_sachen_8259a_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) - : nes_sachen_74x374_device(mconfig, type, name, tag, owner, clock, shortname, source) -{ -} - -nes_sachen_8259a_device::nes_sachen_8259a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_sachen_74x374_device(mconfig, NES_SACHEN_8259A, "NES Cart Sachen 8259A PCB", tag, owner, clock, "nes_s8259a", __FILE__) -{ -} - -nes_sachen_8259b_device::nes_sachen_8259b_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_sachen_8259a_device(mconfig, NES_SACHEN_8259B, "NES Cart Sachen 8259B PCB", tag, owner, clock, "nes_s8259b", __FILE__) -{ -} - -nes_sachen_8259c_device::nes_sachen_8259c_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_sachen_8259a_device(mconfig, NES_SACHEN_8259C, "NES Cart Sachen 8259C PCB", tag, owner, clock, "nes_s8259c", __FILE__) -{ -} - -nes_sachen_8259d_device::nes_sachen_8259d_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_sachen_8259a_device(mconfig, NES_SACHEN_8259D, "NES Cart Sachen 8259D PCB", tag, owner, clock, "nes_s8259d", __FILE__) -{ -} - - - - -void nes_sachen_sa009_device::device_start() -{ - common_start(); -} - -void nes_sachen_sa009_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0); - chr8(0, m_chr_source); -} - -void nes_sachen_sa0036_device::device_start() -{ - common_start(); -} - -void nes_sachen_sa0036_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0); - chr8(0, m_chr_source); -} - -void nes_sachen_sa0037_device::device_start() -{ - common_start(); -} - -void nes_sachen_sa0037_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0); - chr8(0, m_chr_source); -} - -void nes_sachen_sa72007_device::device_start() -{ - common_start(); -} - -void nes_sachen_sa72007_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0); - chr8(0, m_chr_source); -} - -void nes_sachen_sa72008_device::device_start() -{ - common_start(); -} - -void nes_sachen_sa72008_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0); - chr8(0, m_chr_source); -} - -void nes_sachen_tca01_device::device_start() -{ - common_start(); -} - -void nes_sachen_tca01_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(0); - prg16_cdef(1); - chr8(0, m_chr_source); -} - -void nes_sachen_tcu01_device::device_start() -{ - common_start(); -} - -void nes_sachen_tcu01_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0); - chr8(0, m_chr_source); -} - -void nes_sachen_tcu02_device::device_start() -{ - common_start(); - save_item(NAME(m_latch)); -} - -void nes_sachen_tcu02_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0); - chr8(0, m_chr_source); - - m_latch = 0; -} - -void nes_sachen_74x374_device::device_start() -{ - common_start(); - save_item(NAME(m_latch)); - save_item(NAME(m_mmc_vrom_bank)); -} - -void nes_sachen_74x374_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0); - chr8(0, m_chr_source); - - m_latch = 0; - m_mmc_vrom_bank = 0; -} - -void nes_sachen_8259a_device::device_start() -{ - common_start(); - save_item(NAME(m_latch)); - save_item(NAME(m_reg)); -} - -void nes_sachen_8259a_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0); - chr8(0, m_chr_source); - set_nt_mirroring(PPU_MIRROR_VERT); - - m_latch = 0; - memset(m_reg, 0, sizeof(m_reg)); -} - -void nes_sachen_8259d_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0); - chr8(m_vrom_chunks - 1, CHRROM); - set_nt_mirroring(PPU_MIRROR_VERT); - - m_latch = 0; - memset(m_reg, 0, sizeof(m_reg)); -} - - - - -/*------------------------------------------------- - mapper specific handlers - -------------------------------------------------*/ - -/*------------------------------------------------- - - Sachen SA009 bootleg boards - - Games: Pipe 5 - - iNES: mapper 160 - - In MESS: Supported. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_sachen_sa009_device::write_l) -{ - LOG_MMC(("SA009 write_l, offset: %04x, data: %02x\n", offset, data)); - - chr8(data, m_chr_source); -} - -/*------------------------------------------------- - - Sachen SA0036 bootleg boards - - Games: Taiwan Mahjong 16 - - iNES: mapper 149 - - In MESS: Supported. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_sachen_sa0036_device::write_h) -{ - LOG_MMC(("sa0036 write_h, offset: %04x, data: %02x\n", offset, data)); - - chr8(data >> 7, CHRROM); -} - -/*------------------------------------------------- - - Sachen SA0037 bootleg boards - - Games: Mahjong World, Shisen Mahjong - - iNES: mapper 148 - - In MESS: Supported. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_sachen_sa0037_device::write_h) -{ - LOG_MMC(("sa0037 write_h, offset: %04x, data: %02x\n", offset, data)); - - // this pcb is subject to bus conflict - data = account_bus_conflict(offset, data); - - prg32(data >> 3); - chr8(data, CHRROM); -} - -/*------------------------------------------------- - - Sachen SA72007 bootleg boards - - Games: Sidewinder - - iNES: mapper 145 - - In MESS: Supported. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_sachen_sa72007_device::write_l) -{ - LOG_MMC(("SA72007 write_l, offset: %04x, data: %02x\n", offset, data)); - - /* only if we are at 0x4100 + k * 0x200, but 0x4100 is offset = 0 */ - if (!(offset & 0x100)) - chr8(data >> 7, CHRROM); -} - -/*------------------------------------------------- - - Sachen SA72008 bootleg boards - - Games: Jovial Race, Qi Wang - - iNES: mapper 133 - - In MESS: Supported. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_sachen_sa72008_device::write_l) -{ - LOG_MMC(("SA72008 write_l, offset: %04x, data: %02x\n", offset, data)); - - prg32(data >> 2); - chr8(data, CHRROM); -} - -/*------------------------------------------------- - - Sachen TCA-01 bootleg boards - - iNES: mapper 143 - - Games: Dancing Blocks, Magic Mathematic - - In MESS: Supported. - - -------------------------------------------------*/ - -READ8_MEMBER(nes_sachen_tca01_device::read_l) -{ - LOG_MMC(("TCA-01 read_l, offset: %04x\n", offset)); - - /* the address is read only if we are at 0x4100 + k * 0x200, but 0x4100 is offset = 0 */ - if (!(offset & 0x100)) - return (~offset & 0x3f) | 0x40; - else - return 0x00; -} - -/*------------------------------------------------- - - Sachen TCU-01 bootleg boards - - Games: Challenge of the Dragon, Chinese Kungfu - - iNES: mapper 147 - - In MESS: Supported. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_sachen_tcu01_device::write_l) -{ - LOG_MMC(("TCU-01 write_l, offset: %04x, data: %02x\n", offset, data)); - - if ((offset & 0x103) == 0x002) - { - prg32(((data >> 6) & 0x02) | ((data >> 2) & 0x01)); - chr8(data >> 3, CHRROM); - } -} - -/*------------------------------------------------- - - Sachen TCU-02 bootleg boards - - Games: Wei Lai Xiao Zi - - iNES: mapper 136 - - In MESS: Supported. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_sachen_tcu02_device::write_l) -{ - LOG_MMC(("TCU-02 write_l, offset: %04x, data: %02x\n", offset, data)); - - if ((offset & 0x103) == 0x002) - { - m_latch = (data & 0x30) | ((data + 3) & 0x0f); - chr8(m_latch, CHRROM); - } -} - -READ8_MEMBER(nes_sachen_tcu02_device::read_l) -{ - LOG_MMC(("TCU-02 read_l, offset: %04x\n", offset)); - - if ((offset & 0x103) == 0x000) - return m_latch | 0x40; - else - return 0x00; -} - -/*------------------------------------------------- - - Sachen 74x374 bootleg boards - - Games: Chess Academy, Chinese Checkers Jpn, Mahjong Academy, - Olympic IQ, Poker II, Tasac [150], Poker III [243] - - iNES: mappers 150 & 243 - - -------------------------------------------------*/ - -void nes_sachen_74x374_device::set_mirror(UINT8 nt) // also used by mappers 137, 138, 139, 141 -{ - switch (nt) - { - case 0: - case 1: - set_nt_mirroring(nt ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); - break; - case 2: - set_nt_page(0, CIRAM, 0, 1); - set_nt_page(1, CIRAM, 1, 1); - set_nt_page(2, CIRAM, 1, 1); - set_nt_page(3, CIRAM, 1, 1); - break; - case 3: - set_nt_mirroring(PPU_MIRROR_LOW); - break; - default: - LOG_MMC(("Mapper set NT to invalid value %02x", nt)); - break; - } -} - - -WRITE8_MEMBER(nes_sachen_74x374_device::write_l) -{ - LOG_MMC(("Sachen 74*374 write_l, offset: %04x, data: %02x\n", offset, data)); - - /* write happens only if we are at 0x4100 + k * 0x200, but 0x4100 is offset = 0 */ - if (!(offset & 0x100)) - { - if (!(offset & 0x01)) - m_latch = data & 0x07; - else - { - switch (m_latch) - { - case 0x02: - m_mmc_vrom_bank = (m_mmc_vrom_bank & ~0x08) | ((data << 3) & 0x08); - chr8(m_mmc_vrom_bank, CHRROM); - prg32(data & 0x01); - break; - case 0x04: - m_mmc_vrom_bank = (m_mmc_vrom_bank & ~0x04) | ((data << 2) & 0x04); - chr8(m_mmc_vrom_bank, CHRROM); - break; - case 0x05: - prg32(data & 0x07); - break; - case 0x06: - m_mmc_vrom_bank = (m_mmc_vrom_bank & ~0x03) | ((data << 0) & 0x03); - chr8(m_mmc_vrom_bank, CHRROM); - break; - case 0x07: - set_mirror((data >> 1) & 0x03); - break; - default: - break; - } - } - } -} - -READ8_MEMBER(nes_sachen_74x374_device::read_l) -{ - LOG_MMC(("Sachen 74*374 read_l, offset: %04x", offset)); - - /* read happens only if we are at 0x4100 + k * 0x200, but 0x4100 is offset = 0 */ - if (!(offset & 0x100)) - return (~m_latch & 0x3f) /* ^ dips*/; // we would need to check the Dips here - else - return 0; -} - -WRITE8_MEMBER(nes_sachen_74x374_alt_device::write_l) -{ - LOG_MMC(("Sachen 74*374 Alt write_l, offset: %04x, data: %02x\n", offset, data)); - - /* write happens only if we are at 0x4100 + k * 0x200, but 0x4100 is offset = 0 */ - if (!(offset & 0x100)) - { - if (!(offset & 0x01)) - m_latch = data; - else - { - switch (m_latch & 0x07) - { - case 0x00: - prg32(0); - chr8(3, CHRROM); - break; - case 0x02: - m_mmc_vrom_bank = (m_mmc_vrom_bank & ~0x08) | ((data << 3) & 0x08); - chr8(m_mmc_vrom_bank, CHRROM); - break; - case 0x04: - m_mmc_vrom_bank = (m_mmc_vrom_bank & ~0x01) | ((data << 0) & 0x01); - chr8(m_mmc_vrom_bank, CHRROM); - break; - case 0x05: - prg32(data & 0x01); - break; - case 0x06: - m_mmc_vrom_bank = (m_mmc_vrom_bank & ~0x06) | ((data << 1) & 0x06); - chr8(m_mmc_vrom_bank, CHRROM); - break; - case 0x07: - set_mirror(BIT(data, 0)); - break; - default: - break; - } - } - } -} - -/*------------------------------------------------- - - Sachen S8259 bootleg boards - - iNES: mapper 141 (A), 138 (B), 139 (C), 137 (D) - - -------------------------------------------------*/ - -void nes_sachen_8259a_device::chr_update() -{ - UINT8 bank_helper1 = m_reg[7] & 0x01; - UINT8 bank_helper2 = (m_reg[4] & 0x07) << 3; - - if (m_chr_source == CHRROM) - { - chr2_0(((m_reg[bank_helper1 ? 0 : 0] & 0x07) | bank_helper2) << 1 | 0, CHRROM); - chr2_2(((m_reg[bank_helper1 ? 0 : 1] & 0x07) | bank_helper2) << 1 | 1, CHRROM); - chr2_4(((m_reg[bank_helper1 ? 0 : 2] & 0x07) | bank_helper2) << 1 | 0, CHRROM); - chr2_6(((m_reg[bank_helper1 ? 0 : 3] & 0x07) | bank_helper2) << 1 | 1, CHRROM); - } -} - -WRITE8_MEMBER(nes_sachen_8259a_device::write_l) -{ - LOG_MMC(("Sachen 8259 write_l, offset: %04x, data: %02x\n", offset, data)); - - /* write happens only if we are at 0x4100 + k * 0x200, but 0x4100 is offset = 0 */ - if (!(offset & 0x100)) - { - if (!(offset & 0x01)) - m_latch = data & 0x07; - else - { - m_reg[m_latch] = data; - - switch (m_latch) - { - case 0x05: - prg32(data); - break; - case 0x07: - set_mirror(BIT(data, 0) ? 0 : (data >> 1) & 0x03); - break; - default: - chr_update(); - break; - } - } - } -} - -void nes_sachen_8259b_device::chr_update() -{ - UINT8 bank_helper1 = m_reg[7] & 0x01; - UINT8 bank_helper2 = (m_reg[4] & 0x07) << 3; - - if (m_chr_source == CHRROM) - { - chr2_0(((m_reg[bank_helper1 ? 0 : 0] & 0x07) | bank_helper2), CHRROM); - chr2_2(((m_reg[bank_helper1 ? 0 : 1] & 0x07) | bank_helper2), CHRROM); - chr2_4(((m_reg[bank_helper1 ? 0 : 2] & 0x07) | bank_helper2), CHRROM); - chr2_6(((m_reg[bank_helper1 ? 0 : 3] & 0x07) | bank_helper2), CHRROM); - } -} - -void nes_sachen_8259c_device::chr_update() -{ - UINT8 bank_helper1 = m_reg[7] & 0x01; - UINT8 bank_helper2 = (m_reg[4] & 0x07) << 3; - - if (m_chr_source == CHRROM) - { - chr2_0(((m_reg[bank_helper1 ? 0 : 0] & 0x07) | bank_helper2) << 2 | 0, CHRROM); - chr2_2(((m_reg[bank_helper1 ? 0 : 1] & 0x07) | bank_helper2) << 2 | 1, CHRROM); - chr2_4(((m_reg[bank_helper1 ? 0 : 2] & 0x07) | bank_helper2) << 2 | 2, CHRROM); - chr2_6(((m_reg[bank_helper1 ? 0 : 3] & 0x07) | bank_helper2) << 2 | 3, CHRROM); - } -} - -void nes_sachen_8259d_device::chr_update() -{ - if (m_chr_source == CHRROM) - { - chr1_0((m_reg[0] & 0x07), CHRROM); - chr1_1((m_reg[1] & 0x07) | (m_reg[4] << 4 & 0x10), CHRROM); - chr1_2((m_reg[2] & 0x07) | (m_reg[4] << 3 & 0x10), CHRROM); - chr1_3((m_reg[3] & 0x07) | (m_reg[4] << 2 & 0x10) | (m_reg[6] << 3 & 0x08), CHRROM); - } -} diff --git a/src/devices/bus/nes/sachen.cpp b/src/devices/bus/nes/sachen.cpp new file mode 100644 index 00000000000..87edbc6a700 --- /dev/null +++ b/src/devices/bus/nes/sachen.cpp @@ -0,0 +1,695 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for Sachen PCBs + + + Here we emulate the following PCBs + + * Sachen SA-009 [mapper 160] + * Sachen SA-0036 [mapper 148] + * Sachen SA-0037 [mapper 149] + * Sachen SA-72007 [mapper 145] + * Sachen SA-72008 [mapper 133] + * Sachen TCA-01 [mapper 143] + * Sachen TCU-01 [mapper 147] + * Sachen TCU-02 [mapper 136] + * Sachen Discrete PCBs [mapper 150 & 243] + * Sachen 8259 [mapper 141 (A), 138 (B), 139 (C), 137 (D)] + + Known issues on specific mappers: + + * 133 Qi Wang starts with corrupted graphics (ingame seems better) + + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "sachen.h" + + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_SACHEN_SA009 = &device_creator; +const device_type NES_SACHEN_SA0036 = &device_creator; +const device_type NES_SACHEN_SA0037 = &device_creator; +const device_type NES_SACHEN_SA72007 = &device_creator; +const device_type NES_SACHEN_SA72008 = &device_creator; +const device_type NES_SACHEN_TCA01 = &device_creator; +const device_type NES_SACHEN_TCU01 = &device_creator; +const device_type NES_SACHEN_TCU02 = &device_creator; +const device_type NES_SACHEN_74X374 = &device_creator; +const device_type NES_SACHEN_74X374_ALT = &device_creator; +const device_type NES_SACHEN_8259A = &device_creator; +const device_type NES_SACHEN_8259B = &device_creator; +const device_type NES_SACHEN_8259C = &device_creator; +const device_type NES_SACHEN_8259D = &device_creator; + + +nes_sachen_sa009_device::nes_sachen_sa009_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_SACHEN_SA009, "NES Cart Sachen SA009 PCB", tag, owner, clock, "nes_sa009", __FILE__) +{ +} + +nes_sachen_sa0036_device::nes_sachen_sa0036_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_SACHEN_SA0036, "NES Cart Sachen sa0036 PCB", tag, owner, clock, "nes_sa0036", __FILE__) +{ +} + +nes_sachen_sa0037_device::nes_sachen_sa0037_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_SACHEN_SA0037, "NES Cart Sachen sa0037 PCB", tag, owner, clock, "nes_sa0037", __FILE__) +{ +} + +nes_sachen_sa72007_device::nes_sachen_sa72007_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_SACHEN_SA72007, "NES Cart Sachen SA72007 PCB", tag, owner, clock, "nes_sa72007", __FILE__) +{ +} + +nes_sachen_sa72008_device::nes_sachen_sa72008_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_SACHEN_SA72008, "NES Cart Sachen SA72008 PCB", tag, owner, clock, "nes_sa72008", __FILE__) +{ +} + +nes_sachen_tca01_device::nes_sachen_tca01_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_SACHEN_TCA01, "NES Cart Sachen TCA-01 PCB", tag, owner, clock, "nes_tca01", __FILE__) +{ +} + +nes_sachen_tcu01_device::nes_sachen_tcu01_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_SACHEN_TCU01, "NES Cart Sachen TCU-01 PCB", tag, owner, clock, "nes_tcu01", __FILE__) +{ +} + +nes_sachen_tcu02_device::nes_sachen_tcu02_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_SACHEN_TCU02, "NES Cart Sachen TCU-02 PCB", tag, owner, clock, "nes_tcu02", __FILE__) +{ +} + +nes_sachen_74x374_device::nes_sachen_74x374_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +nes_sachen_74x374_device::nes_sachen_74x374_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_SACHEN_74X374, "NES Cart Sachen 74*374 PCB", tag, owner, clock, "nes_s74x34", __FILE__) +{ +} + +nes_sachen_74x374_alt_device::nes_sachen_74x374_alt_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_sachen_74x374_device(mconfig, NES_SACHEN_74X374_ALT, "NES Cart Sachen 74*374 Alt PCB", tag, owner, clock, "nes_s74x34a", __FILE__) +{ +} + +nes_sachen_8259a_device::nes_sachen_8259a_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : nes_sachen_74x374_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +nes_sachen_8259a_device::nes_sachen_8259a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_sachen_74x374_device(mconfig, NES_SACHEN_8259A, "NES Cart Sachen 8259A PCB", tag, owner, clock, "nes_s8259a", __FILE__) +{ +} + +nes_sachen_8259b_device::nes_sachen_8259b_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_sachen_8259a_device(mconfig, NES_SACHEN_8259B, "NES Cart Sachen 8259B PCB", tag, owner, clock, "nes_s8259b", __FILE__) +{ +} + +nes_sachen_8259c_device::nes_sachen_8259c_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_sachen_8259a_device(mconfig, NES_SACHEN_8259C, "NES Cart Sachen 8259C PCB", tag, owner, clock, "nes_s8259c", __FILE__) +{ +} + +nes_sachen_8259d_device::nes_sachen_8259d_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_sachen_8259a_device(mconfig, NES_SACHEN_8259D, "NES Cart Sachen 8259D PCB", tag, owner, clock, "nes_s8259d", __FILE__) +{ +} + + + + +void nes_sachen_sa009_device::device_start() +{ + common_start(); +} + +void nes_sachen_sa009_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + +void nes_sachen_sa0036_device::device_start() +{ + common_start(); +} + +void nes_sachen_sa0036_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + +void nes_sachen_sa0037_device::device_start() +{ + common_start(); +} + +void nes_sachen_sa0037_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + +void nes_sachen_sa72007_device::device_start() +{ + common_start(); +} + +void nes_sachen_sa72007_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + +void nes_sachen_sa72008_device::device_start() +{ + common_start(); +} + +void nes_sachen_sa72008_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + +void nes_sachen_tca01_device::device_start() +{ + common_start(); +} + +void nes_sachen_tca01_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(1); + chr8(0, m_chr_source); +} + +void nes_sachen_tcu01_device::device_start() +{ + common_start(); +} + +void nes_sachen_tcu01_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + +void nes_sachen_tcu02_device::device_start() +{ + common_start(); + save_item(NAME(m_latch)); +} + +void nes_sachen_tcu02_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); + + m_latch = 0; +} + +void nes_sachen_74x374_device::device_start() +{ + common_start(); + save_item(NAME(m_latch)); + save_item(NAME(m_mmc_vrom_bank)); +} + +void nes_sachen_74x374_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); + + m_latch = 0; + m_mmc_vrom_bank = 0; +} + +void nes_sachen_8259a_device::device_start() +{ + common_start(); + save_item(NAME(m_latch)); + save_item(NAME(m_reg)); +} + +void nes_sachen_8259a_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); + set_nt_mirroring(PPU_MIRROR_VERT); + + m_latch = 0; + memset(m_reg, 0, sizeof(m_reg)); +} + +void nes_sachen_8259d_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(m_vrom_chunks - 1, CHRROM); + set_nt_mirroring(PPU_MIRROR_VERT); + + m_latch = 0; + memset(m_reg, 0, sizeof(m_reg)); +} + + + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + Sachen SA009 bootleg boards + + Games: Pipe 5 + + iNES: mapper 160 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_sachen_sa009_device::write_l) +{ + LOG_MMC(("SA009 write_l, offset: %04x, data: %02x\n", offset, data)); + + chr8(data, m_chr_source); +} + +/*------------------------------------------------- + + Sachen SA0036 bootleg boards + + Games: Taiwan Mahjong 16 + + iNES: mapper 149 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_sachen_sa0036_device::write_h) +{ + LOG_MMC(("sa0036 write_h, offset: %04x, data: %02x\n", offset, data)); + + chr8(data >> 7, CHRROM); +} + +/*------------------------------------------------- + + Sachen SA0037 bootleg boards + + Games: Mahjong World, Shisen Mahjong + + iNES: mapper 148 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_sachen_sa0037_device::write_h) +{ + LOG_MMC(("sa0037 write_h, offset: %04x, data: %02x\n", offset, data)); + + // this pcb is subject to bus conflict + data = account_bus_conflict(offset, data); + + prg32(data >> 3); + chr8(data, CHRROM); +} + +/*------------------------------------------------- + + Sachen SA72007 bootleg boards + + Games: Sidewinder + + iNES: mapper 145 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_sachen_sa72007_device::write_l) +{ + LOG_MMC(("SA72007 write_l, offset: %04x, data: %02x\n", offset, data)); + + /* only if we are at 0x4100 + k * 0x200, but 0x4100 is offset = 0 */ + if (!(offset & 0x100)) + chr8(data >> 7, CHRROM); +} + +/*------------------------------------------------- + + Sachen SA72008 bootleg boards + + Games: Jovial Race, Qi Wang + + iNES: mapper 133 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_sachen_sa72008_device::write_l) +{ + LOG_MMC(("SA72008 write_l, offset: %04x, data: %02x\n", offset, data)); + + prg32(data >> 2); + chr8(data, CHRROM); +} + +/*------------------------------------------------- + + Sachen TCA-01 bootleg boards + + iNES: mapper 143 + + Games: Dancing Blocks, Magic Mathematic + + In MESS: Supported. + + -------------------------------------------------*/ + +READ8_MEMBER(nes_sachen_tca01_device::read_l) +{ + LOG_MMC(("TCA-01 read_l, offset: %04x\n", offset)); + + /* the address is read only if we are at 0x4100 + k * 0x200, but 0x4100 is offset = 0 */ + if (!(offset & 0x100)) + return (~offset & 0x3f) | 0x40; + else + return 0x00; +} + +/*------------------------------------------------- + + Sachen TCU-01 bootleg boards + + Games: Challenge of the Dragon, Chinese Kungfu + + iNES: mapper 147 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_sachen_tcu01_device::write_l) +{ + LOG_MMC(("TCU-01 write_l, offset: %04x, data: %02x\n", offset, data)); + + if ((offset & 0x103) == 0x002) + { + prg32(((data >> 6) & 0x02) | ((data >> 2) & 0x01)); + chr8(data >> 3, CHRROM); + } +} + +/*------------------------------------------------- + + Sachen TCU-02 bootleg boards + + Games: Wei Lai Xiao Zi + + iNES: mapper 136 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_sachen_tcu02_device::write_l) +{ + LOG_MMC(("TCU-02 write_l, offset: %04x, data: %02x\n", offset, data)); + + if ((offset & 0x103) == 0x002) + { + m_latch = (data & 0x30) | ((data + 3) & 0x0f); + chr8(m_latch, CHRROM); + } +} + +READ8_MEMBER(nes_sachen_tcu02_device::read_l) +{ + LOG_MMC(("TCU-02 read_l, offset: %04x\n", offset)); + + if ((offset & 0x103) == 0x000) + return m_latch | 0x40; + else + return 0x00; +} + +/*------------------------------------------------- + + Sachen 74x374 bootleg boards + + Games: Chess Academy, Chinese Checkers Jpn, Mahjong Academy, + Olympic IQ, Poker II, Tasac [150], Poker III [243] + + iNES: mappers 150 & 243 + + -------------------------------------------------*/ + +void nes_sachen_74x374_device::set_mirror(UINT8 nt) // also used by mappers 137, 138, 139, 141 +{ + switch (nt) + { + case 0: + case 1: + set_nt_mirroring(nt ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + break; + case 2: + set_nt_page(0, CIRAM, 0, 1); + set_nt_page(1, CIRAM, 1, 1); + set_nt_page(2, CIRAM, 1, 1); + set_nt_page(3, CIRAM, 1, 1); + break; + case 3: + set_nt_mirroring(PPU_MIRROR_LOW); + break; + default: + LOG_MMC(("Mapper set NT to invalid value %02x", nt)); + break; + } +} + + +WRITE8_MEMBER(nes_sachen_74x374_device::write_l) +{ + LOG_MMC(("Sachen 74*374 write_l, offset: %04x, data: %02x\n", offset, data)); + + /* write happens only if we are at 0x4100 + k * 0x200, but 0x4100 is offset = 0 */ + if (!(offset & 0x100)) + { + if (!(offset & 0x01)) + m_latch = data & 0x07; + else + { + switch (m_latch) + { + case 0x02: + m_mmc_vrom_bank = (m_mmc_vrom_bank & ~0x08) | ((data << 3) & 0x08); + chr8(m_mmc_vrom_bank, CHRROM); + prg32(data & 0x01); + break; + case 0x04: + m_mmc_vrom_bank = (m_mmc_vrom_bank & ~0x04) | ((data << 2) & 0x04); + chr8(m_mmc_vrom_bank, CHRROM); + break; + case 0x05: + prg32(data & 0x07); + break; + case 0x06: + m_mmc_vrom_bank = (m_mmc_vrom_bank & ~0x03) | ((data << 0) & 0x03); + chr8(m_mmc_vrom_bank, CHRROM); + break; + case 0x07: + set_mirror((data >> 1) & 0x03); + break; + default: + break; + } + } + } +} + +READ8_MEMBER(nes_sachen_74x374_device::read_l) +{ + LOG_MMC(("Sachen 74*374 read_l, offset: %04x", offset)); + + /* read happens only if we are at 0x4100 + k * 0x200, but 0x4100 is offset = 0 */ + if (!(offset & 0x100)) + return (~m_latch & 0x3f) /* ^ dips*/; // we would need to check the Dips here + else + return 0; +} + +WRITE8_MEMBER(nes_sachen_74x374_alt_device::write_l) +{ + LOG_MMC(("Sachen 74*374 Alt write_l, offset: %04x, data: %02x\n", offset, data)); + + /* write happens only if we are at 0x4100 + k * 0x200, but 0x4100 is offset = 0 */ + if (!(offset & 0x100)) + { + if (!(offset & 0x01)) + m_latch = data; + else + { + switch (m_latch & 0x07) + { + case 0x00: + prg32(0); + chr8(3, CHRROM); + break; + case 0x02: + m_mmc_vrom_bank = (m_mmc_vrom_bank & ~0x08) | ((data << 3) & 0x08); + chr8(m_mmc_vrom_bank, CHRROM); + break; + case 0x04: + m_mmc_vrom_bank = (m_mmc_vrom_bank & ~0x01) | ((data << 0) & 0x01); + chr8(m_mmc_vrom_bank, CHRROM); + break; + case 0x05: + prg32(data & 0x01); + break; + case 0x06: + m_mmc_vrom_bank = (m_mmc_vrom_bank & ~0x06) | ((data << 1) & 0x06); + chr8(m_mmc_vrom_bank, CHRROM); + break; + case 0x07: + set_mirror(BIT(data, 0)); + break; + default: + break; + } + } + } +} + +/*------------------------------------------------- + + Sachen S8259 bootleg boards + + iNES: mapper 141 (A), 138 (B), 139 (C), 137 (D) + + -------------------------------------------------*/ + +void nes_sachen_8259a_device::chr_update() +{ + UINT8 bank_helper1 = m_reg[7] & 0x01; + UINT8 bank_helper2 = (m_reg[4] & 0x07) << 3; + + if (m_chr_source == CHRROM) + { + chr2_0(((m_reg[bank_helper1 ? 0 : 0] & 0x07) | bank_helper2) << 1 | 0, CHRROM); + chr2_2(((m_reg[bank_helper1 ? 0 : 1] & 0x07) | bank_helper2) << 1 | 1, CHRROM); + chr2_4(((m_reg[bank_helper1 ? 0 : 2] & 0x07) | bank_helper2) << 1 | 0, CHRROM); + chr2_6(((m_reg[bank_helper1 ? 0 : 3] & 0x07) | bank_helper2) << 1 | 1, CHRROM); + } +} + +WRITE8_MEMBER(nes_sachen_8259a_device::write_l) +{ + LOG_MMC(("Sachen 8259 write_l, offset: %04x, data: %02x\n", offset, data)); + + /* write happens only if we are at 0x4100 + k * 0x200, but 0x4100 is offset = 0 */ + if (!(offset & 0x100)) + { + if (!(offset & 0x01)) + m_latch = data & 0x07; + else + { + m_reg[m_latch] = data; + + switch (m_latch) + { + case 0x05: + prg32(data); + break; + case 0x07: + set_mirror(BIT(data, 0) ? 0 : (data >> 1) & 0x03); + break; + default: + chr_update(); + break; + } + } + } +} + +void nes_sachen_8259b_device::chr_update() +{ + UINT8 bank_helper1 = m_reg[7] & 0x01; + UINT8 bank_helper2 = (m_reg[4] & 0x07) << 3; + + if (m_chr_source == CHRROM) + { + chr2_0(((m_reg[bank_helper1 ? 0 : 0] & 0x07) | bank_helper2), CHRROM); + chr2_2(((m_reg[bank_helper1 ? 0 : 1] & 0x07) | bank_helper2), CHRROM); + chr2_4(((m_reg[bank_helper1 ? 0 : 2] & 0x07) | bank_helper2), CHRROM); + chr2_6(((m_reg[bank_helper1 ? 0 : 3] & 0x07) | bank_helper2), CHRROM); + } +} + +void nes_sachen_8259c_device::chr_update() +{ + UINT8 bank_helper1 = m_reg[7] & 0x01; + UINT8 bank_helper2 = (m_reg[4] & 0x07) << 3; + + if (m_chr_source == CHRROM) + { + chr2_0(((m_reg[bank_helper1 ? 0 : 0] & 0x07) | bank_helper2) << 2 | 0, CHRROM); + chr2_2(((m_reg[bank_helper1 ? 0 : 1] & 0x07) | bank_helper2) << 2 | 1, CHRROM); + chr2_4(((m_reg[bank_helper1 ? 0 : 2] & 0x07) | bank_helper2) << 2 | 2, CHRROM); + chr2_6(((m_reg[bank_helper1 ? 0 : 3] & 0x07) | bank_helper2) << 2 | 3, CHRROM); + } +} + +void nes_sachen_8259d_device::chr_update() +{ + if (m_chr_source == CHRROM) + { + chr1_0((m_reg[0] & 0x07), CHRROM); + chr1_1((m_reg[1] & 0x07) | (m_reg[4] << 4 & 0x10), CHRROM); + chr1_2((m_reg[2] & 0x07) | (m_reg[4] << 3 & 0x10), CHRROM); + chr1_3((m_reg[3] & 0x07) | (m_reg[4] << 2 & 0x10) | (m_reg[6] << 3 & 0x08), CHRROM); + } +} diff --git a/src/devices/bus/nes/somari.c b/src/devices/bus/nes/somari.c deleted file mode 100644 index 634aad58b68..00000000000 --- a/src/devices/bus/nes/somari.c +++ /dev/null @@ -1,421 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Fabio Priuli -/*********************************************************************************************************** - - - NES/Famicom cartridge emulation for Somari Team PCBs - - - Here we emulate the Somari Team PCBs [mapper 116] - - - ***********************************************************************************************************/ - - -#include "emu.h" -#include "somari.h" - -#include "cpu/m6502/m6502.h" - - -#ifdef NES_PCB_DEBUG -#define VERBOSE 1 -#else -#define VERBOSE 0 -#endif - -#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) - -#define SOMARI_VRC2_MODE 0 -#define SOMARI_MMC3_MODE 1 -#define SOMARI_MMC1_MODE 2 -#define SOMARI_MMC1_MODE_AGAIN 3 - - -//------------------------------------------------- -// constructor -//------------------------------------------------- - -const device_type NES_SOMARI = &device_creator; - - -nes_somari_device::nes_somari_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_txrom_device(mconfig, NES_SOMARI, "NES Cart Team Somari PCB", tag, owner, clock, "nes_somari", __FILE__) -{ -} - - - -void nes_somari_device::device_start() -{ - common_start(); - save_item(NAME(m_board_mode)); - - // MMC3 - save_item(NAME(m_mmc_prg_bank)); - save_item(NAME(m_mmc_vrom_bank)); - save_item(NAME(m_latch)); - save_item(NAME(m_prg_base)); - save_item(NAME(m_prg_mask)); - save_item(NAME(m_chr_base)); - save_item(NAME(m_chr_mask)); - save_item(NAME(m_mmc3_mirror_reg)); - - save_item(NAME(m_irq_enable)); - save_item(NAME(m_irq_count)); - save_item(NAME(m_irq_count_latch)); - save_item(NAME(m_irq_clear)); - - // MMC1 - save_item(NAME(m_count)); - save_item(NAME(m_mmc1_latch)); - save_item(NAME(m_mmc1_reg)); - - // VRC2 - save_item(NAME(m_vrc_prg_bank)); - save_item(NAME(m_vrc_vrom_bank)); - save_item(NAME(m_vrc_mirror_reg)); -} - -void nes_somari_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0); - chr8(0, m_chr_source); - - m_board_mode = 2; // mode - - // MMC3 - m_prg_base = m_chr_base = 0; - m_prg_mask = 0xff; - m_chr_mask = 0xff; - m_latch = 0; - m_mmc_prg_bank[0] = 0x3c; - m_mmc_prg_bank[1] = 0x3d; - m_mmc_prg_bank[2] = 0x3e; - m_mmc_prg_bank[3] = 0x3f; - m_mmc_vrom_bank[0] = 0x00; - m_mmc_vrom_bank[1] = 0x01; - m_mmc_vrom_bank[2] = 0x04; - m_mmc_vrom_bank[3] = 0x05; - m_mmc_vrom_bank[4] = 0x06; - m_mmc_vrom_bank[5] = 0x07; - m_mmc3_mirror_reg = 0; - - m_alt_irq = 0; - m_irq_enable = 0; - m_irq_count = m_irq_count_latch = 0; - m_irq_clear = 0; - - // MMC1 regs - m_count = 0; - m_mmc1_latch = 0; - m_mmc1_reg[0] = 0x0c; - m_mmc1_reg[1] = 0x00; - m_mmc1_reg[2] = 0x00; - m_mmc1_reg[3] = 0x00; - - // VRC2 regs - m_vrc_prg_bank[0] = 0x00; - m_vrc_prg_bank[1] = 0x01; - for (int i = 0; i < 8; ++i) - m_vrc_vrom_bank[i] = i; - bank_update_switchmode(); - m_vrc_mirror_reg = 0; -} - - - - -/*------------------------------------------------- - mapper specific handlers - -------------------------------------------------*/ - -/*------------------------------------------------- - - SOMERI TEAM - - iNES: mapper 116 - - - Emulation note about regs in MESS: currently, - - m_mmc_prg_bank[n] for n=0,...,3 represent the MMC3 PRG banks (inherited from base class) - - m_mmc_vrom_bank[n] for n=0,...,5 represent the MMC3 CHR banks (inherited from base class) - - - m_mmc1_reg[n] for n=0,1,2,3 represent the MMC1 regs - - m_count and m_mmc1_latch are additional variables for MMC1 (notice that MMC3 uses a diff m_latch!) - - - m_vrc_prg_bank[n] for n=0,1 represent the VRC2 PRG banks - - m_vrc_vrom_bank[n] for n=0,...,7 represent the VRC2 CHR banks - - - In MESS: Preliminary support - - -------------------------------------------------*/ - -// MMC1 Mode emulation -WRITE8_MEMBER(nes_somari_device::mmc1_w) -{ - assert(m_board_mode == 2); - - if (data & 0x80) - { - m_count = 0; - m_mmc1_latch = 0; - - m_mmc1_reg[0] |= 0x0c; - update_prg(); - return; - } - - if (m_count < 5) - { - if (m_count == 0) m_mmc1_latch = 0; - m_mmc1_latch >>= 1; - m_mmc1_latch |= (data & 0x01) ? 0x10 : 0x00; - m_count++; - } - - if (m_count == 5) - { - m_mmc1_reg[(offset & 0x6000) >> 13] = m_mmc1_latch; - update_mirror(); - update_prg(); - update_chr(); - - m_count = 0; - } -} - -// MMC3 Mode emulation -WRITE8_MEMBER(nes_somari_device::mmc3_w) -{ - UINT8 mmc_helper, cmd; - - assert(m_board_mode == 1); - - switch (offset & 0x6001) - { - case 0x0000: - mmc_helper = m_latch ^ data; - m_latch = data; - - if (mmc_helper & 0x40) - update_prg(); - - if (mmc_helper & 0x80) - update_chr(); - break; - - case 0x0001: - cmd = m_latch & 0x07; - switch (cmd) - { - case 0: case 1: - case 2: case 3: case 4: case 5: - m_mmc_vrom_bank[cmd] = data; - update_chr(); - break; - case 6: - case 7: - m_mmc_prg_bank[cmd - 6] = data & 0x3f; - update_prg(); - break; - } - break; - - case 0x2000: - m_mmc3_mirror_reg = data & 1; - update_mirror(); - break; - case 0x2001: break; - case 0x4000: m_irq_count_latch = data; break; - case 0x4001: m_irq_count = 0; break; - case 0x6000: m_irq_enable = 0; m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); break; - case 0x6001: m_irq_enable = 1; break; - } -} - -// VRC2 Mode emulation -WRITE8_MEMBER(nes_somari_device::vrc2_w) -{ - UINT8 bank, shift; - - assert(m_board_mode == 0); - - switch (offset & 0x7000) - { - case 0x0000: - m_vrc_prg_bank[0] = data & 0x1f; - update_prg(); - break; - - case 0x1000: - m_vrc_mirror_reg = data & 1; - update_mirror(); - break; - - case 0x2000: - m_vrc_prg_bank[1] = data & 0x1f; - update_prg(); - break; - - case 0x3000: - case 0x4000: - case 0x5000: - case 0x6000: - // this makes no sense for vrc2 and breaks somari, but it's ok for garousp!! - bank = ((offset & 0x7000) - 0x3000) / 0x0800 + BIT(offset, 1); - shift = BIT(offset, 2) * 4; - data = (data & 0x0f) << shift; - m_vrc_vrom_bank[bank] = data; - - update_chr(); - break; - } -} - - -void nes_somari_device::update_prg() -{ - switch (m_board_mode) - { - case SOMARI_VRC2_MODE: - prg8_89(m_vrc_prg_bank[0]); - prg8_ab(m_vrc_prg_bank[1]); - prg8_cd(0x3e); - prg8_ef(0x3f); - break; - case SOMARI_MMC3_MODE: - { - UINT8 prg_flip = (m_latch & 0x40) ? 2 : 0; - prg8_x(0, m_mmc_prg_bank[0 ^ prg_flip]); - prg8_x(1, m_mmc_prg_bank[1]); - prg8_x(2, m_mmc_prg_bank[2 ^ prg_flip]); - prg8_x(3, m_mmc_prg_bank[3]); - } - break; - case SOMARI_MMC1_MODE: -// case SOMARI_MMC1_MODE_AGAIN: - { - UINT8 prg_offset = m_mmc1_reg[1] & 0x10; - - switch (m_mmc1_reg[0] & 0x0c) - { - case 0x00: - case 0x04: - prg32((prg_offset + m_mmc1_reg[3]) >> 1); - break; - case 0x08: - prg16_89ab(prg_offset + 0); - prg16_cdef(prg_offset + m_mmc1_reg[3]); - break; - case 0x0c: - prg16_89ab(prg_offset + m_mmc1_reg[3]); - prg16_cdef(prg_offset + 0x0f); - break; - } - } - break; - } -} - -void nes_somari_device::update_chr() -{ - switch (m_board_mode) - { - case SOMARI_VRC2_MODE: - for (int i = 0; i < 8; i++) - chr1_x(i, m_chr_base | m_vrc_vrom_bank[i], CHRROM); - break; - case SOMARI_MMC3_MODE: - { - UINT8 chr_page = (m_latch & 0x80) >> 5; - chr1_x(chr_page ^ 0, m_chr_base | ((m_mmc_vrom_bank[0] & ~0x01)), CHRROM); - chr1_x(chr_page ^ 1, m_chr_base | ((m_mmc_vrom_bank[0] | 0x01)), CHRROM); - chr1_x(chr_page ^ 2, m_chr_base | ((m_mmc_vrom_bank[1] & ~0x01)), CHRROM); - chr1_x(chr_page ^ 3, m_chr_base | ((m_mmc_vrom_bank[1] | 0x01)), CHRROM); - chr1_x(chr_page ^ 4, m_chr_base | (m_mmc_vrom_bank[2]), CHRROM); - chr1_x(chr_page ^ 5, m_chr_base | (m_mmc_vrom_bank[3]), CHRROM); - chr1_x(chr_page ^ 6, m_chr_base | (m_mmc_vrom_bank[4]), CHRROM); - chr1_x(chr_page ^ 7, m_chr_base | (m_mmc_vrom_bank[5]), CHRROM); - } - break; - case SOMARI_MMC1_MODE: -// case SOMARI_MMC1_MODE_AGAIN: - if (BIT(m_mmc1_reg[0], 4)) - { - chr4_0(m_mmc1_reg[1] & 0x1f, CHRROM); - chr4_4(m_mmc1_reg[2] & 0x1f, CHRROM); - } - else - chr8((m_mmc1_reg[1] & 0x1f) >> 1, CHRROM); - break; - } -} - -void nes_somari_device::update_mirror() -{ - switch (m_board_mode) - { - case SOMARI_VRC2_MODE: - set_nt_mirroring(m_vrc_mirror_reg ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); - break; - case SOMARI_MMC3_MODE: - set_nt_mirroring(m_mmc3_mirror_reg ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); - break; - case SOMARI_MMC1_MODE: -// case SOMARI_MMC1_MODE_AGAIN: - switch (m_mmc1_reg[0] & 0x03) - { - case 0x00: set_nt_mirroring(PPU_MIRROR_LOW); break; - case 0x01: set_nt_mirroring(PPU_MIRROR_HIGH); break; - case 0x02: set_nt_mirroring(PPU_MIRROR_VERT); break; - case 0x03: set_nt_mirroring(PPU_MIRROR_HORZ); break; - } - break; - } -} - - -WRITE8_MEMBER(nes_somari_device::write_h) -{ - LOG_MMC(("somari write_h, mode %d, offset: %04x, data: %02x\n", m_board_mode, offset, data)); - - switch (m_board_mode) - { - case SOMARI_VRC2_MODE: vrc2_w(space, offset, data, mem_mask); break; - case SOMARI_MMC3_MODE: mmc3_w(space, offset, data, mem_mask); break; - case SOMARI_MMC1_MODE: mmc1_w(space, offset, data, mem_mask); break; - } -} - -void nes_somari_device::bank_update_switchmode() -{ - switch (m_board_mode) - { - case SOMARI_VRC2_MODE: - break; - case SOMARI_MMC3_MODE: - break; - case SOMARI_MMC1_MODE: - break; - } - update_mirror(); - update_prg(); - update_chr(); -} - -WRITE8_MEMBER(nes_somari_device::write_m) -{ - LOG_MMC(("somari write_m, offset: %04x, data: %02x\n", offset, data)); - - if (offset & 0x100) - { - m_board_mode = data & 0x03; - m_chr_base = ((m_board_mode & 0x04) << 6); - if (m_board_mode != 1) - m_irq_enable = 0; - bank_update_switchmode(); - } -} diff --git a/src/devices/bus/nes/somari.cpp b/src/devices/bus/nes/somari.cpp new file mode 100644 index 00000000000..634aad58b68 --- /dev/null +++ b/src/devices/bus/nes/somari.cpp @@ -0,0 +1,421 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for Somari Team PCBs + + + Here we emulate the Somari Team PCBs [mapper 116] + + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "somari.h" + +#include "cpu/m6502/m6502.h" + + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + +#define SOMARI_VRC2_MODE 0 +#define SOMARI_MMC3_MODE 1 +#define SOMARI_MMC1_MODE 2 +#define SOMARI_MMC1_MODE_AGAIN 3 + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_SOMARI = &device_creator; + + +nes_somari_device::nes_somari_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_SOMARI, "NES Cart Team Somari PCB", tag, owner, clock, "nes_somari", __FILE__) +{ +} + + + +void nes_somari_device::device_start() +{ + common_start(); + save_item(NAME(m_board_mode)); + + // MMC3 + save_item(NAME(m_mmc_prg_bank)); + save_item(NAME(m_mmc_vrom_bank)); + save_item(NAME(m_latch)); + save_item(NAME(m_prg_base)); + save_item(NAME(m_prg_mask)); + save_item(NAME(m_chr_base)); + save_item(NAME(m_chr_mask)); + save_item(NAME(m_mmc3_mirror_reg)); + + save_item(NAME(m_irq_enable)); + save_item(NAME(m_irq_count)); + save_item(NAME(m_irq_count_latch)); + save_item(NAME(m_irq_clear)); + + // MMC1 + save_item(NAME(m_count)); + save_item(NAME(m_mmc1_latch)); + save_item(NAME(m_mmc1_reg)); + + // VRC2 + save_item(NAME(m_vrc_prg_bank)); + save_item(NAME(m_vrc_vrom_bank)); + save_item(NAME(m_vrc_mirror_reg)); +} + +void nes_somari_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); + + m_board_mode = 2; // mode + + // MMC3 + m_prg_base = m_chr_base = 0; + m_prg_mask = 0xff; + m_chr_mask = 0xff; + m_latch = 0; + m_mmc_prg_bank[0] = 0x3c; + m_mmc_prg_bank[1] = 0x3d; + m_mmc_prg_bank[2] = 0x3e; + m_mmc_prg_bank[3] = 0x3f; + m_mmc_vrom_bank[0] = 0x00; + m_mmc_vrom_bank[1] = 0x01; + m_mmc_vrom_bank[2] = 0x04; + m_mmc_vrom_bank[3] = 0x05; + m_mmc_vrom_bank[4] = 0x06; + m_mmc_vrom_bank[5] = 0x07; + m_mmc3_mirror_reg = 0; + + m_alt_irq = 0; + m_irq_enable = 0; + m_irq_count = m_irq_count_latch = 0; + m_irq_clear = 0; + + // MMC1 regs + m_count = 0; + m_mmc1_latch = 0; + m_mmc1_reg[0] = 0x0c; + m_mmc1_reg[1] = 0x00; + m_mmc1_reg[2] = 0x00; + m_mmc1_reg[3] = 0x00; + + // VRC2 regs + m_vrc_prg_bank[0] = 0x00; + m_vrc_prg_bank[1] = 0x01; + for (int i = 0; i < 8; ++i) + m_vrc_vrom_bank[i] = i; + bank_update_switchmode(); + m_vrc_mirror_reg = 0; +} + + + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + SOMERI TEAM + + iNES: mapper 116 + + + Emulation note about regs in MESS: currently, + - m_mmc_prg_bank[n] for n=0,...,3 represent the MMC3 PRG banks (inherited from base class) + - m_mmc_vrom_bank[n] for n=0,...,5 represent the MMC3 CHR banks (inherited from base class) + + - m_mmc1_reg[n] for n=0,1,2,3 represent the MMC1 regs + - m_count and m_mmc1_latch are additional variables for MMC1 (notice that MMC3 uses a diff m_latch!) + + - m_vrc_prg_bank[n] for n=0,1 represent the VRC2 PRG banks + - m_vrc_vrom_bank[n] for n=0,...,7 represent the VRC2 CHR banks + + + In MESS: Preliminary support + + -------------------------------------------------*/ + +// MMC1 Mode emulation +WRITE8_MEMBER(nes_somari_device::mmc1_w) +{ + assert(m_board_mode == 2); + + if (data & 0x80) + { + m_count = 0; + m_mmc1_latch = 0; + + m_mmc1_reg[0] |= 0x0c; + update_prg(); + return; + } + + if (m_count < 5) + { + if (m_count == 0) m_mmc1_latch = 0; + m_mmc1_latch >>= 1; + m_mmc1_latch |= (data & 0x01) ? 0x10 : 0x00; + m_count++; + } + + if (m_count == 5) + { + m_mmc1_reg[(offset & 0x6000) >> 13] = m_mmc1_latch; + update_mirror(); + update_prg(); + update_chr(); + + m_count = 0; + } +} + +// MMC3 Mode emulation +WRITE8_MEMBER(nes_somari_device::mmc3_w) +{ + UINT8 mmc_helper, cmd; + + assert(m_board_mode == 1); + + switch (offset & 0x6001) + { + case 0x0000: + mmc_helper = m_latch ^ data; + m_latch = data; + + if (mmc_helper & 0x40) + update_prg(); + + if (mmc_helper & 0x80) + update_chr(); + break; + + case 0x0001: + cmd = m_latch & 0x07; + switch (cmd) + { + case 0: case 1: + case 2: case 3: case 4: case 5: + m_mmc_vrom_bank[cmd] = data; + update_chr(); + break; + case 6: + case 7: + m_mmc_prg_bank[cmd - 6] = data & 0x3f; + update_prg(); + break; + } + break; + + case 0x2000: + m_mmc3_mirror_reg = data & 1; + update_mirror(); + break; + case 0x2001: break; + case 0x4000: m_irq_count_latch = data; break; + case 0x4001: m_irq_count = 0; break; + case 0x6000: m_irq_enable = 0; m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); break; + case 0x6001: m_irq_enable = 1; break; + } +} + +// VRC2 Mode emulation +WRITE8_MEMBER(nes_somari_device::vrc2_w) +{ + UINT8 bank, shift; + + assert(m_board_mode == 0); + + switch (offset & 0x7000) + { + case 0x0000: + m_vrc_prg_bank[0] = data & 0x1f; + update_prg(); + break; + + case 0x1000: + m_vrc_mirror_reg = data & 1; + update_mirror(); + break; + + case 0x2000: + m_vrc_prg_bank[1] = data & 0x1f; + update_prg(); + break; + + case 0x3000: + case 0x4000: + case 0x5000: + case 0x6000: + // this makes no sense for vrc2 and breaks somari, but it's ok for garousp!! + bank = ((offset & 0x7000) - 0x3000) / 0x0800 + BIT(offset, 1); + shift = BIT(offset, 2) * 4; + data = (data & 0x0f) << shift; + m_vrc_vrom_bank[bank] = data; + + update_chr(); + break; + } +} + + +void nes_somari_device::update_prg() +{ + switch (m_board_mode) + { + case SOMARI_VRC2_MODE: + prg8_89(m_vrc_prg_bank[0]); + prg8_ab(m_vrc_prg_bank[1]); + prg8_cd(0x3e); + prg8_ef(0x3f); + break; + case SOMARI_MMC3_MODE: + { + UINT8 prg_flip = (m_latch & 0x40) ? 2 : 0; + prg8_x(0, m_mmc_prg_bank[0 ^ prg_flip]); + prg8_x(1, m_mmc_prg_bank[1]); + prg8_x(2, m_mmc_prg_bank[2 ^ prg_flip]); + prg8_x(3, m_mmc_prg_bank[3]); + } + break; + case SOMARI_MMC1_MODE: +// case SOMARI_MMC1_MODE_AGAIN: + { + UINT8 prg_offset = m_mmc1_reg[1] & 0x10; + + switch (m_mmc1_reg[0] & 0x0c) + { + case 0x00: + case 0x04: + prg32((prg_offset + m_mmc1_reg[3]) >> 1); + break; + case 0x08: + prg16_89ab(prg_offset + 0); + prg16_cdef(prg_offset + m_mmc1_reg[3]); + break; + case 0x0c: + prg16_89ab(prg_offset + m_mmc1_reg[3]); + prg16_cdef(prg_offset + 0x0f); + break; + } + } + break; + } +} + +void nes_somari_device::update_chr() +{ + switch (m_board_mode) + { + case SOMARI_VRC2_MODE: + for (int i = 0; i < 8; i++) + chr1_x(i, m_chr_base | m_vrc_vrom_bank[i], CHRROM); + break; + case SOMARI_MMC3_MODE: + { + UINT8 chr_page = (m_latch & 0x80) >> 5; + chr1_x(chr_page ^ 0, m_chr_base | ((m_mmc_vrom_bank[0] & ~0x01)), CHRROM); + chr1_x(chr_page ^ 1, m_chr_base | ((m_mmc_vrom_bank[0] | 0x01)), CHRROM); + chr1_x(chr_page ^ 2, m_chr_base | ((m_mmc_vrom_bank[1] & ~0x01)), CHRROM); + chr1_x(chr_page ^ 3, m_chr_base | ((m_mmc_vrom_bank[1] | 0x01)), CHRROM); + chr1_x(chr_page ^ 4, m_chr_base | (m_mmc_vrom_bank[2]), CHRROM); + chr1_x(chr_page ^ 5, m_chr_base | (m_mmc_vrom_bank[3]), CHRROM); + chr1_x(chr_page ^ 6, m_chr_base | (m_mmc_vrom_bank[4]), CHRROM); + chr1_x(chr_page ^ 7, m_chr_base | (m_mmc_vrom_bank[5]), CHRROM); + } + break; + case SOMARI_MMC1_MODE: +// case SOMARI_MMC1_MODE_AGAIN: + if (BIT(m_mmc1_reg[0], 4)) + { + chr4_0(m_mmc1_reg[1] & 0x1f, CHRROM); + chr4_4(m_mmc1_reg[2] & 0x1f, CHRROM); + } + else + chr8((m_mmc1_reg[1] & 0x1f) >> 1, CHRROM); + break; + } +} + +void nes_somari_device::update_mirror() +{ + switch (m_board_mode) + { + case SOMARI_VRC2_MODE: + set_nt_mirroring(m_vrc_mirror_reg ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + break; + case SOMARI_MMC3_MODE: + set_nt_mirroring(m_mmc3_mirror_reg ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + break; + case SOMARI_MMC1_MODE: +// case SOMARI_MMC1_MODE_AGAIN: + switch (m_mmc1_reg[0] & 0x03) + { + case 0x00: set_nt_mirroring(PPU_MIRROR_LOW); break; + case 0x01: set_nt_mirroring(PPU_MIRROR_HIGH); break; + case 0x02: set_nt_mirroring(PPU_MIRROR_VERT); break; + case 0x03: set_nt_mirroring(PPU_MIRROR_HORZ); break; + } + break; + } +} + + +WRITE8_MEMBER(nes_somari_device::write_h) +{ + LOG_MMC(("somari write_h, mode %d, offset: %04x, data: %02x\n", m_board_mode, offset, data)); + + switch (m_board_mode) + { + case SOMARI_VRC2_MODE: vrc2_w(space, offset, data, mem_mask); break; + case SOMARI_MMC3_MODE: mmc3_w(space, offset, data, mem_mask); break; + case SOMARI_MMC1_MODE: mmc1_w(space, offset, data, mem_mask); break; + } +} + +void nes_somari_device::bank_update_switchmode() +{ + switch (m_board_mode) + { + case SOMARI_VRC2_MODE: + break; + case SOMARI_MMC3_MODE: + break; + case SOMARI_MMC1_MODE: + break; + } + update_mirror(); + update_prg(); + update_chr(); +} + +WRITE8_MEMBER(nes_somari_device::write_m) +{ + LOG_MMC(("somari write_m, offset: %04x, data: %02x\n", offset, data)); + + if (offset & 0x100) + { + m_board_mode = data & 0x03; + m_chr_base = ((m_board_mode & 0x04) << 6); + if (m_board_mode != 1) + m_irq_enable = 0; + bank_update_switchmode(); + } +} diff --git a/src/devices/bus/nes/sunsoft.c b/src/devices/bus/nes/sunsoft.c deleted file mode 100644 index 48d95c05727..00000000000 --- a/src/devices/bus/nes/sunsoft.c +++ /dev/null @@ -1,628 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Fabio Priuli -/*********************************************************************************************************** - - - NES/Famicom cartridge emulation for Sunsoft PCBs - - - Here we emulate the following PCBs - - * Sunsoft-1 [mapper 184] - * Sunsoft-2 [mapper 89 & 93] - * Sunsoft-3 [mapper 67] - * Sunsoft-4 [mapper 68] - * Sunsoft FME7 & Sunsoft-5A [mapper 69] - * Sunsoft-5B [mapper 69] - - TODO: - - check 1-line glitches due to IRQ in Sunsoft-3 - - ***********************************************************************************************************/ - - -#include "emu.h" -#include "sunsoft.h" - -#include "cpu/m6502/m6502.h" -#include "sound/ay8910.h" - -#ifdef NES_PCB_DEBUG -#define VERBOSE 1 -#else -#define VERBOSE 0 -#endif - -#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) - - -//------------------------------------------------- -// constructor -//------------------------------------------------- - -const device_type NES_SUNSOFT_1 = &device_creator; -const device_type NES_SUNSOFT_2 = &device_creator; -const device_type NES_SUNSOFT_3 = &device_creator; -const device_type NES_SUNSOFT_4 = &device_creator; -const device_type NES_SUNSOFT_FME7 = &device_creator; -const device_type NES_SUNSOFT_5 = &device_creator; - - -nes_sunsoft_1_device::nes_sunsoft_1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_SUNSOFT_1, "NES Cart Sunsoft 1 PCB", tag, owner, clock, "nes_sun1", __FILE__) -{ -} - -nes_sunsoft_2_device::nes_sunsoft_2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_SUNSOFT_2, "NES Cart Sunsoft 2 PCB", tag, owner, clock, "nes_sun2", __FILE__) -{ -} - -nes_sunsoft_3_device::nes_sunsoft_3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_SUNSOFT_3, "NES Cart Sunsoft 3 PCB", tag, owner, clock, "nes_sun3", __FILE__) -{ -} - -nes_sunsoft_4_device::nes_sunsoft_4_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) - : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source) -{ -} - -nes_sunsoft_4_device::nes_sunsoft_4_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_SUNSOFT_4, "NES Cart Sunsoft 4 PCB", tag, owner, clock, "nes_sun4", __FILE__) -{ -} - -nes_sunsoft_fme7_device::nes_sunsoft_fme7_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) - : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source) -{ -} - -nes_sunsoft_fme7_device::nes_sunsoft_fme7_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_SUNSOFT_4, "NES Cart Sunsoft FME7 PCB", tag, owner, clock, "nes_fme7", __FILE__) -{ -} - -nes_sunsoft_5_device::nes_sunsoft_5_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_sunsoft_fme7_device(mconfig, NES_SUNSOFT_5, "NES Cart Sunsoft 5A/5B PCB", tag, owner, clock, "nes_sun5", __FILE__), - m_ym2149(*this, "ay") -{ -} - - -void nes_sunsoft_1_device::device_start() -{ - common_start(); -} - -void nes_sunsoft_1_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(0); - prg16_cdef(m_prg_chunks - 1); - chr8(0, m_chr_source); -} - -void nes_sunsoft_2_device::device_start() -{ - common_start(); -} - -void nes_sunsoft_2_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(0); - prg16_cdef(m_prg_chunks - 1); - chr8(0, m_chr_source); - if (m_pcb_ctrl_mirror) - set_nt_mirroring(PPU_MIRROR_LOW); -} - -void nes_sunsoft_3_device::device_start() -{ - common_start(); - irq_timer = timer_alloc(TIMER_IRQ); - irq_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1)); - - save_item(NAME(m_irq_enable)); - save_item(NAME(m_irq_toggle)); - save_item(NAME(m_irq_count)); -} - -void nes_sunsoft_3_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(0); - prg16_cdef(m_prg_chunks - 1); - chr8(0, m_chr_source); - m_irq_toggle = 0; - m_irq_count = 0; - m_irq_enable = 0; -} - -void nes_sunsoft_4_device::device_start() -{ - common_start(); - save_item(NAME(m_latch1)); - save_item(NAME(m_latch2)); - save_item(NAME(m_reg)); - save_item(NAME(m_wram_enable)); -} - -void nes_sunsoft_4_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(0); - prg16_cdef(m_prg_chunks - 1); - chr8(0, m_chr_source); - - m_reg = 0; - m_latch1 = 0; - m_latch2 = 0; - m_wram_enable = 0; -} - -void nes_sunsoft_fme7_device::device_start() -{ - common_start(); - irq_timer = timer_alloc(TIMER_IRQ); - // this has to be hardcoded because some some scanline code only suits NTSC... it will be fixed with PPU rewrite - irq_timer->adjust(attotime::zero, 0, attotime::from_hz((21477272.724 / 12))); -// irq_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1)); - - save_item(NAME(m_wram_bank)); - save_item(NAME(m_latch)); - save_item(NAME(m_irq_enable)); - save_item(NAME(m_irq_count)); -} - -void nes_sunsoft_fme7_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(0); - prg16_cdef(m_prg_chunks - 1); - chr8(0, m_chr_source); - - m_wram_bank = 0; - - m_latch = 0; - m_irq_enable = 0; - m_irq_count = 0; -} - - - -/*------------------------------------------------- - mapper specific handlers - -------------------------------------------------*/ - -/*------------------------------------------------- - - Sunsoft-1 board emulation - - Games: Atlantis no Nazo, Kanshakudama Nage Kantarou no - Toukaidou Gojuusan Tsugi, Wing of Madoola, Fantasy Zone - - iNES: mapper 184 (Fantasy Zone uses this board with no - CHRROM, and the register switches PRG banks) - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_sunsoft_1_device::write_m) -{ - LOG_MMC(("Sunsoft 1 write_m, offset: %04x, data: %02x\n", offset, data)); - - if (m_vrom_chunks) - { - chr4_0(data & 0x0f, CHRROM); - chr4_4(data >> 4, CHRROM); - } - else - prg16_89ab(data & 0x0f); -} - -/*------------------------------------------------- - - Sunsoft-2 board emulation - - The two games using this board have incompatible mirroring - wiring, making necessary two distinct mappers - - iNES: mapper 89 & 93 - - -------------------------------------------------*/ - -// there are two 'variants' depending on hardwired or mapper ctrl mirroring - -WRITE8_MEMBER(nes_sunsoft_2_device::write_h) -{ - UINT8 helper = (data & 0x07) | ((data & 0x80) ? 0x08 : 0x00); - LOG_MMC(("Sunsoft 2 write_h, offset: %04x, data: %02x\n", offset, data)); - - // this pcb is subject to bus conflict - data = account_bus_conflict(offset, data); - - if (m_pcb_ctrl_mirror) - set_nt_mirroring(BIT(data, 3) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW); - - if (m_vrom_chunks) - chr8(helper, CHRROM); - - prg16_89ab(data >> 4); -} - -/*------------------------------------------------- - - Sunsoft-3 board emulation - - The two games using this board have incompatible mirroring - wiring, making necessary two distinct mappers & pcb_id - - iNES: mapper 67 - - -------------------------------------------------*/ - - -void nes_sunsoft_3_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) -{ - if (id == TIMER_IRQ) - { - if (m_irq_enable) - { - if (!m_irq_count) - { - m_maincpu->set_input_line(M6502_IRQ_LINE, ASSERT_LINE); - m_irq_count = 0xffff; - m_irq_enable = 0; - } - else - m_irq_count--; - } - } -} - -WRITE8_MEMBER(nes_sunsoft_3_device::write_h) -{ - LOG_MMC(("Sunsoft 3 write_h, offset %04x, data: %02x\n", offset, data)); - - switch (offset & 0x7800) - { - case 0x0800: - chr2_0(data, CHRROM); - break; - case 0x1800: - chr2_2(data, CHRROM); - break; - case 0x2800: - chr2_4(data, CHRROM); - break; - case 0x3800: - chr2_6(data, CHRROM); - break; - case 0x4000: - case 0x4800: - m_irq_toggle ^= 1; - if (m_irq_toggle) - m_irq_count = (m_irq_count & 0x00ff) | (data << 8); - else - m_irq_count = (m_irq_count & 0xff00) | data; - break; - case 0x5800: - m_irq_enable = BIT(data, 4); - m_irq_toggle = 0; - m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); - break; - case 0x6800: - switch (data & 3) - { - case 0x00: set_nt_mirroring(PPU_MIRROR_VERT); break; - case 0x01: set_nt_mirroring(PPU_MIRROR_HORZ); break; - case 0x02: set_nt_mirroring(PPU_MIRROR_LOW); break; - case 0x03: set_nt_mirroring(PPU_MIRROR_HIGH); break; - } - break; - case 0x7800: - prg16_89ab(data); - break; - default: - LOG_MMC(("Sunsoft 3 write_h uncaught write, offset: %04x, data: %02x\n", offset, data)); - break; - } -} - -/*------------------------------------------------- - - Sunsoft-4 board emulation - - Games: AfterBurner & Maharaja - - iNES: mapper 68 - - -------------------------------------------------*/ - -void nes_sunsoft_4_device::sun4_mirror( int mirror, int mirr0, int mirr1 ) -{ - switch (mirror) - { - case 0x00: - set_nt_mirroring(PPU_MIRROR_VERT); - break; - case 0x01: - set_nt_mirroring(PPU_MIRROR_HORZ); - break; - case 0x02: - set_nt_mirroring(PPU_MIRROR_LOW); - break; - case 0x03: - set_nt_mirroring(PPU_MIRROR_HIGH); - break; - case 0x10: - set_nt_page(0, VROM, mirr0 | 0x80, 0); - set_nt_page(1, VROM, mirr1 | 0x80, 0); - set_nt_page(2, VROM, mirr0 | 0x80, 0); - set_nt_page(3, VROM, mirr1 | 0x80, 0); - break; - case 0x11: - set_nt_page(0, VROM, mirr0 | 0x80, 0); - set_nt_page(1, VROM, mirr0 | 0x80, 0); - set_nt_page(2, VROM, mirr1 | 0x80, 0); - set_nt_page(3, VROM, mirr1 | 0x80, 0); - break; - case 0x12: - set_nt_page(0, VROM, mirr0 | 0x80, 0); - set_nt_page(1, VROM, mirr0 | 0x80, 0); - set_nt_page(2, VROM, mirr0 | 0x80, 0); - set_nt_page(3, VROM, mirr0 | 0x80, 0); - break; - case 0x13: - set_nt_page(0, VROM, mirr1 | 0x80, 0); - set_nt_page(1, VROM, mirr1 | 0x80, 0); - set_nt_page(2, VROM, mirr1 | 0x80, 0); - set_nt_page(3, VROM, mirr1 | 0x80, 0); - break; - } -} - -WRITE8_MEMBER(nes_sunsoft_4_device::sun4_write) -{ - LOG_MMC(("Sunsoft 4 write_h, offset %04x, data: %02x\n", offset, data)); - - switch (offset & 0x7000) - { - case 0x0000: - chr2_0(data, CHRROM); - break; - case 0x1000: - chr2_2(data, CHRROM); - break; - case 0x2000: - chr2_4(data, CHRROM); - break; - case 0x3000: - chr2_6(data, CHRROM); - break; - case 0x4000: - m_latch1 = data & 0x7f; - sun4_mirror(m_reg, m_latch1, m_latch2); - break; - case 0x5000: - m_latch2 = data & 0x7f; - sun4_mirror(m_reg, m_latch1, m_latch2); - break; - case 0x6000: - m_reg = data & 0x13; - sun4_mirror(m_reg, m_latch1, m_latch2); - break; - case 0x7000: - prg16_89ab(data & 0x0f); - m_wram_enable = BIT(data, 4); - break; - default: - LOG_MMC(("Sunsoft 4 write_h uncaught write, offset: %04x, data: %02x\n", offset, data)); - break; - } -} - -WRITE8_MEMBER(nes_sunsoft_4_device::write_m) -{ - LOG_MMC(("Sunsoft 4 write_m, offset: %04x, data: %02x\n", offset, data)); - - if (!m_battery.empty() && m_wram_enable) - m_battery[offset & (m_battery.size() - 1)] = data; - if (!m_prgram.empty() && m_wram_enable) - m_prgram[offset & (m_prgram.size() - 1)] = data; -} - -READ8_MEMBER(nes_sunsoft_4_device::read_m) -{ - LOG_MMC(("Sunsoft 4 read_m, offset: %04x\n", offset)); - - if (!m_battery.empty() && m_wram_enable) - return m_battery[offset & (m_battery.size() - 1)]; - if (!m_prgram.empty() && m_wram_enable) - return m_prgram[offset & (m_prgram.size() - 1)]; - - return m_open_bus; // open bus -} - -/*------------------------------------------------- - - JxROM & Sunsoft 5A / 5B / FME7 board emulation - - Notice that Sunsoft-5B = FME7 + sound chip (the latter being - currently unemulated in MESS) - - iNES: mapper 69 - - -------------------------------------------------*/ - -void nes_sunsoft_fme7_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) -{ - if (id == TIMER_IRQ) - { - if ((m_irq_enable & 0x80)) // bit7, counter decrement - { - if (!m_irq_count) - { - m_irq_count = 0xffff; - if (m_irq_enable & 0x01) // bit0, trigger enable - m_maincpu->set_input_line(M6502_IRQ_LINE, ASSERT_LINE); - } - else - m_irq_count--; - } - } -} - -WRITE8_MEMBER(nes_sunsoft_fme7_device::fme7_write) -{ - LOG_MMC(("fme7_write, offset %04x, data: %02x\n", offset, data)); - - switch (offset & 0x6000) - { - case 0x0000: - m_latch = data & 0x0f; - break; - - case 0x2000: - switch (m_latch) - { - case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: - chr1_x(m_latch, data, CHRROM); - break; - - case 8: - m_wram_bank = data; - break; - case 9: - prg8_89(data); - break; - case 0x0a: - prg8_ab(data); - break; - case 0x0b: - prg8_cd(data); - break; - case 0x0c: - switch (data & 0x03) - { - case 0x00: set_nt_mirroring(PPU_MIRROR_VERT); break; - case 0x01: set_nt_mirroring(PPU_MIRROR_HORZ); break; - case 0x02: set_nt_mirroring(PPU_MIRROR_LOW); break; - case 0x03: set_nt_mirroring(PPU_MIRROR_HIGH); break; - } - break; - case 0x0d: - m_irq_enable = data; - if (!(m_irq_enable & 1)) - m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); - break; - case 0x0e: - m_irq_count = (m_irq_count & 0xff00) | data; - break; - case 0x0f: - m_irq_count = (m_irq_count & 0x00ff) | (data << 8); - break; - } - break; - - default: - logerror("Sunsoft FME7 write_h uncaught %04x value: %02x\n", offset + 0x8000, data); - break; - } -} - -WRITE8_MEMBER(nes_sunsoft_fme7_device::write_m) -{ - UINT8 bank = m_wram_bank & 0x3f; - LOG_MMC(("Sunsoft FME7 write_m, offset: %04x, data: %02x\n", offset, data)); - - if (!(m_wram_bank & 0x40)) // is PRG ROM, no write - return; - else if (m_wram_bank & 0x80) // is PRG RAM - { - if (!m_battery.empty()) - m_battery[((bank * 0x2000) + offset) & (m_battery.size() - 1)] = data; - if (!m_prgram.empty()) - m_prgram[((bank * 0x2000) + offset) & (m_prgram.size() - 1)] = data; - } -} - -READ8_MEMBER(nes_sunsoft_fme7_device::read_m) -{ - UINT8 bank = m_wram_bank & 0x3f; - LOG_MMC(("Sunsoft FME7 read_m, offset: %04x\n", offset)); - - if (!(m_wram_bank & 0x40)) // is PRG ROM - return m_prg[((bank * 0x2000) + offset) & (m_prg_size - 1)]; - else if (m_wram_bank & 0x80) // is PRG RAM - { - if (!m_battery.empty()) - return m_battery[((bank * 0x2000) + offset) & (m_battery.size() - 1)]; - if (!m_prgram.empty()) - return m_prgram[((bank * 0x2000) + offset) & (m_prgram.size() - 1)]; - } - - return m_open_bus; // open bus -} - - -/*------------------------------------------------- - - Sunsoft 5B board emulation (FME7 + Sound) - - Games: Gimmick! - - iNES: mapper 69 - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_sunsoft_5_device::write_h) -{ - LOG_MMC(("sunsoft 5 write_h, offset %04x, data: %02x\n", offset, data)); - - switch (offset & 0x6000) - { - case 0x4000: - m_ym2149->address_w(space, 0, data & 0x0f); - break; - case 0x6000: - m_ym2149->data_w(space, 0, data); - break; - default: - fme7_write(space, offset, data, mem_mask); - break; - } -} - -//------------------------------------------------- -// MACHINE_DRIVER( sun_5b ) -//------------------------------------------------- - -// From NESdev wiki: The 5B's audio is driven by the CPU clock (1.78977267 MHz), -// but like the NES's APU, the YM2149F has an optional clock divider which -// halves the internal clock speed. By comparison of the produced pitches -// in Gimmick! with the register values used, it appears that the 5B is a -// YM2149F operating in this mode. To use an AY-3-8910 as a substitute, -// you would need an external divider to reduce the clock speed by half. - -#define SUN5_NTSC_CLOCK (21477272.724 / 12) - -static MACHINE_CONFIG_FRAGMENT( sun_5b ) - - // additional sound hardware - MCFG_SPEAKER_STANDARD_MONO("addon") - - MCFG_SOUND_ADD("ay", YM2149, SUN5_NTSC_CLOCK/2) // divide by 2 for the internal divider - MCFG_SOUND_ROUTE(ALL_OUTPUTS, "addon", 0.50) -MACHINE_CONFIG_END - -//------------------------------------------------- -// machine_config_additions - device-specific -// machine configurations -//------------------------------------------------- - -machine_config_constructor nes_sunsoft_5_device::device_mconfig_additions() const -{ - return MACHINE_CONFIG_NAME( sun_5b ); -} diff --git a/src/devices/bus/nes/sunsoft.cpp b/src/devices/bus/nes/sunsoft.cpp new file mode 100644 index 00000000000..48d95c05727 --- /dev/null +++ b/src/devices/bus/nes/sunsoft.cpp @@ -0,0 +1,628 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for Sunsoft PCBs + + + Here we emulate the following PCBs + + * Sunsoft-1 [mapper 184] + * Sunsoft-2 [mapper 89 & 93] + * Sunsoft-3 [mapper 67] + * Sunsoft-4 [mapper 68] + * Sunsoft FME7 & Sunsoft-5A [mapper 69] + * Sunsoft-5B [mapper 69] + + TODO: + - check 1-line glitches due to IRQ in Sunsoft-3 + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "sunsoft.h" + +#include "cpu/m6502/m6502.h" +#include "sound/ay8910.h" + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_SUNSOFT_1 = &device_creator; +const device_type NES_SUNSOFT_2 = &device_creator; +const device_type NES_SUNSOFT_3 = &device_creator; +const device_type NES_SUNSOFT_4 = &device_creator; +const device_type NES_SUNSOFT_FME7 = &device_creator; +const device_type NES_SUNSOFT_5 = &device_creator; + + +nes_sunsoft_1_device::nes_sunsoft_1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_SUNSOFT_1, "NES Cart Sunsoft 1 PCB", tag, owner, clock, "nes_sun1", __FILE__) +{ +} + +nes_sunsoft_2_device::nes_sunsoft_2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_SUNSOFT_2, "NES Cart Sunsoft 2 PCB", tag, owner, clock, "nes_sun2", __FILE__) +{ +} + +nes_sunsoft_3_device::nes_sunsoft_3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_SUNSOFT_3, "NES Cart Sunsoft 3 PCB", tag, owner, clock, "nes_sun3", __FILE__) +{ +} + +nes_sunsoft_4_device::nes_sunsoft_4_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +nes_sunsoft_4_device::nes_sunsoft_4_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_SUNSOFT_4, "NES Cart Sunsoft 4 PCB", tag, owner, clock, "nes_sun4", __FILE__) +{ +} + +nes_sunsoft_fme7_device::nes_sunsoft_fme7_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +nes_sunsoft_fme7_device::nes_sunsoft_fme7_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_SUNSOFT_4, "NES Cart Sunsoft FME7 PCB", tag, owner, clock, "nes_fme7", __FILE__) +{ +} + +nes_sunsoft_5_device::nes_sunsoft_5_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_sunsoft_fme7_device(mconfig, NES_SUNSOFT_5, "NES Cart Sunsoft 5A/5B PCB", tag, owner, clock, "nes_sun5", __FILE__), + m_ym2149(*this, "ay") +{ +} + + +void nes_sunsoft_1_device::device_start() +{ + common_start(); +} + +void nes_sunsoft_1_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); +} + +void nes_sunsoft_2_device::device_start() +{ + common_start(); +} + +void nes_sunsoft_2_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + if (m_pcb_ctrl_mirror) + set_nt_mirroring(PPU_MIRROR_LOW); +} + +void nes_sunsoft_3_device::device_start() +{ + common_start(); + irq_timer = timer_alloc(TIMER_IRQ); + irq_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1)); + + save_item(NAME(m_irq_enable)); + save_item(NAME(m_irq_toggle)); + save_item(NAME(m_irq_count)); +} + +void nes_sunsoft_3_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + m_irq_toggle = 0; + m_irq_count = 0; + m_irq_enable = 0; +} + +void nes_sunsoft_4_device::device_start() +{ + common_start(); + save_item(NAME(m_latch1)); + save_item(NAME(m_latch2)); + save_item(NAME(m_reg)); + save_item(NAME(m_wram_enable)); +} + +void nes_sunsoft_4_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + + m_reg = 0; + m_latch1 = 0; + m_latch2 = 0; + m_wram_enable = 0; +} + +void nes_sunsoft_fme7_device::device_start() +{ + common_start(); + irq_timer = timer_alloc(TIMER_IRQ); + // this has to be hardcoded because some some scanline code only suits NTSC... it will be fixed with PPU rewrite + irq_timer->adjust(attotime::zero, 0, attotime::from_hz((21477272.724 / 12))); +// irq_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1)); + + save_item(NAME(m_wram_bank)); + save_item(NAME(m_latch)); + save_item(NAME(m_irq_enable)); + save_item(NAME(m_irq_count)); +} + +void nes_sunsoft_fme7_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + + m_wram_bank = 0; + + m_latch = 0; + m_irq_enable = 0; + m_irq_count = 0; +} + + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + Sunsoft-1 board emulation + + Games: Atlantis no Nazo, Kanshakudama Nage Kantarou no + Toukaidou Gojuusan Tsugi, Wing of Madoola, Fantasy Zone + + iNES: mapper 184 (Fantasy Zone uses this board with no + CHRROM, and the register switches PRG banks) + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_sunsoft_1_device::write_m) +{ + LOG_MMC(("Sunsoft 1 write_m, offset: %04x, data: %02x\n", offset, data)); + + if (m_vrom_chunks) + { + chr4_0(data & 0x0f, CHRROM); + chr4_4(data >> 4, CHRROM); + } + else + prg16_89ab(data & 0x0f); +} + +/*------------------------------------------------- + + Sunsoft-2 board emulation + + The two games using this board have incompatible mirroring + wiring, making necessary two distinct mappers + + iNES: mapper 89 & 93 + + -------------------------------------------------*/ + +// there are two 'variants' depending on hardwired or mapper ctrl mirroring + +WRITE8_MEMBER(nes_sunsoft_2_device::write_h) +{ + UINT8 helper = (data & 0x07) | ((data & 0x80) ? 0x08 : 0x00); + LOG_MMC(("Sunsoft 2 write_h, offset: %04x, data: %02x\n", offset, data)); + + // this pcb is subject to bus conflict + data = account_bus_conflict(offset, data); + + if (m_pcb_ctrl_mirror) + set_nt_mirroring(BIT(data, 3) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW); + + if (m_vrom_chunks) + chr8(helper, CHRROM); + + prg16_89ab(data >> 4); +} + +/*------------------------------------------------- + + Sunsoft-3 board emulation + + The two games using this board have incompatible mirroring + wiring, making necessary two distinct mappers & pcb_id + + iNES: mapper 67 + + -------------------------------------------------*/ + + +void nes_sunsoft_3_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (id == TIMER_IRQ) + { + if (m_irq_enable) + { + if (!m_irq_count) + { + m_maincpu->set_input_line(M6502_IRQ_LINE, ASSERT_LINE); + m_irq_count = 0xffff; + m_irq_enable = 0; + } + else + m_irq_count--; + } + } +} + +WRITE8_MEMBER(nes_sunsoft_3_device::write_h) +{ + LOG_MMC(("Sunsoft 3 write_h, offset %04x, data: %02x\n", offset, data)); + + switch (offset & 0x7800) + { + case 0x0800: + chr2_0(data, CHRROM); + break; + case 0x1800: + chr2_2(data, CHRROM); + break; + case 0x2800: + chr2_4(data, CHRROM); + break; + case 0x3800: + chr2_6(data, CHRROM); + break; + case 0x4000: + case 0x4800: + m_irq_toggle ^= 1; + if (m_irq_toggle) + m_irq_count = (m_irq_count & 0x00ff) | (data << 8); + else + m_irq_count = (m_irq_count & 0xff00) | data; + break; + case 0x5800: + m_irq_enable = BIT(data, 4); + m_irq_toggle = 0; + m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); + break; + case 0x6800: + switch (data & 3) + { + case 0x00: set_nt_mirroring(PPU_MIRROR_VERT); break; + case 0x01: set_nt_mirroring(PPU_MIRROR_HORZ); break; + case 0x02: set_nt_mirroring(PPU_MIRROR_LOW); break; + case 0x03: set_nt_mirroring(PPU_MIRROR_HIGH); break; + } + break; + case 0x7800: + prg16_89ab(data); + break; + default: + LOG_MMC(("Sunsoft 3 write_h uncaught write, offset: %04x, data: %02x\n", offset, data)); + break; + } +} + +/*------------------------------------------------- + + Sunsoft-4 board emulation + + Games: AfterBurner & Maharaja + + iNES: mapper 68 + + -------------------------------------------------*/ + +void nes_sunsoft_4_device::sun4_mirror( int mirror, int mirr0, int mirr1 ) +{ + switch (mirror) + { + case 0x00: + set_nt_mirroring(PPU_MIRROR_VERT); + break; + case 0x01: + set_nt_mirroring(PPU_MIRROR_HORZ); + break; + case 0x02: + set_nt_mirroring(PPU_MIRROR_LOW); + break; + case 0x03: + set_nt_mirroring(PPU_MIRROR_HIGH); + break; + case 0x10: + set_nt_page(0, VROM, mirr0 | 0x80, 0); + set_nt_page(1, VROM, mirr1 | 0x80, 0); + set_nt_page(2, VROM, mirr0 | 0x80, 0); + set_nt_page(3, VROM, mirr1 | 0x80, 0); + break; + case 0x11: + set_nt_page(0, VROM, mirr0 | 0x80, 0); + set_nt_page(1, VROM, mirr0 | 0x80, 0); + set_nt_page(2, VROM, mirr1 | 0x80, 0); + set_nt_page(3, VROM, mirr1 | 0x80, 0); + break; + case 0x12: + set_nt_page(0, VROM, mirr0 | 0x80, 0); + set_nt_page(1, VROM, mirr0 | 0x80, 0); + set_nt_page(2, VROM, mirr0 | 0x80, 0); + set_nt_page(3, VROM, mirr0 | 0x80, 0); + break; + case 0x13: + set_nt_page(0, VROM, mirr1 | 0x80, 0); + set_nt_page(1, VROM, mirr1 | 0x80, 0); + set_nt_page(2, VROM, mirr1 | 0x80, 0); + set_nt_page(3, VROM, mirr1 | 0x80, 0); + break; + } +} + +WRITE8_MEMBER(nes_sunsoft_4_device::sun4_write) +{ + LOG_MMC(("Sunsoft 4 write_h, offset %04x, data: %02x\n", offset, data)); + + switch (offset & 0x7000) + { + case 0x0000: + chr2_0(data, CHRROM); + break; + case 0x1000: + chr2_2(data, CHRROM); + break; + case 0x2000: + chr2_4(data, CHRROM); + break; + case 0x3000: + chr2_6(data, CHRROM); + break; + case 0x4000: + m_latch1 = data & 0x7f; + sun4_mirror(m_reg, m_latch1, m_latch2); + break; + case 0x5000: + m_latch2 = data & 0x7f; + sun4_mirror(m_reg, m_latch1, m_latch2); + break; + case 0x6000: + m_reg = data & 0x13; + sun4_mirror(m_reg, m_latch1, m_latch2); + break; + case 0x7000: + prg16_89ab(data & 0x0f); + m_wram_enable = BIT(data, 4); + break; + default: + LOG_MMC(("Sunsoft 4 write_h uncaught write, offset: %04x, data: %02x\n", offset, data)); + break; + } +} + +WRITE8_MEMBER(nes_sunsoft_4_device::write_m) +{ + LOG_MMC(("Sunsoft 4 write_m, offset: %04x, data: %02x\n", offset, data)); + + if (!m_battery.empty() && m_wram_enable) + m_battery[offset & (m_battery.size() - 1)] = data; + if (!m_prgram.empty() && m_wram_enable) + m_prgram[offset & (m_prgram.size() - 1)] = data; +} + +READ8_MEMBER(nes_sunsoft_4_device::read_m) +{ + LOG_MMC(("Sunsoft 4 read_m, offset: %04x\n", offset)); + + if (!m_battery.empty() && m_wram_enable) + return m_battery[offset & (m_battery.size() - 1)]; + if (!m_prgram.empty() && m_wram_enable) + return m_prgram[offset & (m_prgram.size() - 1)]; + + return m_open_bus; // open bus +} + +/*------------------------------------------------- + + JxROM & Sunsoft 5A / 5B / FME7 board emulation + + Notice that Sunsoft-5B = FME7 + sound chip (the latter being + currently unemulated in MESS) + + iNES: mapper 69 + + -------------------------------------------------*/ + +void nes_sunsoft_fme7_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (id == TIMER_IRQ) + { + if ((m_irq_enable & 0x80)) // bit7, counter decrement + { + if (!m_irq_count) + { + m_irq_count = 0xffff; + if (m_irq_enable & 0x01) // bit0, trigger enable + m_maincpu->set_input_line(M6502_IRQ_LINE, ASSERT_LINE); + } + else + m_irq_count--; + } + } +} + +WRITE8_MEMBER(nes_sunsoft_fme7_device::fme7_write) +{ + LOG_MMC(("fme7_write, offset %04x, data: %02x\n", offset, data)); + + switch (offset & 0x6000) + { + case 0x0000: + m_latch = data & 0x0f; + break; + + case 0x2000: + switch (m_latch) + { + case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: + chr1_x(m_latch, data, CHRROM); + break; + + case 8: + m_wram_bank = data; + break; + case 9: + prg8_89(data); + break; + case 0x0a: + prg8_ab(data); + break; + case 0x0b: + prg8_cd(data); + break; + case 0x0c: + switch (data & 0x03) + { + case 0x00: set_nt_mirroring(PPU_MIRROR_VERT); break; + case 0x01: set_nt_mirroring(PPU_MIRROR_HORZ); break; + case 0x02: set_nt_mirroring(PPU_MIRROR_LOW); break; + case 0x03: set_nt_mirroring(PPU_MIRROR_HIGH); break; + } + break; + case 0x0d: + m_irq_enable = data; + if (!(m_irq_enable & 1)) + m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); + break; + case 0x0e: + m_irq_count = (m_irq_count & 0xff00) | data; + break; + case 0x0f: + m_irq_count = (m_irq_count & 0x00ff) | (data << 8); + break; + } + break; + + default: + logerror("Sunsoft FME7 write_h uncaught %04x value: %02x\n", offset + 0x8000, data); + break; + } +} + +WRITE8_MEMBER(nes_sunsoft_fme7_device::write_m) +{ + UINT8 bank = m_wram_bank & 0x3f; + LOG_MMC(("Sunsoft FME7 write_m, offset: %04x, data: %02x\n", offset, data)); + + if (!(m_wram_bank & 0x40)) // is PRG ROM, no write + return; + else if (m_wram_bank & 0x80) // is PRG RAM + { + if (!m_battery.empty()) + m_battery[((bank * 0x2000) + offset) & (m_battery.size() - 1)] = data; + if (!m_prgram.empty()) + m_prgram[((bank * 0x2000) + offset) & (m_prgram.size() - 1)] = data; + } +} + +READ8_MEMBER(nes_sunsoft_fme7_device::read_m) +{ + UINT8 bank = m_wram_bank & 0x3f; + LOG_MMC(("Sunsoft FME7 read_m, offset: %04x\n", offset)); + + if (!(m_wram_bank & 0x40)) // is PRG ROM + return m_prg[((bank * 0x2000) + offset) & (m_prg_size - 1)]; + else if (m_wram_bank & 0x80) // is PRG RAM + { + if (!m_battery.empty()) + return m_battery[((bank * 0x2000) + offset) & (m_battery.size() - 1)]; + if (!m_prgram.empty()) + return m_prgram[((bank * 0x2000) + offset) & (m_prgram.size() - 1)]; + } + + return m_open_bus; // open bus +} + + +/*------------------------------------------------- + + Sunsoft 5B board emulation (FME7 + Sound) + + Games: Gimmick! + + iNES: mapper 69 + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_sunsoft_5_device::write_h) +{ + LOG_MMC(("sunsoft 5 write_h, offset %04x, data: %02x\n", offset, data)); + + switch (offset & 0x6000) + { + case 0x4000: + m_ym2149->address_w(space, 0, data & 0x0f); + break; + case 0x6000: + m_ym2149->data_w(space, 0, data); + break; + default: + fme7_write(space, offset, data, mem_mask); + break; + } +} + +//------------------------------------------------- +// MACHINE_DRIVER( sun_5b ) +//------------------------------------------------- + +// From NESdev wiki: The 5B's audio is driven by the CPU clock (1.78977267 MHz), +// but like the NES's APU, the YM2149F has an optional clock divider which +// halves the internal clock speed. By comparison of the produced pitches +// in Gimmick! with the register values used, it appears that the 5B is a +// YM2149F operating in this mode. To use an AY-3-8910 as a substitute, +// you would need an external divider to reduce the clock speed by half. + +#define SUN5_NTSC_CLOCK (21477272.724 / 12) + +static MACHINE_CONFIG_FRAGMENT( sun_5b ) + + // additional sound hardware + MCFG_SPEAKER_STANDARD_MONO("addon") + + MCFG_SOUND_ADD("ay", YM2149, SUN5_NTSC_CLOCK/2) // divide by 2 for the internal divider + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "addon", 0.50) +MACHINE_CONFIG_END + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor nes_sunsoft_5_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( sun_5b ); +} diff --git a/src/devices/bus/nes/sunsoft_dcs.c b/src/devices/bus/nes/sunsoft_dcs.c deleted file mode 100644 index c7de9fd3040..00000000000 --- a/src/devices/bus/nes/sunsoft_dcs.c +++ /dev/null @@ -1,315 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Fabio Priuli -/*********************************************************************************************************** - - - NES/Famicom cartridge emulation for Sunsoft DCS PCBs - - - Here we emulate the Sunsoft Dual Cassette System (DCS) PCB used by Nantettate!! Baseball + subslot - - - ***********************************************************************************************************/ - - -#include "emu.h" -#include "sunsoft_dcs.h" - -#ifdef NES_PCB_DEBUG -#define VERBOSE 1 -#else -#define VERBOSE 0 -#endif - -#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) - - -//----------------------------------------------- -// -// Nantettate!! Baseball Cartslot implementation -// -//----------------------------------------------- - -//------------------------------------------------- -// sub-cart interface -//------------------------------------------------- - -ntb_cart_interface::ntb_cart_interface(const machine_config &mconfig, device_t &device) - : device_slot_card_interface(mconfig, device), - m_rom(NULL) -{ -} - -ntb_cart_interface::~ntb_cart_interface() -{ -} - -//------------------------------------------------- -// sub-cart slot device -//------------------------------------------------- - -const device_type NES_NTB_SLOT = &device_creator; - -nes_ntb_slot_device::nes_ntb_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : - device_t(mconfig, NES_NTB_SLOT, "NES NTB Cartridge Slot", tag, owner, clock, "nes_ntb_slot", __FILE__), - device_image_interface(mconfig, *this), - device_slot_interface(mconfig, *this) -{ -} - -nes_ntb_slot_device::~nes_ntb_slot_device() -{ -} - - -void nes_ntb_slot_device::device_start() -{ - m_cart = dynamic_cast(get_card_device()); -} - -READ8_MEMBER(nes_ntb_slot_device::read) -{ - if (m_cart) - return m_cart->read(space, offset, mem_mask); - - return 0xff; -} - - -bool nes_ntb_slot_device::call_load() -{ - if (m_cart) - { - UINT8 *ROM = m_cart->get_cart_base(); - - if (!ROM) - return IMAGE_INIT_FAIL; - - if (software_entry() == NULL) - { - if (length() != 0x4000) - return IMAGE_INIT_FAIL; - - fread(&ROM, 0x4000); - } - else - { - if (get_software_region_length("rom") != 0x4000) - return IMAGE_INIT_FAIL; - - memcpy(ROM, get_software_region("rom"), 0x4000); - } - } - - return IMAGE_INIT_PASS; -} - - -bool nes_ntb_slot_device::call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry) -{ - load_software_part_region(*this, swlist, swname, start_entry ); - return TRUE; -} - -void nes_ntb_slot_device::get_default_card_software(std::string &result) -{ - software_get_default_slot(result, "ntbrom"); -} - -//----------------------------------------------- -// -// Nantettate!! Baseball Minicart implementation -// -//----------------------------------------------- - -ROM_START( ntb_rom ) - ROM_REGION(0x4000, "ntbrom", ROMREGION_ERASEFF) -ROM_END - -const device_type NES_NTB_ROM = &device_creator; - -nes_ntb_rom_device::nes_ntb_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : device_t(mconfig, NES_NTB_ROM, "NES NTB ROM", tag, owner, clock, "nes_ntbrom", __FILE__), - ntb_cart_interface( mconfig, *this ) -{ -} - -void nes_ntb_rom_device::device_start() -{ - m_rom = (UINT8*)memregion("ntbrom")->base(); -} - -const rom_entry *nes_ntb_rom_device::device_rom_region() const -{ - return ROM_NAME( ntb_rom ); -} - -UINT8 *nes_ntb_rom_device::get_cart_base() -{ - return m_rom; -} - - - -//------------------------------------------------ -// -// Nantettate!! Baseball base cart implementation -// a.k.a. Sunsoft Dual Cassette System -// (variant of Sunsoft-4 PCB) -// -//------------------------------------------------ - -const device_type NES_SUNSOFT_DCS = &device_creator; - - -nes_sunsoft_dcs_device::nes_sunsoft_dcs_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_sunsoft_4_device(mconfig, NES_SUNSOFT_DCS, "NES Cart Sunsoft DCS PCB", tag, owner, clock, "nes_dcs", __FILE__), - m_subslot(*this, "ntb_slot") -{ -} - - -void nes_sunsoft_dcs_device::device_start() -{ - common_start(); - ntb_enable_timer = timer_alloc(TIMER_PROTECT); - ntb_enable_timer->reset(); - timer_freq = machine().device("maincpu")->cycles_to_attotime(107520); - - save_item(NAME(m_latch1)); - save_item(NAME(m_latch2)); - save_item(NAME(m_reg)); - save_item(NAME(m_wram_enable)); - save_item(NAME(m_exrom_enable)); - save_item(NAME(m_timer_on)); -} - -void nes_sunsoft_dcs_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(0); - prg16_cdef(m_prg_chunks - 1); - chr8(0, m_chr_source); - - m_reg = 0; - m_latch1 = 0; - m_latch2 = 0; - m_wram_enable = 0; - m_exrom_enable = 0; - m_timer_on = 0; -} - - -/*------------------------------------------------- - mapper specific handlers - -------------------------------------------------*/ - -/*------------------------------------------------- - - Sunsoft-DCS board emulation - - Games: Nantettatte!! Baseball - - This board feature a subslot to load minicart containing - updated data? - - iNES: mapper 68 - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_sunsoft_dcs_device::write_h) -{ - LOG_MMC(("Sunsoft DCS write_h, offset %04x, data: %02x\n", offset, data)); - - switch (offset & 0x7000) - { - case 0x7000: - prg16_89ab(data & 0x07); - m_exrom_enable = !BIT(data, 3); - m_wram_enable = BIT(data, 4); - break; - default: - sun4_write(space, offset, data, mem_mask); - break; - } -} - -READ8_MEMBER(nes_sunsoft_dcs_device::read_h) -{ - LOG_MMC(("Sunsoft DCS read_h, offset: %04x\n", offset)); - - if (m_exrom_enable && m_subslot->m_cart && offset < 0x4000) - { - if (m_timer_on) - return m_subslot->m_cart->read(space, offset, mem_mask); - else - return m_open_bus; // after the timer is off, this returns open bus... - } - else - return hi_access_rom(offset); -} - -WRITE8_MEMBER(nes_sunsoft_dcs_device::write_m) -{ - LOG_MMC(("Sunsoft DCS write_m, offset: %04x, data: %02x\n", offset, data)); - - if (!m_battery.empty() && m_wram_enable) - m_battery[offset & (m_battery.size() - 1)] = data; - if (!m_prgram.empty() && m_wram_enable) - m_prgram[offset & (m_prgram.size() - 1)] = data; - if (!m_wram_enable && !m_timer_on) - { - m_timer_on = 1; - // start NTB-ROM timer - ntb_enable_timer->adjust(timer_freq); - } -} - -READ8_MEMBER(nes_sunsoft_dcs_device::read_m) -{ - LOG_MMC(("Sunsoft DCS read_m, offset: %04x\n", offset)); - - if (!m_battery.empty() && m_wram_enable) - return m_battery[offset & (m_battery.size() - 1)]; - if (!m_prgram.empty() && m_wram_enable) - return m_prgram[offset & (m_prgram.size() - 1)]; - - return m_open_bus; // open bus -} - -//------------------------------------------------- -// MACHINE_CONFIG_FRAGMENT( sub_slot ) -//------------------------------------------------- - -static SLOT_INTERFACE_START(ntb_cart) - SLOT_INTERFACE_INTERNAL("ntbrom", NES_NTB_ROM) -SLOT_INTERFACE_END - -static MACHINE_CONFIG_FRAGMENT( sub_slot ) - MCFG_NTB_MINICART_ADD("ntb_slot", ntb_cart) -MACHINE_CONFIG_END - - -//------------------------------------------------- -// machine_config_additions - device-specific -// machine configurations -//------------------------------------------------- - -machine_config_constructor nes_sunsoft_dcs_device::device_mconfig_additions() const -{ - return MACHINE_CONFIG_NAME( sub_slot ); -} - - -//------------------------------------------------- -// device_timer - handler timer events -//------------------------------------------------- - -void nes_sunsoft_dcs_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) -{ - if (id == TIMER_PROTECT) - { - m_timer_on = 0; - ntb_enable_timer->reset(); - } -} diff --git a/src/devices/bus/nes/sunsoft_dcs.cpp b/src/devices/bus/nes/sunsoft_dcs.cpp new file mode 100644 index 00000000000..c7de9fd3040 --- /dev/null +++ b/src/devices/bus/nes/sunsoft_dcs.cpp @@ -0,0 +1,315 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for Sunsoft DCS PCBs + + + Here we emulate the Sunsoft Dual Cassette System (DCS) PCB used by Nantettate!! Baseball + subslot + + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "sunsoft_dcs.h" + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//----------------------------------------------- +// +// Nantettate!! Baseball Cartslot implementation +// +//----------------------------------------------- + +//------------------------------------------------- +// sub-cart interface +//------------------------------------------------- + +ntb_cart_interface::ntb_cart_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig, device), + m_rom(NULL) +{ +} + +ntb_cart_interface::~ntb_cart_interface() +{ +} + +//------------------------------------------------- +// sub-cart slot device +//------------------------------------------------- + +const device_type NES_NTB_SLOT = &device_creator; + +nes_ntb_slot_device::nes_ntb_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, NES_NTB_SLOT, "NES NTB Cartridge Slot", tag, owner, clock, "nes_ntb_slot", __FILE__), + device_image_interface(mconfig, *this), + device_slot_interface(mconfig, *this) +{ +} + +nes_ntb_slot_device::~nes_ntb_slot_device() +{ +} + + +void nes_ntb_slot_device::device_start() +{ + m_cart = dynamic_cast(get_card_device()); +} + +READ8_MEMBER(nes_ntb_slot_device::read) +{ + if (m_cart) + return m_cart->read(space, offset, mem_mask); + + return 0xff; +} + + +bool nes_ntb_slot_device::call_load() +{ + if (m_cart) + { + UINT8 *ROM = m_cart->get_cart_base(); + + if (!ROM) + return IMAGE_INIT_FAIL; + + if (software_entry() == NULL) + { + if (length() != 0x4000) + return IMAGE_INIT_FAIL; + + fread(&ROM, 0x4000); + } + else + { + if (get_software_region_length("rom") != 0x4000) + return IMAGE_INIT_FAIL; + + memcpy(ROM, get_software_region("rom"), 0x4000); + } + } + + return IMAGE_INIT_PASS; +} + + +bool nes_ntb_slot_device::call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry) +{ + load_software_part_region(*this, swlist, swname, start_entry ); + return TRUE; +} + +void nes_ntb_slot_device::get_default_card_software(std::string &result) +{ + software_get_default_slot(result, "ntbrom"); +} + +//----------------------------------------------- +// +// Nantettate!! Baseball Minicart implementation +// +//----------------------------------------------- + +ROM_START( ntb_rom ) + ROM_REGION(0x4000, "ntbrom", ROMREGION_ERASEFF) +ROM_END + +const device_type NES_NTB_ROM = &device_creator; + +nes_ntb_rom_device::nes_ntb_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, NES_NTB_ROM, "NES NTB ROM", tag, owner, clock, "nes_ntbrom", __FILE__), + ntb_cart_interface( mconfig, *this ) +{ +} + +void nes_ntb_rom_device::device_start() +{ + m_rom = (UINT8*)memregion("ntbrom")->base(); +} + +const rom_entry *nes_ntb_rom_device::device_rom_region() const +{ + return ROM_NAME( ntb_rom ); +} + +UINT8 *nes_ntb_rom_device::get_cart_base() +{ + return m_rom; +} + + + +//------------------------------------------------ +// +// Nantettate!! Baseball base cart implementation +// a.k.a. Sunsoft Dual Cassette System +// (variant of Sunsoft-4 PCB) +// +//------------------------------------------------ + +const device_type NES_SUNSOFT_DCS = &device_creator; + + +nes_sunsoft_dcs_device::nes_sunsoft_dcs_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_sunsoft_4_device(mconfig, NES_SUNSOFT_DCS, "NES Cart Sunsoft DCS PCB", tag, owner, clock, "nes_dcs", __FILE__), + m_subslot(*this, "ntb_slot") +{ +} + + +void nes_sunsoft_dcs_device::device_start() +{ + common_start(); + ntb_enable_timer = timer_alloc(TIMER_PROTECT); + ntb_enable_timer->reset(); + timer_freq = machine().device("maincpu")->cycles_to_attotime(107520); + + save_item(NAME(m_latch1)); + save_item(NAME(m_latch2)); + save_item(NAME(m_reg)); + save_item(NAME(m_wram_enable)); + save_item(NAME(m_exrom_enable)); + save_item(NAME(m_timer_on)); +} + +void nes_sunsoft_dcs_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + + m_reg = 0; + m_latch1 = 0; + m_latch2 = 0; + m_wram_enable = 0; + m_exrom_enable = 0; + m_timer_on = 0; +} + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + Sunsoft-DCS board emulation + + Games: Nantettatte!! Baseball + + This board feature a subslot to load minicart containing + updated data? + + iNES: mapper 68 + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_sunsoft_dcs_device::write_h) +{ + LOG_MMC(("Sunsoft DCS write_h, offset %04x, data: %02x\n", offset, data)); + + switch (offset & 0x7000) + { + case 0x7000: + prg16_89ab(data & 0x07); + m_exrom_enable = !BIT(data, 3); + m_wram_enable = BIT(data, 4); + break; + default: + sun4_write(space, offset, data, mem_mask); + break; + } +} + +READ8_MEMBER(nes_sunsoft_dcs_device::read_h) +{ + LOG_MMC(("Sunsoft DCS read_h, offset: %04x\n", offset)); + + if (m_exrom_enable && m_subslot->m_cart && offset < 0x4000) + { + if (m_timer_on) + return m_subslot->m_cart->read(space, offset, mem_mask); + else + return m_open_bus; // after the timer is off, this returns open bus... + } + else + return hi_access_rom(offset); +} + +WRITE8_MEMBER(nes_sunsoft_dcs_device::write_m) +{ + LOG_MMC(("Sunsoft DCS write_m, offset: %04x, data: %02x\n", offset, data)); + + if (!m_battery.empty() && m_wram_enable) + m_battery[offset & (m_battery.size() - 1)] = data; + if (!m_prgram.empty() && m_wram_enable) + m_prgram[offset & (m_prgram.size() - 1)] = data; + if (!m_wram_enable && !m_timer_on) + { + m_timer_on = 1; + // start NTB-ROM timer + ntb_enable_timer->adjust(timer_freq); + } +} + +READ8_MEMBER(nes_sunsoft_dcs_device::read_m) +{ + LOG_MMC(("Sunsoft DCS read_m, offset: %04x\n", offset)); + + if (!m_battery.empty() && m_wram_enable) + return m_battery[offset & (m_battery.size() - 1)]; + if (!m_prgram.empty() && m_wram_enable) + return m_prgram[offset & (m_prgram.size() - 1)]; + + return m_open_bus; // open bus +} + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( sub_slot ) +//------------------------------------------------- + +static SLOT_INTERFACE_START(ntb_cart) + SLOT_INTERFACE_INTERNAL("ntbrom", NES_NTB_ROM) +SLOT_INTERFACE_END + +static MACHINE_CONFIG_FRAGMENT( sub_slot ) + MCFG_NTB_MINICART_ADD("ntb_slot", ntb_cart) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor nes_sunsoft_dcs_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( sub_slot ); +} + + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +void nes_sunsoft_dcs_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (id == TIMER_PROTECT) + { + m_timer_on = 0; + ntb_enable_timer->reset(); + } +} diff --git a/src/devices/bus/nes/taito.c b/src/devices/bus/nes/taito.c deleted file mode 100644 index 2338d91ee25..00000000000 --- a/src/devices/bus/nes/taito.c +++ /dev/null @@ -1,470 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Fabio Priuli -/*********************************************************************************************************** - - - NES/Famicom cartridge emulation for Taito PCBs - - - Here we emulate the following PCBs - - * Taito TC0190FMC/TC0190FMR [mapper 33] - * Taito TC0190FMC+PAL16R4 [mapper 48] - * Taito X1-005 [mapper 80, 207] - * Taito X1-017 [mapper 82] - - TODO: - - Akira does not work. Investigate why! - - Don Doko Don 2 freezes when you get to the first boss - - - ***********************************************************************************************************/ - - -#include "emu.h" -#include "taito.h" - -#include "cpu/m6502/m6502.h" -#include "video/ppu2c0x.h" // this has to be included so that IRQ functions can access PPU_BOTTOM_VISIBLE_SCANLINE - - -#ifdef NES_PCB_DEBUG -#define VERBOSE 1 -#else -#define VERBOSE 0 -#endif - -#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) - - -//------------------------------------------------- -// constructor -//------------------------------------------------- - -const device_type NES_TC0190FMC = &device_creator; -const device_type NES_TC0190FMC_PAL16R4 = &device_creator; -const device_type NES_X1_005 = &device_creator; -const device_type NES_X1_017 = &device_creator; - - -nes_tc0190fmc_device::nes_tc0190fmc_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) - : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source) -{ -} - -nes_tc0190fmc_device::nes_tc0190fmc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_TC0190FMC, "NES Cart Taito TC0190FMC PCB", tag, owner, clock, "nes_tc0190fmc", __FILE__) -{ -} - -nes_tc0190fmc_pal16r4_device::nes_tc0190fmc_pal16r4_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_tc0190fmc_device(mconfig, NES_TC0190FMC_PAL16R4, "NES Cart Taito TC0190FMC + PAL16R4 PCB", tag, owner, clock, "nes_tc0190pal", __FILE__) -{ -} - -nes_x1_005_device::nes_x1_005_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_X1_005, "NES Cart Taito X1-005 PCB", tag, owner, clock, "nes_x1_005", __FILE__) -{ -} - -nes_x1_017_device::nes_x1_017_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_X1_017, "NES Cart Taito X1-017 PCB", tag, owner, clock, "nes_x1_017", __FILE__) -{ -} - - - -void nes_tc0190fmc_device::device_start() -{ - common_start(); -} - -void nes_tc0190fmc_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(0); - prg16_cdef(m_prg_chunks - 1); - chr8(0, m_chr_source); -} - -void nes_tc0190fmc_pal16r4_device::device_start() -{ - common_start(); - save_item(NAME(m_irq_enable)); - save_item(NAME(m_irq_count)); - save_item(NAME(m_irq_count_latch)); -} - -void nes_tc0190fmc_pal16r4_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(0); - prg16_cdef(m_prg_chunks - 1); - chr8(0, m_chr_source); - - m_irq_enable = 0; - m_irq_count = 0; - m_irq_count_latch = 0; -} - -void nes_x1_005_device::device_start() -{ - common_start(); - save_item(NAME(m_latch)); - - save_item(NAME(m_x1_005_ram)); - - m_mapper_sram_size = 0x80; - m_mapper_sram = m_x1_005_ram; -} - -void nes_x1_005_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(0); - prg16_cdef(m_prg_chunks - 1); - chr8(0, m_chr_source); - - m_latch = 0; -} - -void nes_x1_017_device::device_start() -{ - common_start(); - save_item(NAME(m_latch)); - save_item(NAME(m_reg)); - save_item(NAME(m_mmc_vrom_bank)); - - save_item(NAME(m_x1_017_ram)); - - m_mapper_sram_size = 0x1400; - m_mapper_sram = m_x1_017_ram; -} - -void nes_x1_017_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(0); - prg16_cdef(m_prg_chunks - 1); - chr8(0, m_chr_source); - - m_latch = 0; - memset(m_reg, 0, sizeof(m_reg)); - memset(m_mmc_vrom_bank, 0, sizeof(m_mmc_vrom_bank)); -} - - - -/*------------------------------------------------- - mapper specific handlers - -------------------------------------------------*/ - -/*------------------------------------------------- - - Taito TC0190FMC board emulation - - Games: Akira, Bakushou!! Jinsei Gekijou, Don Doko Don, - Insector X, Operation Wolf, Power Blazer, Takeshi no - Sengoku Fuuunji - - iNES: mapper 33 - - In MESS: Supported. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_tc0190fmc_device::tc0190fmc_write) -{ - LOG_MMC(("tc0190fmc_write, offset: %04x, data: %02x\n", offset, data)); - - switch (offset & 0x7003) - { - case 0x0000: - set_nt_mirroring(BIT(data, 6) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); - prg8_89(data); - break; - case 0x0001: - prg8_ab(data); - break; - case 0x0002: - chr2_0(data, CHRROM); - break; - case 0x0003: - chr2_2(data, CHRROM); - break; - case 0x2000: - chr1_4(data, CHRROM); - break; - case 0x2001: - chr1_5(data, CHRROM); - break; - case 0x2002: - chr1_6(data, CHRROM); - break; - case 0x2003: - chr1_7(data, CHRROM); - break; - } -} - -/*------------------------------------------------- - - Taito TC0190FMC + PAL16R4 board emulation - - Games: Bakushou!! Jinsei Gekijou 3, Bubble Bobble 2, - Captain Saver, Don Doko Don 2, Flintstones, Jetsons - - This is basically Mapper 33 + IRQ. Notably, IRQ works the - same as MMC3 irq, BUT latch values are "inverted" (XOR'ed - with 0xff) and there is a little delay (not implemented yet) - We simply use MMC3 IRQ and XOR the value written in the - register 0xc000 below - - iNES: mapper 48 - - In MESS: Supported. - - -------------------------------------------------*/ - -void nes_tc0190fmc_pal16r4_device::hblank_irq( int scanline, int vblank, int blanked ) -{ - if (scanline < PPU_BOTTOM_VISIBLE_SCANLINE) - { - int prior_count = m_irq_count; - if (m_irq_count == 0) - m_irq_count = m_irq_count_latch; - else - m_irq_count--; - - if (m_irq_enable && !blanked && (m_irq_count == 0) && prior_count) - m_maincpu->set_input_line(M6502_IRQ_LINE, ASSERT_LINE); - } -} - -WRITE8_MEMBER(nes_tc0190fmc_pal16r4_device::write_h) -{ - LOG_MMC(("tc0190fmc pal16r4 write_h, offset: %04x, data: %02x\n", offset, data)); - - switch (offset & 0x7003) - { - case 0x0000: - prg8_89(data); - break; - case 0x0001: - case 0x0002: - case 0x0003: - case 0x2000: - case 0x2001: - case 0x2002: - case 0x2003: - tc0190fmc_write(space, offset, data, mem_mask); - break; - case 0x4000: - m_irq_count_latch = (0x100 - data) & 0xff; - break; - case 0x4001: - m_irq_count = m_irq_count_latch; - break; - case 0x4002: - m_irq_enable = 1; - break; - case 0x4003: - m_irq_enable = 0; - m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); - break; - case 0x6000: - set_nt_mirroring(BIT(data, 6) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); - break; - } -} - -/*------------------------------------------------- - - Taito X1-005 board emulation - - Actually, Fudou Myouou Den uses a variant of the board with - CIRAM, making necessary two distinct mappers & pcb_id. - - Also, we miss to emulate the security check at 0x7ef8 / 0x7ef9 - and the 0x80 ram! - - iNES: mappers 80 & 207 - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_x1_005_device::write_m) -{ - LOG_MMC(("x1_005 write_m, offset: %04x, data: %02x\n", offset, data)); - - switch (offset) - { - case 0x1ef0: - chr2_0((data & 0x7f) >> 1, CHRROM); - if (m_x1_005_alt_mirroring) - { - set_nt_page(0, CIRAM, (data & 0x80) ? 1 : 0, 1); - set_nt_page(1, CIRAM, (data & 0x80) ? 1 : 0, 1); - } - break; - case 0x1ef1: - chr2_2((data & 0x7f) >> 1, CHRROM); - if (m_x1_005_alt_mirroring) - { - set_nt_page(2, CIRAM, (data & 0x80) ? 1 : 0, 1); - set_nt_page(3, CIRAM, (data & 0x80) ? 1 : 0, 1); - } - break; - case 0x1ef2: - chr1_4(data, CHRROM); - break; - case 0x1ef3: - chr1_5(data, CHRROM); - break; - case 0x1ef4: - chr1_6(data, CHRROM); - break; - case 0x1ef5: - chr1_7(data, CHRROM); - break; - case 0x1ef6: - case 0x1ef7: - if (!m_x1_005_alt_mirroring) - set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ); - break; - case 0x1ef8: - case 0x1ef9: - m_latch = data; - break; - case 0x1efa: - case 0x1efb: - prg8_89(data); - break; - case 0x1efc: - case 0x1efd: - prg8_ab(data); - break; - case 0x1efe: - case 0x1eff: - prg8_cd(data); - break; - default: - logerror("mapper80_m_w uncaught addr: %04x, value: %02x\n", offset + 0x6000, data); - break; - } - - if (offset >= 0x1f00 && m_latch == 0xa3) - m_x1_005_ram[offset & 0x7f] = data; -} - -READ8_MEMBER(nes_x1_005_device::read_m) -{ - LOG_MMC(("x1_005 read_m, offset: %04x\n", offset)); - - if (offset >= 0x1f00 && m_latch == 0xa3) - return m_x1_005_ram[offset & 0x7f]; - - return m_open_bus; // open bus -} - -/*------------------------------------------------- - - Taito X1-017 board emulation - - We miss to emulate the security check at 0x6000-0x73ff - and the ram! - - Games: Kyuukyoku Harikiri Koushien, Kyuukyoku Harikiri - Stadium, SD Keiji - Blader - - iNES: mapper 82 - - In MESS: Supported. - - -------------------------------------------------*/ - -void nes_x1_017_device::set_chr() -{ - if (m_latch) - { - chr2_4(m_mmc_vrom_bank[0] >> 1, CHRROM); - chr2_6(m_mmc_vrom_bank[1] >> 1, CHRROM); - } - else - { - chr2_0(m_mmc_vrom_bank[0] >> 1, CHRROM); - chr2_2(m_mmc_vrom_bank[1] >> 1, CHRROM); - } - chr1_x(4 ^ m_latch, m_mmc_vrom_bank[2], CHRROM); - chr1_x(5 ^ m_latch, m_mmc_vrom_bank[3], CHRROM); - chr1_x(6 ^ m_latch, m_mmc_vrom_bank[4], CHRROM); - chr1_x(7 ^ m_latch, m_mmc_vrom_bank[5], CHRROM); -} - -WRITE8_MEMBER(nes_x1_017_device::write_m) -{ - LOG_MMC(("x1017 write_m, offset: %04x, data: %02x\n", offset, data)); - - switch (offset) - { - case 0x1ef0: - case 0x1ef1: - case 0x1ef2: - case 0x1ef3: - case 0x1ef4: - case 0x1ef5: - if (m_mmc_vrom_bank[offset & 0x07] != data) - { - m_mmc_vrom_bank[offset & 0x07] = data; - set_chr(); - } - break; - case 0x1ef6: - set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ); - if (m_latch != ((data & 0x02) << 1)) - { - m_latch = ((data & 0x02) << 1); - set_chr(); - } - break; - case 0x1ef7: - case 0x1ef8: - case 0x1ef9: - m_reg[(offset & 0x0f) - 7] = data; - break; - case 0x1efa: - prg8_89(data >> 2); - break; - case 0x1efb: - prg8_ab(data >> 2); - break; - case 0x1efc: - prg8_cd(data >> 2); - break; - default: - logerror("x1017_m_w uncaught write, addr: %04x, value: %02x\n", offset + 0x6000, data); - break; - } - - // 2+2+1 KB of Internal RAM can be independently enabled/disabled! - if (offset < 0x0800 && m_reg[0] == 0xca) - m_x1_017_ram[0x0000 + (offset & 0x7ff)] = data; - if (offset < 0x1000 && m_reg[1] == 0x69) - m_x1_017_ram[0x0800 + (offset & 0x7ff)] = data; - if (offset < 0x1400 && m_reg[2] == 0x84) - m_x1_017_ram[0x1000 + (offset & 0x3ff)] = data; -} - -READ8_MEMBER(nes_x1_017_device::read_m) -{ - LOG_MMC(("x1017 read_m, offset: %04x\n", offset)); - - // 2+2+1 KB of Internal RAM can be independently enabled/disabled! - if (offset < 0x0800 && m_reg[0] == 0xca) - return m_x1_017_ram[0x0000 + (offset & 0x7ff)]; - if (offset < 0x1000 && m_reg[1] == 0x69) - return m_x1_017_ram[0x0800 + (offset & 0x7ff)]; - if (offset < 0x1400 && m_reg[2] == 0x84) - return m_x1_017_ram[0x1000 + (offset & 0x3ff)]; - - return m_open_bus; // open bus -} diff --git a/src/devices/bus/nes/taito.cpp b/src/devices/bus/nes/taito.cpp new file mode 100644 index 00000000000..2338d91ee25 --- /dev/null +++ b/src/devices/bus/nes/taito.cpp @@ -0,0 +1,470 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for Taito PCBs + + + Here we emulate the following PCBs + + * Taito TC0190FMC/TC0190FMR [mapper 33] + * Taito TC0190FMC+PAL16R4 [mapper 48] + * Taito X1-005 [mapper 80, 207] + * Taito X1-017 [mapper 82] + + TODO: + - Akira does not work. Investigate why! + - Don Doko Don 2 freezes when you get to the first boss + + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "taito.h" + +#include "cpu/m6502/m6502.h" +#include "video/ppu2c0x.h" // this has to be included so that IRQ functions can access PPU_BOTTOM_VISIBLE_SCANLINE + + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_TC0190FMC = &device_creator; +const device_type NES_TC0190FMC_PAL16R4 = &device_creator; +const device_type NES_X1_005 = &device_creator; +const device_type NES_X1_017 = &device_creator; + + +nes_tc0190fmc_device::nes_tc0190fmc_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +nes_tc0190fmc_device::nes_tc0190fmc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_TC0190FMC, "NES Cart Taito TC0190FMC PCB", tag, owner, clock, "nes_tc0190fmc", __FILE__) +{ +} + +nes_tc0190fmc_pal16r4_device::nes_tc0190fmc_pal16r4_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_tc0190fmc_device(mconfig, NES_TC0190FMC_PAL16R4, "NES Cart Taito TC0190FMC + PAL16R4 PCB", tag, owner, clock, "nes_tc0190pal", __FILE__) +{ +} + +nes_x1_005_device::nes_x1_005_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_X1_005, "NES Cart Taito X1-005 PCB", tag, owner, clock, "nes_x1_005", __FILE__) +{ +} + +nes_x1_017_device::nes_x1_017_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_X1_017, "NES Cart Taito X1-017 PCB", tag, owner, clock, "nes_x1_017", __FILE__) +{ +} + + + +void nes_tc0190fmc_device::device_start() +{ + common_start(); +} + +void nes_tc0190fmc_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); +} + +void nes_tc0190fmc_pal16r4_device::device_start() +{ + common_start(); + save_item(NAME(m_irq_enable)); + save_item(NAME(m_irq_count)); + save_item(NAME(m_irq_count_latch)); +} + +void nes_tc0190fmc_pal16r4_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + + m_irq_enable = 0; + m_irq_count = 0; + m_irq_count_latch = 0; +} + +void nes_x1_005_device::device_start() +{ + common_start(); + save_item(NAME(m_latch)); + + save_item(NAME(m_x1_005_ram)); + + m_mapper_sram_size = 0x80; + m_mapper_sram = m_x1_005_ram; +} + +void nes_x1_005_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + + m_latch = 0; +} + +void nes_x1_017_device::device_start() +{ + common_start(); + save_item(NAME(m_latch)); + save_item(NAME(m_reg)); + save_item(NAME(m_mmc_vrom_bank)); + + save_item(NAME(m_x1_017_ram)); + + m_mapper_sram_size = 0x1400; + m_mapper_sram = m_x1_017_ram; +} + +void nes_x1_017_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + + m_latch = 0; + memset(m_reg, 0, sizeof(m_reg)); + memset(m_mmc_vrom_bank, 0, sizeof(m_mmc_vrom_bank)); +} + + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + Taito TC0190FMC board emulation + + Games: Akira, Bakushou!! Jinsei Gekijou, Don Doko Don, + Insector X, Operation Wolf, Power Blazer, Takeshi no + Sengoku Fuuunji + + iNES: mapper 33 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_tc0190fmc_device::tc0190fmc_write) +{ + LOG_MMC(("tc0190fmc_write, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x7003) + { + case 0x0000: + set_nt_mirroring(BIT(data, 6) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + prg8_89(data); + break; + case 0x0001: + prg8_ab(data); + break; + case 0x0002: + chr2_0(data, CHRROM); + break; + case 0x0003: + chr2_2(data, CHRROM); + break; + case 0x2000: + chr1_4(data, CHRROM); + break; + case 0x2001: + chr1_5(data, CHRROM); + break; + case 0x2002: + chr1_6(data, CHRROM); + break; + case 0x2003: + chr1_7(data, CHRROM); + break; + } +} + +/*------------------------------------------------- + + Taito TC0190FMC + PAL16R4 board emulation + + Games: Bakushou!! Jinsei Gekijou 3, Bubble Bobble 2, + Captain Saver, Don Doko Don 2, Flintstones, Jetsons + + This is basically Mapper 33 + IRQ. Notably, IRQ works the + same as MMC3 irq, BUT latch values are "inverted" (XOR'ed + with 0xff) and there is a little delay (not implemented yet) + We simply use MMC3 IRQ and XOR the value written in the + register 0xc000 below + + iNES: mapper 48 + + In MESS: Supported. + + -------------------------------------------------*/ + +void nes_tc0190fmc_pal16r4_device::hblank_irq( int scanline, int vblank, int blanked ) +{ + if (scanline < PPU_BOTTOM_VISIBLE_SCANLINE) + { + int prior_count = m_irq_count; + if (m_irq_count == 0) + m_irq_count = m_irq_count_latch; + else + m_irq_count--; + + if (m_irq_enable && !blanked && (m_irq_count == 0) && prior_count) + m_maincpu->set_input_line(M6502_IRQ_LINE, ASSERT_LINE); + } +} + +WRITE8_MEMBER(nes_tc0190fmc_pal16r4_device::write_h) +{ + LOG_MMC(("tc0190fmc pal16r4 write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x7003) + { + case 0x0000: + prg8_89(data); + break; + case 0x0001: + case 0x0002: + case 0x0003: + case 0x2000: + case 0x2001: + case 0x2002: + case 0x2003: + tc0190fmc_write(space, offset, data, mem_mask); + break; + case 0x4000: + m_irq_count_latch = (0x100 - data) & 0xff; + break; + case 0x4001: + m_irq_count = m_irq_count_latch; + break; + case 0x4002: + m_irq_enable = 1; + break; + case 0x4003: + m_irq_enable = 0; + m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); + break; + case 0x6000: + set_nt_mirroring(BIT(data, 6) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + break; + } +} + +/*------------------------------------------------- + + Taito X1-005 board emulation + + Actually, Fudou Myouou Den uses a variant of the board with + CIRAM, making necessary two distinct mappers & pcb_id. + + Also, we miss to emulate the security check at 0x7ef8 / 0x7ef9 + and the 0x80 ram! + + iNES: mappers 80 & 207 + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_x1_005_device::write_m) +{ + LOG_MMC(("x1_005 write_m, offset: %04x, data: %02x\n", offset, data)); + + switch (offset) + { + case 0x1ef0: + chr2_0((data & 0x7f) >> 1, CHRROM); + if (m_x1_005_alt_mirroring) + { + set_nt_page(0, CIRAM, (data & 0x80) ? 1 : 0, 1); + set_nt_page(1, CIRAM, (data & 0x80) ? 1 : 0, 1); + } + break; + case 0x1ef1: + chr2_2((data & 0x7f) >> 1, CHRROM); + if (m_x1_005_alt_mirroring) + { + set_nt_page(2, CIRAM, (data & 0x80) ? 1 : 0, 1); + set_nt_page(3, CIRAM, (data & 0x80) ? 1 : 0, 1); + } + break; + case 0x1ef2: + chr1_4(data, CHRROM); + break; + case 0x1ef3: + chr1_5(data, CHRROM); + break; + case 0x1ef4: + chr1_6(data, CHRROM); + break; + case 0x1ef5: + chr1_7(data, CHRROM); + break; + case 0x1ef6: + case 0x1ef7: + if (!m_x1_005_alt_mirroring) + set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ); + break; + case 0x1ef8: + case 0x1ef9: + m_latch = data; + break; + case 0x1efa: + case 0x1efb: + prg8_89(data); + break; + case 0x1efc: + case 0x1efd: + prg8_ab(data); + break; + case 0x1efe: + case 0x1eff: + prg8_cd(data); + break; + default: + logerror("mapper80_m_w uncaught addr: %04x, value: %02x\n", offset + 0x6000, data); + break; + } + + if (offset >= 0x1f00 && m_latch == 0xa3) + m_x1_005_ram[offset & 0x7f] = data; +} + +READ8_MEMBER(nes_x1_005_device::read_m) +{ + LOG_MMC(("x1_005 read_m, offset: %04x\n", offset)); + + if (offset >= 0x1f00 && m_latch == 0xa3) + return m_x1_005_ram[offset & 0x7f]; + + return m_open_bus; // open bus +} + +/*------------------------------------------------- + + Taito X1-017 board emulation + + We miss to emulate the security check at 0x6000-0x73ff + and the ram! + + Games: Kyuukyoku Harikiri Koushien, Kyuukyoku Harikiri + Stadium, SD Keiji - Blader + + iNES: mapper 82 + + In MESS: Supported. + + -------------------------------------------------*/ + +void nes_x1_017_device::set_chr() +{ + if (m_latch) + { + chr2_4(m_mmc_vrom_bank[0] >> 1, CHRROM); + chr2_6(m_mmc_vrom_bank[1] >> 1, CHRROM); + } + else + { + chr2_0(m_mmc_vrom_bank[0] >> 1, CHRROM); + chr2_2(m_mmc_vrom_bank[1] >> 1, CHRROM); + } + chr1_x(4 ^ m_latch, m_mmc_vrom_bank[2], CHRROM); + chr1_x(5 ^ m_latch, m_mmc_vrom_bank[3], CHRROM); + chr1_x(6 ^ m_latch, m_mmc_vrom_bank[4], CHRROM); + chr1_x(7 ^ m_latch, m_mmc_vrom_bank[5], CHRROM); +} + +WRITE8_MEMBER(nes_x1_017_device::write_m) +{ + LOG_MMC(("x1017 write_m, offset: %04x, data: %02x\n", offset, data)); + + switch (offset) + { + case 0x1ef0: + case 0x1ef1: + case 0x1ef2: + case 0x1ef3: + case 0x1ef4: + case 0x1ef5: + if (m_mmc_vrom_bank[offset & 0x07] != data) + { + m_mmc_vrom_bank[offset & 0x07] = data; + set_chr(); + } + break; + case 0x1ef6: + set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ); + if (m_latch != ((data & 0x02) << 1)) + { + m_latch = ((data & 0x02) << 1); + set_chr(); + } + break; + case 0x1ef7: + case 0x1ef8: + case 0x1ef9: + m_reg[(offset & 0x0f) - 7] = data; + break; + case 0x1efa: + prg8_89(data >> 2); + break; + case 0x1efb: + prg8_ab(data >> 2); + break; + case 0x1efc: + prg8_cd(data >> 2); + break; + default: + logerror("x1017_m_w uncaught write, addr: %04x, value: %02x\n", offset + 0x6000, data); + break; + } + + // 2+2+1 KB of Internal RAM can be independently enabled/disabled! + if (offset < 0x0800 && m_reg[0] == 0xca) + m_x1_017_ram[0x0000 + (offset & 0x7ff)] = data; + if (offset < 0x1000 && m_reg[1] == 0x69) + m_x1_017_ram[0x0800 + (offset & 0x7ff)] = data; + if (offset < 0x1400 && m_reg[2] == 0x84) + m_x1_017_ram[0x1000 + (offset & 0x3ff)] = data; +} + +READ8_MEMBER(nes_x1_017_device::read_m) +{ + LOG_MMC(("x1017 read_m, offset: %04x\n", offset)); + + // 2+2+1 KB of Internal RAM can be independently enabled/disabled! + if (offset < 0x0800 && m_reg[0] == 0xca) + return m_x1_017_ram[0x0000 + (offset & 0x7ff)]; + if (offset < 0x1000 && m_reg[1] == 0x69) + return m_x1_017_ram[0x0800 + (offset & 0x7ff)]; + if (offset < 0x1400 && m_reg[2] == 0x84) + return m_x1_017_ram[0x1000 + (offset & 0x3ff)]; + + return m_open_bus; // open bus +} diff --git a/src/devices/bus/nes/tengen.c b/src/devices/bus/nes/tengen.c deleted file mode 100644 index 555b0da3f35..00000000000 --- a/src/devices/bus/nes/tengen.c +++ /dev/null @@ -1,376 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Fabio Priuli -/*********************************************************************************************************** - - - NES/Famicom cartridge emulation for Tengen PCBs - - - Here we emulate the following PCBs - - * Tengen 800008 - * Tengen 800032 [mapper 64] - * Tengen 800037 [mapper 158] - - TODO: - - emulated the IRQ delay in 800032 (possibly reason of Skull & Crossbones not working?) - - ***********************************************************************************************************/ - - -#include "emu.h" -#include "tengen.h" - -#include "cpu/m6502/m6502.h" -#include "video/ppu2c0x.h" // this has to be included so that IRQ functions can access PPU_BOTTOM_VISIBLE_SCANLINE - - -#ifdef NES_PCB_DEBUG -#define VERBOSE 1 -#else -#define VERBOSE 0 -#endif - -#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) - - -//------------------------------------------------- -// constructor -//------------------------------------------------- - -const device_type NES_TENGEN_800008 = &device_creator; -const device_type NES_TENGEN_800032 = &device_creator; -const device_type NES_TENGEN_800037 = &device_creator; - - -nes_tengen008_device::nes_tengen008_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_TENGEN_800008, "NES Cart Tengen 800008 PCB", tag, owner, clock, "nes_tengen008", __FILE__) -{ -} - -nes_tengen032_device::nes_tengen032_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) - : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source) -{ -} - -nes_tengen032_device::nes_tengen032_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_TENGEN_800032, "NES Cart Tengen 800032 PCB", tag, owner, clock, "nes_tengen032", __FILE__) -{ -} - -nes_tengen037_device::nes_tengen037_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_tengen032_device(mconfig, NES_TENGEN_800037, "NES Cart Tengen 800037 PCB", tag, owner, clock, "nes_tengen037", __FILE__) -{ -} - - - - -void nes_tengen008_device::device_start() -{ - common_start(); -} - -void nes_tengen008_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0); - chr8(0, m_chr_source); -} - -void nes_tengen032_device::device_start() -{ - common_start(); - irq_timer = timer_alloc(TIMER_IRQ); - irq_timer->reset(); - timer_freq = machine().device("maincpu")->cycles_to_attotime(4); - - save_item(NAME(m_mmc_prg_bank)); - save_item(NAME(m_mmc_vrom_bank)); - save_item(NAME(m_latch)); - - save_item(NAME(m_irq_mode)); - save_item(NAME(m_irq_reset)); - save_item(NAME(m_irq_enable)); - save_item(NAME(m_irq_count)); - save_item(NAME(m_irq_count_latch)); -} - -void nes_tengen032_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(m_prg_chunks - 1); - prg16_cdef(m_prg_chunks - 1); - chr8(0, m_chr_source); - memset(m_mmc_prg_bank, 0, sizeof(m_mmc_prg_bank)); - memset(m_mmc_vrom_bank, 0, sizeof(m_mmc_vrom_bank)); - - m_latch = 0; - m_irq_mode = 0; - m_irq_reset = 0; - m_irq_enable = 0; - m_irq_count = m_irq_count_latch = 0; -} - - -/*------------------------------------------------- - mapper specific handlers - -------------------------------------------------*/ - -/*------------------------------------------------- - - Tengen 800008 Board - - iNES: mapper 3? - - In MESS: Supported. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_tengen008_device::write_h) -{ - LOG_MMC(("tengen008 write_h, offset: %04x, data: %02x\n", offset, data)); - - // this pcb is subject to bus conflict - data = account_bus_conflict(offset, data); - - prg32(data >> 3); - chr8(data, CHRROM); -} - -/*------------------------------------------------- - - Tengen 800032 Board - - Games: Klax, Road Runner, Rolling Thunder, Shinobi, Skulls - & Crossbones, Xybots - - This is very similar to MMC-3 (or more probably to the - Namcot predecessor of MMC-3), but with more registers - and with an alternative IRQ mode - - iNES: mapper 64 - - In MESS: Partially Supported (there should be a small - delay between the IRQ and its execution, but that is not - emulated yet: this is possibly the problem with Skulls - & Crossbones) - - -------------------------------------------------*/ - -inline void nes_tengen032_device::irq_clock(int blanked) -{ - // From NESdev wiki: Regardless of the mode used to clock the counter, every time the counter is clocked, - // the following actions occur: - // - If Reset reg ($C001) was written to after previous clock, reload IRQ counter with IRQ Reload + 1 - // - Otherwise, if IRQ Counter is 0, reload IRQ counter with IRQ Reload value - // - Otherwise, first decrement IRQ counter by 1, then if IRQ counter is now 0 and IRQs are enabled, - // trigger IRQ - if (m_irq_reset) - { - m_irq_reset = 0; - m_irq_count = m_irq_count_latch + 1; - } - else if (!m_irq_count) - m_irq_count = m_irq_count_latch; - - m_irq_count--; - if (m_irq_enable && !blanked && !m_irq_count) - m_maincpu->set_input_line(M6502_IRQ_LINE, ASSERT_LINE); -} - -// we use the HBLANK IRQ latch from PPU for the scanline based IRQ mode -// and a timer for the cycle based IRQ mode, which both call irq_clock - -void nes_tengen032_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) -{ - if (id == TIMER_IRQ) - { - irq_clock(0); - } -} - - -void nes_tengen032_device::hblank_irq(int scanline, int vblank, int blanked) -{ - if (!m_irq_mode) // we are in scanline mode! - { - if (scanline < PPU_BOTTOM_VISIBLE_SCANLINE) - { - irq_clock(blanked); - } - } -} - -void nes_tengen032_device::set_prg() -{ - UINT8 prg_mode = m_latch & 0x40; - - prg8_89(m_mmc_prg_bank[prg_mode ? 2: 0]); - prg8_ab(m_mmc_prg_bank[prg_mode ? 0: 1]); - prg8_cd(m_mmc_prg_bank[prg_mode ? 1: 2]); -} - -void nes_tengen032_device::chr_cb(int start, int bank, int source) -{ - chr1_x(start, bank, source); -} - -void nes_tengen032_device::set_chr() -{ - UINT8 chr_page = (m_latch & 0x80) >> 5; - - if (m_latch & 0x20) - { - chr_cb(0 ^ chr_page, m_mmc_vrom_bank[0], CHRROM); - chr_cb(1 ^ chr_page, m_mmc_vrom_bank[6], CHRROM); - chr_cb(2 ^ chr_page, m_mmc_vrom_bank[1], CHRROM); - chr_cb(3 ^ chr_page, m_mmc_vrom_bank[7], CHRROM); - } - else - { - chr_cb(0 ^ chr_page, m_mmc_vrom_bank[0] & ~0x01, CHRROM); - chr_cb(1 ^ chr_page, m_mmc_vrom_bank[0] | 0x01, CHRROM); - chr_cb(2 ^ chr_page, m_mmc_vrom_bank[1] & ~0x01, CHRROM); - chr_cb(3 ^ chr_page, m_mmc_vrom_bank[1] | 0x01, CHRROM); - } - - chr_cb(4 ^ chr_page, m_mmc_vrom_bank[2], CHRROM); - chr_cb(5 ^ chr_page, m_mmc_vrom_bank[3], CHRROM); - chr_cb(6 ^ chr_page, m_mmc_vrom_bank[4], CHRROM); - chr_cb(7 ^ chr_page, m_mmc_vrom_bank[5], CHRROM); -} - -WRITE8_MEMBER(nes_tengen032_device::tengen032_write) -{ - UINT8 helper, cmd; - LOG_MMC(("tengen032_write, offset: %04x, data: %02x\n", offset, data)); - - switch (offset & 0x6001) - { - case 0x0000: - helper = m_latch ^ data; - m_latch = data; - - // Has PRG Mode changed? - if (helper & 0x40) - set_prg(); - - // Has CHR Mode changed? - if (helper & 0xa0) - set_chr(); - break; - - case 0x0001: - cmd = m_latch & 0x0f; - switch (cmd) - { - case 0: case 1: - case 2: case 3: - case 4: case 5: - m_mmc_vrom_bank[cmd] = data; - set_chr(); - break; - case 6: case 7: - m_mmc_prg_bank[cmd - 6] = data; - set_prg(); - break; - case 8: case 9: - m_mmc_vrom_bank[cmd - 2] = data; - set_chr(); - break; - case 0x0f: - m_mmc_prg_bank[2] = data; - set_prg(); - break; - } - break; - - case 0x2000: - set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); - break; - - case 0x4000: - m_irq_count_latch = data; - break; - - case 0x4001: /* $c001 - IRQ scanline latch */ - m_irq_mode = data & 0x01; - if (m_irq_mode) - irq_timer->adjust(attotime::zero, 0, timer_freq); - else - irq_timer->adjust(attotime::never); - m_irq_reset = 1; - break; - - case 0x6000: - m_irq_enable = 0; - m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); - break; - - case 0x6001: - m_irq_enable = 1; - break; - - default: - LOG_MMC(("Tengen 800032 write. addr: %04x value: %02x\n", offset + 0x8000, data)); - break; - } -} - -/*------------------------------------------------- - - Tengen 800037 Board - - Games: Alien Syndrome - - Same as above (mapper chip RAMBO-1) but CHR A17 output - is connected to CIRAM A10, so this differs from 800032 - exactly in the same way as TLSROM differs from plain - MMC-3 - - iNES: mapper 158 - - In MESS: Supported. - - -------------------------------------------------*/ - -void nes_tengen037_device::set_mirror() -{ - if (m_latch & 0x80) - { - set_nt_page(0, CIRAM, BIT(m_mmc_vrom_bank[2],7), 1); - set_nt_page(1, CIRAM, BIT(m_mmc_vrom_bank[3],7), 1); - set_nt_page(2, CIRAM, BIT(m_mmc_vrom_bank[4],7), 1); - set_nt_page(3, CIRAM, BIT(m_mmc_vrom_bank[5],7), 1); - } - else - { - set_nt_page(0, CIRAM, BIT(m_mmc_vrom_bank[0],7), 1); - set_nt_page(1, CIRAM, BIT(m_mmc_vrom_bank[0],7), 1); - set_nt_page(2, CIRAM, BIT(m_mmc_vrom_bank[1],7), 1); - set_nt_page(3, CIRAM, BIT(m_mmc_vrom_bank[1],7), 1); - } -} - -void nes_tengen037_device::chr_cb( int start, int bank, int source ) -{ - set_mirror(); // we could probably update only for one (e.g. the first) call, to slightly optimize the code - chr1_x(start, bank, source); -} - - -WRITE8_MEMBER(nes_tengen037_device::write_h) -{ - LOG_MMC(("tengen037 write_h, offset: %04x, data: %02x\n", offset, data)); - - switch (offset & 0x6001) - { - case 0x2000: - break; - - default: - tengen032_write(space, offset, data, mem_mask); - break; - } -} diff --git a/src/devices/bus/nes/tengen.cpp b/src/devices/bus/nes/tengen.cpp new file mode 100644 index 00000000000..555b0da3f35 --- /dev/null +++ b/src/devices/bus/nes/tengen.cpp @@ -0,0 +1,376 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for Tengen PCBs + + + Here we emulate the following PCBs + + * Tengen 800008 + * Tengen 800032 [mapper 64] + * Tengen 800037 [mapper 158] + + TODO: + - emulated the IRQ delay in 800032 (possibly reason of Skull & Crossbones not working?) + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "tengen.h" + +#include "cpu/m6502/m6502.h" +#include "video/ppu2c0x.h" // this has to be included so that IRQ functions can access PPU_BOTTOM_VISIBLE_SCANLINE + + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_TENGEN_800008 = &device_creator; +const device_type NES_TENGEN_800032 = &device_creator; +const device_type NES_TENGEN_800037 = &device_creator; + + +nes_tengen008_device::nes_tengen008_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_TENGEN_800008, "NES Cart Tengen 800008 PCB", tag, owner, clock, "nes_tengen008", __FILE__) +{ +} + +nes_tengen032_device::nes_tengen032_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +nes_tengen032_device::nes_tengen032_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_TENGEN_800032, "NES Cart Tengen 800032 PCB", tag, owner, clock, "nes_tengen032", __FILE__) +{ +} + +nes_tengen037_device::nes_tengen037_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_tengen032_device(mconfig, NES_TENGEN_800037, "NES Cart Tengen 800037 PCB", tag, owner, clock, "nes_tengen037", __FILE__) +{ +} + + + + +void nes_tengen008_device::device_start() +{ + common_start(); +} + +void nes_tengen008_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + +void nes_tengen032_device::device_start() +{ + common_start(); + irq_timer = timer_alloc(TIMER_IRQ); + irq_timer->reset(); + timer_freq = machine().device("maincpu")->cycles_to_attotime(4); + + save_item(NAME(m_mmc_prg_bank)); + save_item(NAME(m_mmc_vrom_bank)); + save_item(NAME(m_latch)); + + save_item(NAME(m_irq_mode)); + save_item(NAME(m_irq_reset)); + save_item(NAME(m_irq_enable)); + save_item(NAME(m_irq_count)); + save_item(NAME(m_irq_count_latch)); +} + +void nes_tengen032_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(m_prg_chunks - 1); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + memset(m_mmc_prg_bank, 0, sizeof(m_mmc_prg_bank)); + memset(m_mmc_vrom_bank, 0, sizeof(m_mmc_vrom_bank)); + + m_latch = 0; + m_irq_mode = 0; + m_irq_reset = 0; + m_irq_enable = 0; + m_irq_count = m_irq_count_latch = 0; +} + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + Tengen 800008 Board + + iNES: mapper 3? + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_tengen008_device::write_h) +{ + LOG_MMC(("tengen008 write_h, offset: %04x, data: %02x\n", offset, data)); + + // this pcb is subject to bus conflict + data = account_bus_conflict(offset, data); + + prg32(data >> 3); + chr8(data, CHRROM); +} + +/*------------------------------------------------- + + Tengen 800032 Board + + Games: Klax, Road Runner, Rolling Thunder, Shinobi, Skulls + & Crossbones, Xybots + + This is very similar to MMC-3 (or more probably to the + Namcot predecessor of MMC-3), but with more registers + and with an alternative IRQ mode + + iNES: mapper 64 + + In MESS: Partially Supported (there should be a small + delay between the IRQ and its execution, but that is not + emulated yet: this is possibly the problem with Skulls + & Crossbones) + + -------------------------------------------------*/ + +inline void nes_tengen032_device::irq_clock(int blanked) +{ + // From NESdev wiki: Regardless of the mode used to clock the counter, every time the counter is clocked, + // the following actions occur: + // - If Reset reg ($C001) was written to after previous clock, reload IRQ counter with IRQ Reload + 1 + // - Otherwise, if IRQ Counter is 0, reload IRQ counter with IRQ Reload value + // - Otherwise, first decrement IRQ counter by 1, then if IRQ counter is now 0 and IRQs are enabled, + // trigger IRQ + if (m_irq_reset) + { + m_irq_reset = 0; + m_irq_count = m_irq_count_latch + 1; + } + else if (!m_irq_count) + m_irq_count = m_irq_count_latch; + + m_irq_count--; + if (m_irq_enable && !blanked && !m_irq_count) + m_maincpu->set_input_line(M6502_IRQ_LINE, ASSERT_LINE); +} + +// we use the HBLANK IRQ latch from PPU for the scanline based IRQ mode +// and a timer for the cycle based IRQ mode, which both call irq_clock + +void nes_tengen032_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (id == TIMER_IRQ) + { + irq_clock(0); + } +} + + +void nes_tengen032_device::hblank_irq(int scanline, int vblank, int blanked) +{ + if (!m_irq_mode) // we are in scanline mode! + { + if (scanline < PPU_BOTTOM_VISIBLE_SCANLINE) + { + irq_clock(blanked); + } + } +} + +void nes_tengen032_device::set_prg() +{ + UINT8 prg_mode = m_latch & 0x40; + + prg8_89(m_mmc_prg_bank[prg_mode ? 2: 0]); + prg8_ab(m_mmc_prg_bank[prg_mode ? 0: 1]); + prg8_cd(m_mmc_prg_bank[prg_mode ? 1: 2]); +} + +void nes_tengen032_device::chr_cb(int start, int bank, int source) +{ + chr1_x(start, bank, source); +} + +void nes_tengen032_device::set_chr() +{ + UINT8 chr_page = (m_latch & 0x80) >> 5; + + if (m_latch & 0x20) + { + chr_cb(0 ^ chr_page, m_mmc_vrom_bank[0], CHRROM); + chr_cb(1 ^ chr_page, m_mmc_vrom_bank[6], CHRROM); + chr_cb(2 ^ chr_page, m_mmc_vrom_bank[1], CHRROM); + chr_cb(3 ^ chr_page, m_mmc_vrom_bank[7], CHRROM); + } + else + { + chr_cb(0 ^ chr_page, m_mmc_vrom_bank[0] & ~0x01, CHRROM); + chr_cb(1 ^ chr_page, m_mmc_vrom_bank[0] | 0x01, CHRROM); + chr_cb(2 ^ chr_page, m_mmc_vrom_bank[1] & ~0x01, CHRROM); + chr_cb(3 ^ chr_page, m_mmc_vrom_bank[1] | 0x01, CHRROM); + } + + chr_cb(4 ^ chr_page, m_mmc_vrom_bank[2], CHRROM); + chr_cb(5 ^ chr_page, m_mmc_vrom_bank[3], CHRROM); + chr_cb(6 ^ chr_page, m_mmc_vrom_bank[4], CHRROM); + chr_cb(7 ^ chr_page, m_mmc_vrom_bank[5], CHRROM); +} + +WRITE8_MEMBER(nes_tengen032_device::tengen032_write) +{ + UINT8 helper, cmd; + LOG_MMC(("tengen032_write, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x6001) + { + case 0x0000: + helper = m_latch ^ data; + m_latch = data; + + // Has PRG Mode changed? + if (helper & 0x40) + set_prg(); + + // Has CHR Mode changed? + if (helper & 0xa0) + set_chr(); + break; + + case 0x0001: + cmd = m_latch & 0x0f; + switch (cmd) + { + case 0: case 1: + case 2: case 3: + case 4: case 5: + m_mmc_vrom_bank[cmd] = data; + set_chr(); + break; + case 6: case 7: + m_mmc_prg_bank[cmd - 6] = data; + set_prg(); + break; + case 8: case 9: + m_mmc_vrom_bank[cmd - 2] = data; + set_chr(); + break; + case 0x0f: + m_mmc_prg_bank[2] = data; + set_prg(); + break; + } + break; + + case 0x2000: + set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + break; + + case 0x4000: + m_irq_count_latch = data; + break; + + case 0x4001: /* $c001 - IRQ scanline latch */ + m_irq_mode = data & 0x01; + if (m_irq_mode) + irq_timer->adjust(attotime::zero, 0, timer_freq); + else + irq_timer->adjust(attotime::never); + m_irq_reset = 1; + break; + + case 0x6000: + m_irq_enable = 0; + m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); + break; + + case 0x6001: + m_irq_enable = 1; + break; + + default: + LOG_MMC(("Tengen 800032 write. addr: %04x value: %02x\n", offset + 0x8000, data)); + break; + } +} + +/*------------------------------------------------- + + Tengen 800037 Board + + Games: Alien Syndrome + + Same as above (mapper chip RAMBO-1) but CHR A17 output + is connected to CIRAM A10, so this differs from 800032 + exactly in the same way as TLSROM differs from plain + MMC-3 + + iNES: mapper 158 + + In MESS: Supported. + + -------------------------------------------------*/ + +void nes_tengen037_device::set_mirror() +{ + if (m_latch & 0x80) + { + set_nt_page(0, CIRAM, BIT(m_mmc_vrom_bank[2],7), 1); + set_nt_page(1, CIRAM, BIT(m_mmc_vrom_bank[3],7), 1); + set_nt_page(2, CIRAM, BIT(m_mmc_vrom_bank[4],7), 1); + set_nt_page(3, CIRAM, BIT(m_mmc_vrom_bank[5],7), 1); + } + else + { + set_nt_page(0, CIRAM, BIT(m_mmc_vrom_bank[0],7), 1); + set_nt_page(1, CIRAM, BIT(m_mmc_vrom_bank[0],7), 1); + set_nt_page(2, CIRAM, BIT(m_mmc_vrom_bank[1],7), 1); + set_nt_page(3, CIRAM, BIT(m_mmc_vrom_bank[1],7), 1); + } +} + +void nes_tengen037_device::chr_cb( int start, int bank, int source ) +{ + set_mirror(); // we could probably update only for one (e.g. the first) call, to slightly optimize the code + chr1_x(start, bank, source); +} + + +WRITE8_MEMBER(nes_tengen037_device::write_h) +{ + LOG_MMC(("tengen037 write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x6001) + { + case 0x2000: + break; + + default: + tengen032_write(space, offset, data, mem_mask); + break; + } +} diff --git a/src/devices/bus/nes/txc.c b/src/devices/bus/nes/txc.c deleted file mode 100644 index ae36ece75ee..00000000000 --- a/src/devices/bus/nes/txc.c +++ /dev/null @@ -1,268 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Fabio Priuli -/*********************************************************************************************************** - - - NES/Famicom cartridge emulation for TXC PCBs - - Here we emulate the following PCBs - - * TXC 22111 [mapper 132] - * TXC Du Ma Racing [mapper 172] - * TXC Mahjong Block [mapper 172] - * TXC Strike Wolf [mapper 36] - * TXC Commandos (and many more) [mapper 241] - - TODO: - - Does Commandos indeed use this board? - - - ***********************************************************************************************************/ - - -#include "emu.h" -#include "txc.h" - - -#ifdef NES_PCB_DEBUG -#define VERBOSE 1 -#else -#define VERBOSE 0 -#endif - -#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) - - -//------------------------------------------------- -// constructor -//------------------------------------------------- - -const device_type NES_TXC_22211 = &device_creator; -const device_type NES_TXC_DUMARACING = &device_creator; -const device_type NES_TXC_MJBLOCK = &device_creator; -const device_type NES_TXC_STRIKEW = &device_creator; -const device_type NES_TXC_COMMANDOS = &device_creator; - - -nes_txc_22211_device::nes_txc_22211_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) - : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source) -{ -} - -nes_txc_22211_device::nes_txc_22211_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_TXC_22211, "NES Cart TXC 22211 PCB", tag, owner, clock, "nes_txc_22211", __FILE__) -{ -} - -nes_txc_dumarc_device::nes_txc_dumarc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_txc_22211_device(mconfig, NES_TXC_DUMARACING, "NES Cart TXC Du Ma Racing PCB", tag, owner, clock, "nes_dumarc", __FILE__) -{ -} - -nes_txc_mjblock_device::nes_txc_mjblock_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_txc_22211_device(mconfig, NES_TXC_MJBLOCK, "NES Cart TXC Mahjong Block PCB", tag, owner, clock, "nes_mjblock", __FILE__) -{ -} - -nes_txc_strikew_device::nes_txc_strikew_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_TXC_STRIKEW, "NES Cart Strike Wolf PCB", tag, owner, clock, "nes_txc_strikew", __FILE__) -{ -} - -nes_txc_commandos_device::nes_txc_commandos_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_TXC_COMMANDOS, "NES Cart Commandos (and others) PCB", tag, owner, clock, "nes_txc_comm", __FILE__) -{ -} - - - - -void nes_txc_22211_device::device_start() -{ - common_start(); - save_item(NAME(m_reg)); -} - -void nes_txc_22211_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0); - chr8(0, m_chr_source); - m_reg[0] = m_reg[1] = m_reg[2] = m_reg[3] = 0; -} - -void nes_txc_strikew_device::device_start() -{ - common_start(); -} - -void nes_txc_strikew_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0); - chr8(0, m_chr_source); -} - -void nes_txc_commandos_device::device_start() -{ - common_start(); -} - -void nes_txc_commandos_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0); - chr8(0, m_chr_source); -} - - - - - -/*------------------------------------------------- - mapper specific handlers - -------------------------------------------------*/ - -/*------------------------------------------------- - - Bootleg Board 22211 by TXC (Type A) - - Games: Creatom - - Info from NEStopia: this mapper features write to four - registers (0x4100-0x4103). The third one is used to select - PRG and CHR banks. - - iNES: mapper 132 - - In MESS: Supported. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_txc_22211_device::write_l) -{ - LOG_MMC(("TXC 22111 write_l, offset: %04x, data: %02x\n", offset, data)); - - if (offset < 4) - m_reg[offset & 0x03] = data; -} - -READ8_MEMBER(nes_txc_22211_device::read_l) -{ - LOG_MMC(("TXC 22111 read_l, offset: %04x\n", offset)); - - if (offset == 0x0000) - return (m_reg[1] ^ m_reg[2]) | 0x40; - else - return 0x00; -} - -WRITE8_MEMBER(nes_txc_22211_device::write_h) -{ - LOG_MMC(("TXC 22111 write_h, offset: %04x, data: %02x\n", offset, data)); - - prg32(m_reg[2] >> 2); - chr8(m_reg[2], CHRROM); -} - -/*------------------------------------------------- - - Bootleg Board 22211 by TXC (Type B) - - Games: 1991 Du Ma Racing - - This mapper is basically the same as Type A. Only difference is - in the way CHR banks are selected (see below) - - iNES: mapper 172 - - In MESS: Supported. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_txc_dumarc_device::write_h) -{ - LOG_MMC(("TXC Du Ma Racing write_h, offset: %04x, data: %02x\n", offset, data)); - - prg32(m_reg[2] >> 2); - chr8((((data ^ m_reg[2]) >> 3) & 0x02) | (((data ^ m_reg[2]) >> 5) & 0x01), CHRROM); -} - -/*------------------------------------------------- - - Bootleg Board 22211 by TXC (Type C) - - Games: Mahjong Block, Xiao Ma Li - - This mapper is basically the same as 132 too. Only difference is - in 0x4100 reads which expect also bit 0 to be set - - iNES: mapper 172 - - In MESS: Supported. - - -------------------------------------------------*/ - -READ8_MEMBER(nes_txc_mjblock_device::read_l) -{ - LOG_MMC(("TXC mjblock read_l, offset: %04x\n", offset)); - - if (offset == 0x0000) - return (m_reg[1] ^ m_reg[2]) | 0x41; - else - return 0x00; -} - -/*------------------------------------------------- - - Bootleg Board 'Strike Wolf' by TXC - - Games: Strike Wolf and Policeman - - iNES: mapper 36 - - In MESS: Partially Supported (Policeman has glitches) - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_txc_strikew_device::write_h) -{ - LOG_MMC(("TXC Strike Wolf write_h, offset: %04x, data: %02x\n", offset, data)); - - // this pcb is subject to bus conflict - data = account_bus_conflict(offset, data); - - if ((offset >= 0x400) && (offset < 0x7fff)) - { - prg32(data >> 4); - chr8(data & 0x0f, CHRROM); - } -} - -/*------------------------------------------------- - - Bootleg Board MXMDHTWO by TXC - - Games: Commandos, Journey to the West, Ma Bu Mi Zhen & - Qu Wei Cheng Yu Wu, Si Lu Chuan Qi - - Simple Mapper: writes to 0x8000-0xffff sets the prg32 bank. - Not sure if returning 0x50 for reads in 0x4100-0x5000 is correct. - - iNES: mapper 241 - - In MESS: Supported. - - -------------------------------------------------*/ - -READ8_MEMBER(nes_txc_commandos_device::read_l) -{ - return 0x50; -} - -WRITE8_MEMBER(nes_txc_commandos_device::write_h) -{ - LOG_MMC(("TXC Commandos write_h, offset: %04x, data: %02x\n", offset, data)); - - prg32(data); -} diff --git a/src/devices/bus/nes/txc.cpp b/src/devices/bus/nes/txc.cpp new file mode 100644 index 00000000000..ae36ece75ee --- /dev/null +++ b/src/devices/bus/nes/txc.cpp @@ -0,0 +1,268 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for TXC PCBs + + Here we emulate the following PCBs + + * TXC 22111 [mapper 132] + * TXC Du Ma Racing [mapper 172] + * TXC Mahjong Block [mapper 172] + * TXC Strike Wolf [mapper 36] + * TXC Commandos (and many more) [mapper 241] + + TODO: + - Does Commandos indeed use this board? + + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "txc.h" + + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_TXC_22211 = &device_creator; +const device_type NES_TXC_DUMARACING = &device_creator; +const device_type NES_TXC_MJBLOCK = &device_creator; +const device_type NES_TXC_STRIKEW = &device_creator; +const device_type NES_TXC_COMMANDOS = &device_creator; + + +nes_txc_22211_device::nes_txc_22211_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +nes_txc_22211_device::nes_txc_22211_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_TXC_22211, "NES Cart TXC 22211 PCB", tag, owner, clock, "nes_txc_22211", __FILE__) +{ +} + +nes_txc_dumarc_device::nes_txc_dumarc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txc_22211_device(mconfig, NES_TXC_DUMARACING, "NES Cart TXC Du Ma Racing PCB", tag, owner, clock, "nes_dumarc", __FILE__) +{ +} + +nes_txc_mjblock_device::nes_txc_mjblock_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txc_22211_device(mconfig, NES_TXC_MJBLOCK, "NES Cart TXC Mahjong Block PCB", tag, owner, clock, "nes_mjblock", __FILE__) +{ +} + +nes_txc_strikew_device::nes_txc_strikew_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_TXC_STRIKEW, "NES Cart Strike Wolf PCB", tag, owner, clock, "nes_txc_strikew", __FILE__) +{ +} + +nes_txc_commandos_device::nes_txc_commandos_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_TXC_COMMANDOS, "NES Cart Commandos (and others) PCB", tag, owner, clock, "nes_txc_comm", __FILE__) +{ +} + + + + +void nes_txc_22211_device::device_start() +{ + common_start(); + save_item(NAME(m_reg)); +} + +void nes_txc_22211_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); + m_reg[0] = m_reg[1] = m_reg[2] = m_reg[3] = 0; +} + +void nes_txc_strikew_device::device_start() +{ + common_start(); +} + +void nes_txc_strikew_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + +void nes_txc_commandos_device::device_start() +{ + common_start(); +} + +void nes_txc_commandos_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + + + + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + Bootleg Board 22211 by TXC (Type A) + + Games: Creatom + + Info from NEStopia: this mapper features write to four + registers (0x4100-0x4103). The third one is used to select + PRG and CHR banks. + + iNES: mapper 132 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_txc_22211_device::write_l) +{ + LOG_MMC(("TXC 22111 write_l, offset: %04x, data: %02x\n", offset, data)); + + if (offset < 4) + m_reg[offset & 0x03] = data; +} + +READ8_MEMBER(nes_txc_22211_device::read_l) +{ + LOG_MMC(("TXC 22111 read_l, offset: %04x\n", offset)); + + if (offset == 0x0000) + return (m_reg[1] ^ m_reg[2]) | 0x40; + else + return 0x00; +} + +WRITE8_MEMBER(nes_txc_22211_device::write_h) +{ + LOG_MMC(("TXC 22111 write_h, offset: %04x, data: %02x\n", offset, data)); + + prg32(m_reg[2] >> 2); + chr8(m_reg[2], CHRROM); +} + +/*------------------------------------------------- + + Bootleg Board 22211 by TXC (Type B) + + Games: 1991 Du Ma Racing + + This mapper is basically the same as Type A. Only difference is + in the way CHR banks are selected (see below) + + iNES: mapper 172 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_txc_dumarc_device::write_h) +{ + LOG_MMC(("TXC Du Ma Racing write_h, offset: %04x, data: %02x\n", offset, data)); + + prg32(m_reg[2] >> 2); + chr8((((data ^ m_reg[2]) >> 3) & 0x02) | (((data ^ m_reg[2]) >> 5) & 0x01), CHRROM); +} + +/*------------------------------------------------- + + Bootleg Board 22211 by TXC (Type C) + + Games: Mahjong Block, Xiao Ma Li + + This mapper is basically the same as 132 too. Only difference is + in 0x4100 reads which expect also bit 0 to be set + + iNES: mapper 172 + + In MESS: Supported. + + -------------------------------------------------*/ + +READ8_MEMBER(nes_txc_mjblock_device::read_l) +{ + LOG_MMC(("TXC mjblock read_l, offset: %04x\n", offset)); + + if (offset == 0x0000) + return (m_reg[1] ^ m_reg[2]) | 0x41; + else + return 0x00; +} + +/*------------------------------------------------- + + Bootleg Board 'Strike Wolf' by TXC + + Games: Strike Wolf and Policeman + + iNES: mapper 36 + + In MESS: Partially Supported (Policeman has glitches) + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_txc_strikew_device::write_h) +{ + LOG_MMC(("TXC Strike Wolf write_h, offset: %04x, data: %02x\n", offset, data)); + + // this pcb is subject to bus conflict + data = account_bus_conflict(offset, data); + + if ((offset >= 0x400) && (offset < 0x7fff)) + { + prg32(data >> 4); + chr8(data & 0x0f, CHRROM); + } +} + +/*------------------------------------------------- + + Bootleg Board MXMDHTWO by TXC + + Games: Commandos, Journey to the West, Ma Bu Mi Zhen & + Qu Wei Cheng Yu Wu, Si Lu Chuan Qi + + Simple Mapper: writes to 0x8000-0xffff sets the prg32 bank. + Not sure if returning 0x50 for reads in 0x4100-0x5000 is correct. + + iNES: mapper 241 + + In MESS: Supported. + + -------------------------------------------------*/ + +READ8_MEMBER(nes_txc_commandos_device::read_l) +{ + return 0x50; +} + +WRITE8_MEMBER(nes_txc_commandos_device::write_h) +{ + LOG_MMC(("TXC Commandos write_h, offset: %04x, data: %02x\n", offset, data)); + + prg32(data); +} diff --git a/src/devices/bus/nes/waixing.c b/src/devices/bus/nes/waixing.c deleted file mode 100644 index 8a223a8e295..00000000000 --- a/src/devices/bus/nes/waixing.c +++ /dev/null @@ -1,1244 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Fabio Priuli -/*********************************************************************************************************** - - - NES/Famicom cartridge emulation for Waixing PCBs - - Here we emulate the various PCBs used by Waixing for its games - - TODO: - - investigate the PPU issues causing some games not to have sprites (e.g. some games using mappers 15, 164, - 242, 249) - - ***********************************************************************************************************/ - - -#include "emu.h" -#include "waixing.h" - -#include "cpu/m6502/m6502.h" - - -#ifdef NES_PCB_DEBUG -#define VERBOSE 1 -#else -#define VERBOSE 0 -#endif - -#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) - - -//------------------------------------------------- -// constructor -//------------------------------------------------- - -const device_type NES_WAIXING_A = &device_creator; -const device_type NES_WAIXING_A1 = &device_creator; -const device_type NES_WAIXING_B = &device_creator; -const device_type NES_WAIXING_C = &device_creator; -const device_type NES_WAIXING_D = &device_creator; -const device_type NES_WAIXING_E = &device_creator; -const device_type NES_WAIXING_F = &device_creator; -const device_type NES_WAIXING_G = &device_creator; -const device_type NES_WAIXING_H = &device_creator; -const device_type NES_WAIXING_H1 = &device_creator; -const device_type NES_WAIXING_I = &device_creator; -const device_type NES_WAIXING_J = &device_creator; -const device_type NES_WAIXING_SH2 = &device_creator; -const device_type NES_WAIXING_SEC = &device_creator; -const device_type NES_WAIXING_SGZ = &device_creator; -const device_type NES_WAIXING_SGZLZ = &device_creator; -const device_type NES_WAIXING_FFV = &device_creator; -const device_type NES_WAIXING_WXZS = &device_creator; -const device_type NES_WAIXING_DQ8 = &device_creator; -const device_type NES_WAIXING_WXZS2 = &device_creator; -const device_type NES_WAIXING_FS304 = &device_creator; - - -nes_waixing_a_device::nes_waixing_a_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) - : nes_txrom_device(mconfig, type, name, tag, owner, clock, shortname, source) -{ -} - -nes_waixing_a_device::nes_waixing_a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_txrom_device(mconfig, NES_WAIXING_A, "NES Cart Waixing Type A PCB", tag, owner, clock, "nes_waixing_a", __FILE__) -{ -} - -nes_waixing_a1_device::nes_waixing_a1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_waixing_a_device(mconfig, NES_WAIXING_A1, "NES Cart Waixing Type A (Alt) PCB", tag, owner, clock, "nes_waixing_a1", __FILE__) -{ -} - -nes_waixing_b_device::nes_waixing_b_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_waixing_a_device(mconfig, NES_WAIXING_B, "NES Cart Waixing Type B PCB", tag, owner, clock, "nes_waixing_b", __FILE__) -{ -} - -nes_waixing_c_device::nes_waixing_c_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_waixing_a_device(mconfig, NES_WAIXING_C, "NES Cart Waixing Type C PCB", tag, owner, clock, "nes_waixing_c", __FILE__) -{ -} - -nes_waixing_d_device::nes_waixing_d_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_waixing_a_device(mconfig, NES_WAIXING_D, "NES Cart Waixing Type D PCB", tag, owner, clock, "nes_waixing_d", __FILE__) -{ -} - -nes_waixing_e_device::nes_waixing_e_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_waixing_a_device(mconfig, NES_WAIXING_E, "NES Cart Waixing Type E PCB", tag, owner, clock, "nes_waixing_e", __FILE__) -{ -} - -nes_waixing_f_device::nes_waixing_f_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_waixing_a_device(mconfig, NES_WAIXING_F, "NES Cart Waixing Type F PCB", tag, owner, clock, "nes_waixing_f", __FILE__) -{ -} - -nes_waixing_g_device::nes_waixing_g_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_waixing_a_device(mconfig, NES_WAIXING_G, "NES Cart Waixing Type G PCB", tag, owner, clock, "nes_waixing_g", __FILE__) -{ -} - -nes_waixing_h_device::nes_waixing_h_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) - : nes_txrom_device(mconfig, type, name, tag, owner, clock, shortname, source) -{ -} - -nes_waixing_h_device::nes_waixing_h_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_txrom_device(mconfig, NES_WAIXING_H, "NES Cart Waixing Type H PCB", tag, owner, clock, "nes_waixing_h", __FILE__) -{ -} - -nes_waixing_h1_device::nes_waixing_h1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_waixing_h_device(mconfig, NES_WAIXING_H1, "NES Cart Waixing Type H (Alt) PCB", tag, owner, clock, "nes_waixing_h1", __FILE__) -{ -} - -nes_waixing_i_device::nes_waixing_i_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_waixing_a_device(mconfig, NES_WAIXING_I, "NES Cart Waixing Type I PCB", tag, owner, clock, "nes_waixing_i", __FILE__) -{ -} - -nes_waixing_j_device::nes_waixing_j_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_waixing_a_device(mconfig, NES_WAIXING_J, "NES Cart Waixing Type J PCB", tag, owner, clock, "nes_waixing_j", __FILE__) -{ -} - -nes_waixing_sh2_device::nes_waixing_sh2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_txrom_device(mconfig, NES_WAIXING_SH2, "NES Cart Waixing SH2 PCB", tag, owner, clock, "nes_waixing_sh2", __FILE__) -{ -} - -nes_waixing_sec_device::nes_waixing_sec_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_txrom_device(mconfig, NES_WAIXING_SEC, "NES Cart Waixing Security Chip PCB", tag, owner, clock, "nes_waixing_sec", __FILE__) -{ -} - -nes_waixing_sgz_device::nes_waixing_sgz_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_WAIXING_SGZ, "NES Cart Waixing San Guo Zhi PCB", tag, owner, clock, "nes_waixing_sgz", __FILE__) -{ -} - -nes_waixing_sgzlz_device::nes_waixing_sgzlz_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_WAIXING_SGZLZ, "NES Cart Waixing San Guo Zhong Lie Zhuan PCB", tag, owner, clock, "nes_waixing_sgzlz", __FILE__) -{ -} - -nes_waixing_ffv_device::nes_waixing_ffv_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_WAIXING_FFV, "NES Cart Waixing Final Fantasy V PCB", tag, owner, clock, "nes_waixing_ffv", __FILE__) -{ -} - -nes_waixing_wxzs_device::nes_waixing_wxzs_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_WAIXING_WXZS, "NES Cart Waixing Wai Xing Zhan Shi PCB", tag, owner, clock, "nes_waixing_wxzs", __FILE__) -{ -} - -nes_waixing_dq8_device::nes_waixing_dq8_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_WAIXING_DQ8, "NES Cart Waixing Dragon Quest VIII PCB", tag, owner, clock, "nes_waixing_dq8", __FILE__) -{ -} - -nes_waixing_wxzs2_device::nes_waixing_wxzs2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_WAIXING_WXZS2, "NES Cart Waixing Wai Xing Zhan Shi 2 PCB", tag, owner, clock, "nes_waixing_wxzs2", __FILE__) -{ -} - -nes_waixing_fs304_device::nes_waixing_fs304_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : nes_nrom_device(mconfig, NES_WAIXING_FS304, "NES Cart Waixing FS-304 PCB", tag, owner, clock, "nes_waixing_fs304", __FILE__) -{ -} - - -void nes_waixing_a_device::device_start() -{ - mmc3_start(); - save_item(NAME(mapper_ram)); -} - -void nes_waixing_a_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - mmc3_common_initialize(0xff, 0xff, 0); - - memset(mapper_ram, 0, sizeof(mapper_ram)); -} - -void nes_waixing_f_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - mmc3_common_initialize(0xff, 0xff, 0); - - memset(mapper_ram, 0, sizeof(mapper_ram)); - m_mmc_prg_bank[0] = 0x00; - m_mmc_prg_bank[1] = 0x01; - m_mmc_prg_bank[2] = 0x4e; - m_mmc_prg_bank[3] = 0x4f; - set_prg(m_prg_base, m_prg_mask); -} - -void nes_waixing_g_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - mmc3_common_initialize(0xff, 0xff, 0); - - memset(mapper_ram, 0, sizeof(mapper_ram)); - m_mmc_prg_bank[0] = 0x00; - m_mmc_prg_bank[1] = 0x01; - m_mmc_prg_bank[2] = 0x3e; - m_mmc_prg_bank[3] = 0x3f; - m_mmc_vrom_bank[0] = 0x00; - m_mmc_vrom_bank[1] = 0x02; - m_mmc_vrom_bank[2] = 0x04; - m_mmc_vrom_bank[3] = 0x05; - m_mmc_vrom_bank[4] = 0x06; - m_mmc_vrom_bank[5] = 0x07; - m_mmc_vrom_bank[6] = 0x01; - m_mmc_vrom_bank[7] = 0x03; - set_prg(m_prg_base, m_prg_mask); - set_chr(m_chr_source, m_chr_base, m_chr_mask); -} - -void nes_waixing_j_device::device_start() -{ - mmc3_start(); - save_item(NAME(m_reg)); -} - -void nes_waixing_j_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - - m_reg[0] = 0x01; - m_reg[1] = 0x02; - m_reg[2] = 0x7e; - m_reg[3] = 0x7f; - mmc3_common_initialize(0xff, 0xff, 0); - set_prg(m_prg_base, m_prg_mask); -} - -void nes_waixing_sh2_device::device_start() -{ - mmc3_start(); - save_item(NAME(m_reg)); -} - -void nes_waixing_sh2_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - - m_reg[0] = m_reg[1] = 0; - mmc3_common_initialize(0xff, 0xff, 0); -} - -void nes_waixing_sec_device::device_start() -{ - mmc3_start(); - save_item(NAME(m_reg)); -} - -void nes_waixing_sec_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - - m_reg = 0; - mmc3_common_initialize(0xff, 0xff, 0); -} - -void nes_waixing_sgz_device::device_start() -{ - common_start(); - save_item(NAME(m_irq_enable)); - save_item(NAME(m_irq_enable_latch)); - save_item(NAME(m_irq_count)); - save_item(NAME(m_irq_count_latch)); - save_item(NAME(m_mmc_vrom_bank)); -} - -void nes_waixing_sgz_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(0); - prg16_cdef(m_prg_chunks - 1); - chr8(0, m_chr_source); - - m_irq_enable = 0; - m_irq_enable_latch = 0; - m_irq_count = 0; - m_irq_count_latch = 0; - - memset(m_mmc_vrom_bank, 0, sizeof(m_mmc_vrom_bank)); -} - -void nes_waixing_sgzlz_device::device_start() -{ - common_start(); - save_item(NAME(m_latch)); -} - -void nes_waixing_sgzlz_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0); - chr8(0, m_chr_source); - - m_latch = 0; -} - -void nes_waixing_ffv_device::device_start() -{ - common_start(); - save_item(NAME(m_reg)); -} - -void nes_waixing_ffv_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(0); - prg16_cdef(0x1f); - chr8(0, m_chr_source); - - m_reg[0] = m_reg[1] = 0; -} - -void nes_waixing_wxzs_device::device_start() -{ - common_start(); -} - -void nes_waixing_wxzs_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0); - chr8(0, m_chr_source); -} - -void nes_waixing_dq8_device::device_start() -{ - common_start(); -} - -void nes_waixing_dq8_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0); - chr8(0, m_chr_source); -} - -void nes_waixing_wxzs2_device::device_start() -{ - common_start(); -} - -void nes_waixing_wxzs2_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0); - chr8(0, m_chr_source); - set_nt_mirroring(PPU_MIRROR_VERT); -} - -void nes_waixing_fs304_device::device_start() -{ - common_start(); - save_item(NAME(m_reg)); -} - -void nes_waixing_fs304_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0); - chr8(0, m_chr_source); - - memset(m_reg, 0x00, sizeof(m_reg)); -} - - - - - -/*------------------------------------------------- - mapper specific handlers - -------------------------------------------------*/ - -/*------------------------------------------------- - - Waixing Board Type A - - Games: Columbus - Ougon no Yoake (C), Ji Jia Zhan Shi, - Jia A Fung Yun, Wei Luo Chuan Qi - - This mapper is quite similar to MMC3, but with two differences: - mirroring is not the same, and when VROM banks 8,9 are accessed - they point to CHRRAM and not CHRROM. - - iNES: mapper 74 - - In MESS: Supported - - -------------------------------------------------*/ - -/* MIRROR_LOW and MIRROR_HIGH are swapped! */ -void nes_waixing_a_device::set_mirror(UINT8 nt) -{ - switch (nt) - { - case 0: - case 1: - set_nt_mirroring(nt ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); - break; - case 2: - set_nt_mirroring(PPU_MIRROR_LOW); - break; - case 3: - set_nt_mirroring(PPU_MIRROR_HIGH); - break; - default: - LOG_MMC(("Mapper set NT to invalid value %02x", nt)); - break; - } -} - -/* Luo Ke Ren X only works with this */ -void nes_waixing_a_device::chr_cb(int start, int bank, int source) -{ - int chr_src = (bank <= 9) ? CHRRAM : CHRROM; - chr1_x(start, bank, chr_src); -} - -/* Ji Jia Zhan Shi only works with this */ -void nes_waixing_a1_device::chr_cb(int start, int bank, int source) -{ - int chr_src = ((bank == 8) || (bank == 9)) ? CHRRAM : CHRROM; - chr1_x(start, bank, chr_src); -} - -WRITE8_MEMBER(nes_waixing_a_device::waixing_write) -{ - LOG_MMC(("waixing_write, offset: %04x, data: %02x\n", offset, data)); - - switch (offset & 0x6001) - { - case 0x2000: - set_mirror(data); //maybe data & 0x03? - break; - - case 0x2001: - break; - - default: - txrom_write(space, offset, data, mem_mask); - break; - } -} - -READ8_MEMBER(nes_waixing_a_device::read_l) -{ - LOG_MMC(("waixing read_l, offset: %04x\n", offset)); - offset += 0x100; - if (offset >= 0x1000 && offset < 0x1400) - return mapper_ram[offset & 0x3ff]; - else - return 0xff; -} - -WRITE8_MEMBER(nes_waixing_a_device::write_l) -{ - LOG_MMC(("waixing write_l, offset: %04x, data: %02x\n", offset, data)); - offset += 0x100; - if (offset >= 0x1000 && offset < 0x1400) - mapper_ram[offset & 0x3ff] = data; -} - - -/*------------------------------------------------- - - Waixing Board Type B - - Games: Sugoro Quest (C) - - MMC3 clone. This is a minor modification of Mapper 74, - in the sense that it is the same board except for the - CHRRAM pages. - - iNES: mapper 191 - - In MESS: Supported. - - -------------------------------------------------*/ - -void nes_waixing_b_device::chr_cb(int start, int bank, int source) -{ - int chr_src = BIT(bank, 7) ? CHRRAM : CHRROM; - chr1_x(start, bank, chr_src); -} - -/*------------------------------------------------- - - Waixing Board Type C - - Games: Ying Lie Qun Xia Zhuan, Young Chivalry - - MMC3 clone. This is a minor modification of Mapper 74, - in the sense that it is the same board except for the - CHRRAM pages. - - iNES: mapper 192 - - In MESS: Supported. - - -------------------------------------------------*/ - -void nes_waixing_c_device::chr_cb(int start, int bank, int source) -{ - int chr_src = ((bank == 0x08) || (bank == 0x09) || (bank == 0x0a) || (bank == 0x0b)) ? CHRRAM : CHRROM; - chr1_x(start, bank, chr_src); -} - -/*------------------------------------------------- - - Waixing Board Type D - - Games: Super Robot Taisen (C) - - MMC3 clone. This is a minor modification of Mapper 74, - in the sense that it is the same board except for the - CHRRAM pages. - - iNES: mapper 194 - - In MESS: Supported. - - -------------------------------------------------*/ - -void nes_waixing_d_device::chr_cb(int start, int bank, int source) -{ - int chr_src = (bank < 0x02) ? CHRRAM : CHRROM; - chr1_x(start, bank, chr_src); -} - -/*------------------------------------------------- - - Waixing Board Type E - - Games: Captain Tsubasa Vol. II (C), Chaos World, God - Slayer (C), Zu Qiu Xiao Jiang - - MMC3 clone. This is a minor modification of Mapper 74, - in the sense that it is the same board except for the - CHRRAM pages. - - iNES: mapper 195 - - In MESS: Supported. - - -------------------------------------------------*/ - -void nes_waixing_e_device::chr_cb(int start, int bank, int source) -{ - int chr_src = (bank < 0x04) ? CHRRAM : CHRROM; - chr1_x(start, bank, chr_src); -} - - -/*------------------------------------------------- - - Waixing Board Type F - - Games: Tenchi wo Kurau II (C) - - MMC3 clone. - - iNES: mapper 198 - - In MESS: Preliminary support. - - -------------------------------------------------*/ - -void nes_waixing_f_device::chr_cb(int start, int bank, int source) -{ - chr1_x(start, bank, CHRRAM); -} - -void nes_waixing_f_device::prg_cb(int start, int bank) -{ -// if (bank > 0x3f) -// bank = 0x40 | (bank & 0xf); - prg8_x(start, bank); -} - -void nes_waixing_f_device::set_prg( int prg_base, int prg_mask ) -{ - UINT8 prg_flip = (m_latch & 0x40) ? 2 : 0; - - prg_cb(0, m_mmc_prg_bank[0 ^ prg_flip]); - prg_cb(1, m_mmc_prg_bank[1]); - prg_cb(2, m_mmc_prg_bank[2 ^ prg_flip]); - prg_cb(3, m_mmc_prg_bank[3]); -} - -WRITE8_MEMBER(nes_waixing_f_device::write_h) -{ - UINT8 cmd; - LOG_MMC(("waixing_f write_h, offset: %04x, data: %02x\n", offset, data)); - - switch (offset & 0x6001) - { - case 0x0001: - cmd = m_latch & 0x07; - switch (cmd) - { - case 0: case 1: // these do not need to be separated: we take care of them in set_chr! - case 2: case 3: case 4: case 5: - m_mmc_vrom_bank[cmd] = data; - set_chr(m_chr_source, m_chr_base, m_chr_mask); - break; - case 6: - case 7: - case 8: - case 9: - m_mmc_prg_bank[cmd - 6] = data; - //printf("prg bank %d value %x\n", cmd - 6, data); - set_prg(m_prg_base, m_prg_mask); - break; - } - break; - - case 0x2001: - break; - - default: - waixing_write(space, offset, data, mem_mask); - break; - } -} - -/*------------------------------------------------- - - Waixing Board Type G - - Games: San Guo Zhi 2, Dragon Ball Z Gaiden (C), Dragon - Ball Z II (C) - - MMC3 clone, capable of switching all 4 PRG banks - - iNES: mapper 199 - - In MESS: Supported. - - -------------------------------------------------*/ - -void nes_waixing_g_device::chr_cb(int start, int bank, int source) -{ - int chr_src = (bank < 0x08) ? CHRRAM : CHRROM; - chr1_x(start, bank, chr_src); -} - -void nes_waixing_g_device::set_chr(UINT8 chr, int chr_base, int chr_mask) -{ - UINT8 chr_page = (m_latch & 0x80) >> 5; - - chr_cb(chr_page ^ 0, chr_base | (m_mmc_vrom_bank[0] & chr_mask), chr); - chr_cb(chr_page ^ 1, chr_base | (m_mmc_vrom_bank[6] & chr_mask), chr); - chr_cb(chr_page ^ 2, chr_base | (m_mmc_vrom_bank[1] & chr_mask), chr); - chr_cb(chr_page ^ 3, chr_base | (m_mmc_vrom_bank[7] & chr_mask), chr); - chr_cb(chr_page ^ 4, chr_base | (m_mmc_vrom_bank[2] & chr_mask), chr); - chr_cb(chr_page ^ 5, chr_base | (m_mmc_vrom_bank[3] & chr_mask), chr); - chr_cb(chr_page ^ 6, chr_base | (m_mmc_vrom_bank[4] & chr_mask), chr); - chr_cb(chr_page ^ 7, chr_base | (m_mmc_vrom_bank[5] & chr_mask), chr); -} - -WRITE8_MEMBER(nes_waixing_g_device::write_h) -{ - UINT8 cmd; - LOG_MMC(("waixing_g write_h, offset: %04x, data: %02x\n", offset, data)); - - switch (offset & 0x6001) - { - case 0x0001: - cmd = m_latch & 0x0f; - switch (cmd) - { - case 0: case 1: - case 2: case 3: case 4: case 5: - m_mmc_vrom_bank[cmd] = data; - set_chr(m_chr_source, m_chr_base, m_chr_mask); - break; - case 6: - case 7: - case 8: - case 9: - m_mmc_prg_bank[cmd - 6] = data; - set_prg(m_prg_base, m_prg_mask); - break; - case 0x0a: case 0x0b: - m_mmc_vrom_bank[cmd - 4] = data; - set_chr(m_chr_source, m_chr_base, m_chr_mask); - break; - } - break; - - default: - waixing_write(space, offset, data, mem_mask); - break; - } -} - -/*------------------------------------------------- - - Waixing Board Type H - - Games: Ying Xiong Yuan Yi Jing Chuan Qi, Yong Zhe Dou E - Long - Dragon Quest VII - - MMC3 clone. More info to come. - - Notice that Chinese Zelda translation stops working if - WRAM protect bit is ignored (i.e. if writes to 0x2001 - are skipped)! OTOH, Chinese Monster Maker 1/2 translations - and Zheng Ba ShiJi stop working if WRAM protect is - accounted. So we split the board into two subtypes - - iNES: mapper 245 - - In MESS: Supported. - - -------------------------------------------------*/ - -void nes_waixing_h_device::chr_cb(int start, int bank, int source) -{ - if (source == CHRROM) - chr1_x(start, bank, source); -} - -WRITE8_MEMBER(nes_waixing_h_device::write_h) -{ - UINT8 cmd; - LOG_MMC(("waixing_h write_h, offset: %04x, data: %02x\n", offset, data)); - - switch (offset & 0x6001) - { - case 0x0001: - cmd = m_latch & 0x07; - switch (cmd) - { - case 0: // in this case we set prg_base in addition to m_mmc_vrom_bank! - m_prg_base = (data << 5) & 0x40; - m_prg_mask = 0x3f; - set_prg(m_prg_base, m_prg_mask); - case 1: - case 2: case 3: case 4: case 5: - m_mmc_vrom_bank[cmd] = data; - set_chr(m_chr_source, m_chr_base, m_chr_mask); - break; - case 6: - case 7: - m_mmc_prg_bank[cmd - 6] = data; - set_prg(m_prg_base, m_prg_mask); - break; - case 0x0a: case 0x0b: // CHR switches in 1K banks only, and bank1 & bank3 are controlled by these - m_mmc_vrom_bank[cmd - 4] = data; - set_chr(m_chr_source, m_chr_base, m_chr_mask); - break; - } - break; - - case 0x2001: - break; - - default: - txrom_write(space, offset, data, mem_mask); - break; - } -} - -WRITE8_MEMBER(nes_waixing_h1_device::write_h) -{ - UINT8 cmd; - LOG_MMC(("waixing_h1 write_h, offset: %04x, data: %02x\n", offset, data)); - - switch (offset & 0x6001) - { - case 0x0001: - cmd = m_latch & 0x07; - switch (cmd) - { - case 0: // in this case we set prg_base in addition to m_mmc_vrom_bank! - m_prg_base = (data << 5) & 0x40; - m_prg_mask = 0x3f; - set_prg(m_prg_base, m_prg_mask); - case 1: - case 2: case 3: case 4: case 5: - m_mmc_vrom_bank[cmd] = data; - set_chr(m_chr_source, m_chr_base, m_chr_mask); - break; - case 6: - case 7: - m_mmc_prg_bank[cmd - 6] = data; - set_prg(m_prg_base, m_prg_mask); - break; - case 0x0a: case 0x0b: // CHR switches in 1K banks only, and bank1 & bank3 are controlled by these - m_mmc_vrom_bank[cmd - 4] = data; - set_chr(m_chr_source, m_chr_base, m_chr_mask); - break; - } - break; - - default: - txrom_write(space, offset, data, mem_mask); - break; - } -} - -/*------------------------------------------------- - - Waixing Board Type J - - Games: Final Fantasy III (C) - - MMC3 clone. - - In MESS: Preliminary support. - - -------------------------------------------------*/ - -void nes_waixing_j_device::set_prg( int prg_base, int prg_mask ) -{ - UINT8 prg_flip = (m_latch & 0x40) ? 2 : 0; - - prg_cb(0, m_reg[0 ^ prg_flip]); - prg_cb(1, m_reg[1]); - prg_cb(2, m_reg[2 ^ prg_flip]); - prg_cb(3, m_reg[3]); -} - -WRITE8_MEMBER(nes_waixing_j_device::write_h) -{ - UINT8 cmd; - LOG_MMC(("waixing_f write_h, offset: %04x, data: %02x\n", offset, data)); - - switch (offset & 0x6001) - { - case 0x0001: - cmd = m_latch & 0x07; - switch (cmd) - { - case 0: case 1: // these do not need to be separated: we take care of them in set_chr! - case 2: case 3: case 4: case 5: - m_mmc_vrom_bank[cmd] = data; - set_chr(m_chr_source, m_chr_base, m_chr_mask); - break; - case 6: - case 7: - case 8: - case 9: - m_reg[cmd - 6] = data; - set_prg(m_prg_base, m_prg_mask); - break; - } - break; - -// case 0x2001: -// break; - - default: - waixing_write(space, offset, data, mem_mask); - break; - } -} - -/*------------------------------------------------- - - Waixing SH2 Board - - Games: Fire Emblem (C) and Fire Emblem Gaiden (C) - - MMC3 clone with different access to CHR - - iNES: mapper 165 - - In MESS: Partially Supported. - - -------------------------------------------------*/ - -void nes_waixing_sh2_device::chr_cb(int start, int bank, int source) -{ - chr4_0(m_reg[0], m_reg[0] ? CHRRAM : CHRROM); - chr4_4(m_reg[1], m_reg[1] ? CHRRAM : CHRROM); -} - -READ8_MEMBER(nes_waixing_sh2_device::chr_r) -{ - int bank = offset >> 10; - UINT8 val = m_chr_access[bank][offset & 0x3ff]; // this would be usual return value - int chr_helper; - - switch (offset & 0xff8) - { - case 0xfd0: chr_helper = (bank & 0x4) | 0x0; break; - case 0xfe8: chr_helper = (bank & 0x4) | 0x2; break; - default: return val; - } - - m_reg[offset >> 12] = chr_helper; - if (offset & 0x1000) - chr4_4(m_reg[1], m_reg[1] ? CHRRAM : CHRROM); - else - chr4_0(m_reg[0], m_reg[0] ? CHRRAM : CHRROM); - - return val; -} - -/*------------------------------------------------- - - Waixing Board with Security Chip - - Games: Duo Bao Xiao Ying Hao - Guang Ming yu An Hei Chuan Shuo, - Myth Struggle, San Shi Liu Ji, Shui Hu Zhuan - - MMC3 clone - - iNES: mapper 249 - - In MESS: Partially Supported. - - -------------------------------------------------*/ - -void nes_waixing_sec_device::prg_cb(int start, int bank) -{ - if (m_reg) - bank = BITSWAP8(bank & 0x1f,7,6,5,2,1,3,4,0); - - prg8_x(start, bank); -} - -void nes_waixing_sec_device::chr_cb(int start, int bank, int source) -{ - if (m_reg) - bank = BITSWAP8(bank, 5,4,2,6,7,3,1,0); - - chr1_x(start, bank, source); -} - -WRITE8_MEMBER(nes_waixing_sec_device::write_l) -{ - LOG_MMC(("waixing_sec write_l, offset: %04x, data: %02x\n", offset, data)); - offset += 0x100; - - if (offset == 0x1000) - { - m_reg = data & 0x02; - set_prg(m_prg_base, m_prg_mask); - set_chr(m_chr_source, m_chr_base, m_chr_mask); - } -} - -/*------------------------------------------------- - - Waixing San Guo Zhi Board - - Games: San Guo Zhi - - This board uses Konami IRQ - - iNES: mapper 252 - - In MESS: Unsupported. - - -------------------------------------------------*/ - -// same as Konami IRQ -void nes_waixing_sgz_device::hblank_irq(int scanline, int vblank, int blanked) -{ - /* Increment & check the IRQ scanline counter */ - if (m_irq_enable && (++m_irq_count == 0x100)) - { - m_irq_count = m_irq_count_latch; - m_irq_enable = m_irq_enable_latch; - m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE); - } -} - -WRITE8_MEMBER(nes_waixing_sgz_device::write_h) -{ - UINT8 helper, bank; - LOG_MMC(("waixing_sgz write_h, offset: %04x, data: %02x\n", offset, data)); - - switch (offset & 0x7000) - { - case 0x0000: - prg8_89(data); - break; - case 0x2000: - prg8_ab(data); - break; - case 0x3000: - case 0x4000: - case 0x5000: - case 0x6000: - bank = ((offset & 0x7000) - 0x3000) / 0x0800 + ((offset & 0x0008) >> 3); - helper = offset & 0x04; - if (helper) - m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0x0f) | ((data & 0x0f) << 4); - else - m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0xf0) | (data & 0x0f); - chr1_x(bank, m_mmc_vrom_bank[bank], CHRROM); - break; - case 0x7000: - switch (offset & 0x0c) - { - case 0x00: - m_irq_count_latch = (m_irq_count_latch & 0xf0) | (data & 0x0f); - break; - case 0x04: - m_irq_count_latch = (m_irq_count_latch & 0x0f) | ((data & 0x0f) << 4); - break; - case 0x08: - m_irq_enable = data & 0x02; - m_irq_count_latch = data & 0x01; - if (data & 0x02) - m_irq_count = m_irq_count_latch; - break; - case 0x0c: - m_irq_enable = m_irq_enable_latch; - break; - } - break; - } -} - - -/*------------------------------------------------- - - Waixing San Guo Zhong Lie Zhuan Board - - Games: Fan Kong Jing Ying, San Guo Zhong Lie Zhuan, Xing - Ji Zheng Ba - - iNES: mapper 178 - - In MESS: Supported. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_waixing_sgzlz_device::write_l) -{ - LOG_MMC(("waixing_sgzlz write_l, offset: %04x, data: %02x\n", offset, data)); - - switch (offset) - { - case 0x700: - set_nt_mirroring(data ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); - break; - case 0x701: - m_latch = (m_latch & 0x0c) | ((data >> 1) & 0x03); - prg32(m_latch); - break; - case 0x702: - m_latch = (m_latch & 0x03) | ((data << 2) & 0x0c); - break; - } -} - -/*------------------------------------------------- - - Waixing Final Fantasy V Board - - Games: Darkseed, Digital Dragon, Final Fantasy V, Pocket - Monster Red - - iNES: mapper 164 - - In MESS: Supported. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_waixing_ffv_device::write_l) -{ - UINT8 helper; - LOG_MMC(("waixing_ffv write_l, offset: %04x, data: %02x\n", offset, data)); - offset += 0x100; /* the checks work better on addresses */ - - if ((offset & 0x1200) == 0x1000) - { - m_reg[BIT(offset, 8)] = data; - helper = BIT(m_reg[1], 0) << 5; - switch (m_reg[0] & 0x70) - { - case 0x00: - case 0x20: - case 0x40: - case 0x60: - prg16_89ab(helper | ((m_reg[0] >> 1) & 0x10) | (m_reg[0] & 0x0f)); - prg16_cdef(helper & 0x1f); - break; - case 0x50: - prg32((helper >> 1) | (m_reg[0] & 0x0f)); - break; - case 0x70: - prg16_89ab(helper | ((m_reg[0] << 1) & 0x10) | (m_reg[0] & 0x0f)); - prg16_cdef(helper & 0x1f); - break; - } - } -} - -/*------------------------------------------------- - - Waixing Zhan Shi Board - - Games: Wai Xing Zhan Shi - - Simple mapper: writes to 0x8000-0xffff sets prg32 banks to - (offset>>3)&f. written data&3 sets the mirroring (with - switched high/low compared to the standard one). - - A crc check is required to support Dragon Quest VIII (which - uses a slightly different board) - - iNES: mapper 242 - - In MESS: Supported. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_waixing_wxzs_device::write_h) -{ - LOG_MMC(("waixing_zs write_h, offset: %04x, data: %02x\n", offset, data)); - - prg32(offset >> 3); - - switch (data & 0x03) - { - case 0: set_nt_mirroring(PPU_MIRROR_VERT); break; - case 1: set_nt_mirroring(PPU_MIRROR_HORZ); break; - case 2: set_nt_mirroring(PPU_MIRROR_LOW); break; - case 3: set_nt_mirroring(PPU_MIRROR_HIGH); break; - } -} - -/*------------------------------------------------- - - Waixing Dragon Quest VIII Board - - Games: Dragon Quest VIII - - Simple mapper: writes to 0x8000-0xffff sets prg32 banks to - (offset>>3)&f. - - iNES: mapper 242 - - In MESS: Supported. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_waixing_dq8_device::write_h) -{ - LOG_MMC(("waixing_dq8 write_h, offset: %04x, data: %02x\n", offset, data)); - - prg32(offset >> 3); -} - - -/*------------------------------------------------- - - Waixing WXZS2 / PS2 board - - Games: Wai Xing Zhan Shi 2 (aka Phantasy Star 2), - Bao Xiao Tien Guo, Bio Hazard, Pokemon Gold, Subor (R) - - iNES: mapper 15 - - In MESS: Supported - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_waixing_wxzs2_device::write_h) -{ - UINT8 flip = (data & 0x80) >> 7; - UINT8 helper = (data & 0x7f) << 1; - - LOG_MMC(("waixing_wxzs2 write_h, offset: %04x, data: %02x\n", offset, data)); - - set_nt_mirroring(BIT(data, 6) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); - - switch (offset & 0x0fff) - { - case 0x000: - prg8_89((helper + 0) ^ flip); - prg8_ab((helper + 1) ^ flip); - prg8_cd((helper + 2) ^ flip); - prg8_ef((helper + 3) ^ flip); - break; - case 0x001: - helper |= flip; - prg8_89(helper); - prg8_ab(helper + 1); - prg8_cd(helper + 1); - prg8_ef(helper + 1); - break; - case 0x002: - helper |= flip; - prg8_89(helper); - prg8_ab(helper); - prg8_cd(helper); - prg8_ef(helper); - break; - case 0x003: - helper |= flip; - prg8_89(helper); - prg8_ab(helper + 1); - prg8_cd(helper); - prg8_ef(helper + 1); - break; - } -} - -/*------------------------------------------------- - - Board UNL-FS304 - - Games: A Link to the Past by Waixing - - iNES: mapper 162? (only found in UNIF format) - - In MESS: Supported. - - -------------------------------------------------*/ - -WRITE8_MEMBER(nes_waixing_fs304_device::write_l) -{ - LOG_MMC(("fs304 write_l, offset: %04x, data: %02x\n", offset, data)); - int bank; - offset += 0x100; - - if (offset >= 0x1000) - { - m_reg[(offset >> 8) & 3] = data; - bank = ((m_reg[2] & 0x0f) << 4) | BIT(m_reg[1], 1) | (m_reg[0] & 0x0e); - prg32(bank); - chr8(0, CHRRAM); - } -} diff --git a/src/devices/bus/nes/waixing.cpp b/src/devices/bus/nes/waixing.cpp new file mode 100644 index 00000000000..8a223a8e295 --- /dev/null +++ b/src/devices/bus/nes/waixing.cpp @@ -0,0 +1,1244 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for Waixing PCBs + + Here we emulate the various PCBs used by Waixing for its games + + TODO: + - investigate the PPU issues causing some games not to have sprites (e.g. some games using mappers 15, 164, + 242, 249) + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "waixing.h" + +#include "cpu/m6502/m6502.h" + + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_WAIXING_A = &device_creator; +const device_type NES_WAIXING_A1 = &device_creator; +const device_type NES_WAIXING_B = &device_creator; +const device_type NES_WAIXING_C = &device_creator; +const device_type NES_WAIXING_D = &device_creator; +const device_type NES_WAIXING_E = &device_creator; +const device_type NES_WAIXING_F = &device_creator; +const device_type NES_WAIXING_G = &device_creator; +const device_type NES_WAIXING_H = &device_creator; +const device_type NES_WAIXING_H1 = &device_creator; +const device_type NES_WAIXING_I = &device_creator; +const device_type NES_WAIXING_J = &device_creator; +const device_type NES_WAIXING_SH2 = &device_creator; +const device_type NES_WAIXING_SEC = &device_creator; +const device_type NES_WAIXING_SGZ = &device_creator; +const device_type NES_WAIXING_SGZLZ = &device_creator; +const device_type NES_WAIXING_FFV = &device_creator; +const device_type NES_WAIXING_WXZS = &device_creator; +const device_type NES_WAIXING_DQ8 = &device_creator; +const device_type NES_WAIXING_WXZS2 = &device_creator; +const device_type NES_WAIXING_FS304 = &device_creator; + + +nes_waixing_a_device::nes_waixing_a_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : nes_txrom_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +nes_waixing_a_device::nes_waixing_a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_WAIXING_A, "NES Cart Waixing Type A PCB", tag, owner, clock, "nes_waixing_a", __FILE__) +{ +} + +nes_waixing_a1_device::nes_waixing_a1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_waixing_a_device(mconfig, NES_WAIXING_A1, "NES Cart Waixing Type A (Alt) PCB", tag, owner, clock, "nes_waixing_a1", __FILE__) +{ +} + +nes_waixing_b_device::nes_waixing_b_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_waixing_a_device(mconfig, NES_WAIXING_B, "NES Cart Waixing Type B PCB", tag, owner, clock, "nes_waixing_b", __FILE__) +{ +} + +nes_waixing_c_device::nes_waixing_c_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_waixing_a_device(mconfig, NES_WAIXING_C, "NES Cart Waixing Type C PCB", tag, owner, clock, "nes_waixing_c", __FILE__) +{ +} + +nes_waixing_d_device::nes_waixing_d_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_waixing_a_device(mconfig, NES_WAIXING_D, "NES Cart Waixing Type D PCB", tag, owner, clock, "nes_waixing_d", __FILE__) +{ +} + +nes_waixing_e_device::nes_waixing_e_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_waixing_a_device(mconfig, NES_WAIXING_E, "NES Cart Waixing Type E PCB", tag, owner, clock, "nes_waixing_e", __FILE__) +{ +} + +nes_waixing_f_device::nes_waixing_f_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_waixing_a_device(mconfig, NES_WAIXING_F, "NES Cart Waixing Type F PCB", tag, owner, clock, "nes_waixing_f", __FILE__) +{ +} + +nes_waixing_g_device::nes_waixing_g_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_waixing_a_device(mconfig, NES_WAIXING_G, "NES Cart Waixing Type G PCB", tag, owner, clock, "nes_waixing_g", __FILE__) +{ +} + +nes_waixing_h_device::nes_waixing_h_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : nes_txrom_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +nes_waixing_h_device::nes_waixing_h_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_WAIXING_H, "NES Cart Waixing Type H PCB", tag, owner, clock, "nes_waixing_h", __FILE__) +{ +} + +nes_waixing_h1_device::nes_waixing_h1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_waixing_h_device(mconfig, NES_WAIXING_H1, "NES Cart Waixing Type H (Alt) PCB", tag, owner, clock, "nes_waixing_h1", __FILE__) +{ +} + +nes_waixing_i_device::nes_waixing_i_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_waixing_a_device(mconfig, NES_WAIXING_I, "NES Cart Waixing Type I PCB", tag, owner, clock, "nes_waixing_i", __FILE__) +{ +} + +nes_waixing_j_device::nes_waixing_j_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_waixing_a_device(mconfig, NES_WAIXING_J, "NES Cart Waixing Type J PCB", tag, owner, clock, "nes_waixing_j", __FILE__) +{ +} + +nes_waixing_sh2_device::nes_waixing_sh2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_WAIXING_SH2, "NES Cart Waixing SH2 PCB", tag, owner, clock, "nes_waixing_sh2", __FILE__) +{ +} + +nes_waixing_sec_device::nes_waixing_sec_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_WAIXING_SEC, "NES Cart Waixing Security Chip PCB", tag, owner, clock, "nes_waixing_sec", __FILE__) +{ +} + +nes_waixing_sgz_device::nes_waixing_sgz_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_WAIXING_SGZ, "NES Cart Waixing San Guo Zhi PCB", tag, owner, clock, "nes_waixing_sgz", __FILE__) +{ +} + +nes_waixing_sgzlz_device::nes_waixing_sgzlz_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_WAIXING_SGZLZ, "NES Cart Waixing San Guo Zhong Lie Zhuan PCB", tag, owner, clock, "nes_waixing_sgzlz", __FILE__) +{ +} + +nes_waixing_ffv_device::nes_waixing_ffv_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_WAIXING_FFV, "NES Cart Waixing Final Fantasy V PCB", tag, owner, clock, "nes_waixing_ffv", __FILE__) +{ +} + +nes_waixing_wxzs_device::nes_waixing_wxzs_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_WAIXING_WXZS, "NES Cart Waixing Wai Xing Zhan Shi PCB", tag, owner, clock, "nes_waixing_wxzs", __FILE__) +{ +} + +nes_waixing_dq8_device::nes_waixing_dq8_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_WAIXING_DQ8, "NES Cart Waixing Dragon Quest VIII PCB", tag, owner, clock, "nes_waixing_dq8", __FILE__) +{ +} + +nes_waixing_wxzs2_device::nes_waixing_wxzs2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_WAIXING_WXZS2, "NES Cart Waixing Wai Xing Zhan Shi 2 PCB", tag, owner, clock, "nes_waixing_wxzs2", __FILE__) +{ +} + +nes_waixing_fs304_device::nes_waixing_fs304_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_WAIXING_FS304, "NES Cart Waixing FS-304 PCB", tag, owner, clock, "nes_waixing_fs304", __FILE__) +{ +} + + +void nes_waixing_a_device::device_start() +{ + mmc3_start(); + save_item(NAME(mapper_ram)); +} + +void nes_waixing_a_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + mmc3_common_initialize(0xff, 0xff, 0); + + memset(mapper_ram, 0, sizeof(mapper_ram)); +} + +void nes_waixing_f_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + mmc3_common_initialize(0xff, 0xff, 0); + + memset(mapper_ram, 0, sizeof(mapper_ram)); + m_mmc_prg_bank[0] = 0x00; + m_mmc_prg_bank[1] = 0x01; + m_mmc_prg_bank[2] = 0x4e; + m_mmc_prg_bank[3] = 0x4f; + set_prg(m_prg_base, m_prg_mask); +} + +void nes_waixing_g_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + mmc3_common_initialize(0xff, 0xff, 0); + + memset(mapper_ram, 0, sizeof(mapper_ram)); + m_mmc_prg_bank[0] = 0x00; + m_mmc_prg_bank[1] = 0x01; + m_mmc_prg_bank[2] = 0x3e; + m_mmc_prg_bank[3] = 0x3f; + m_mmc_vrom_bank[0] = 0x00; + m_mmc_vrom_bank[1] = 0x02; + m_mmc_vrom_bank[2] = 0x04; + m_mmc_vrom_bank[3] = 0x05; + m_mmc_vrom_bank[4] = 0x06; + m_mmc_vrom_bank[5] = 0x07; + m_mmc_vrom_bank[6] = 0x01; + m_mmc_vrom_bank[7] = 0x03; + set_prg(m_prg_base, m_prg_mask); + set_chr(m_chr_source, m_chr_base, m_chr_mask); +} + +void nes_waixing_j_device::device_start() +{ + mmc3_start(); + save_item(NAME(m_reg)); +} + +void nes_waixing_j_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + + m_reg[0] = 0x01; + m_reg[1] = 0x02; + m_reg[2] = 0x7e; + m_reg[3] = 0x7f; + mmc3_common_initialize(0xff, 0xff, 0); + set_prg(m_prg_base, m_prg_mask); +} + +void nes_waixing_sh2_device::device_start() +{ + mmc3_start(); + save_item(NAME(m_reg)); +} + +void nes_waixing_sh2_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + + m_reg[0] = m_reg[1] = 0; + mmc3_common_initialize(0xff, 0xff, 0); +} + +void nes_waixing_sec_device::device_start() +{ + mmc3_start(); + save_item(NAME(m_reg)); +} + +void nes_waixing_sec_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + + m_reg = 0; + mmc3_common_initialize(0xff, 0xff, 0); +} + +void nes_waixing_sgz_device::device_start() +{ + common_start(); + save_item(NAME(m_irq_enable)); + save_item(NAME(m_irq_enable_latch)); + save_item(NAME(m_irq_count)); + save_item(NAME(m_irq_count_latch)); + save_item(NAME(m_mmc_vrom_bank)); +} + +void nes_waixing_sgz_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + + m_irq_enable = 0; + m_irq_enable_latch = 0; + m_irq_count = 0; + m_irq_count_latch = 0; + + memset(m_mmc_vrom_bank, 0, sizeof(m_mmc_vrom_bank)); +} + +void nes_waixing_sgzlz_device::device_start() +{ + common_start(); + save_item(NAME(m_latch)); +} + +void nes_waixing_sgzlz_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); + + m_latch = 0; +} + +void nes_waixing_ffv_device::device_start() +{ + common_start(); + save_item(NAME(m_reg)); +} + +void nes_waixing_ffv_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(0x1f); + chr8(0, m_chr_source); + + m_reg[0] = m_reg[1] = 0; +} + +void nes_waixing_wxzs_device::device_start() +{ + common_start(); +} + +void nes_waixing_wxzs_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + +void nes_waixing_dq8_device::device_start() +{ + common_start(); +} + +void nes_waixing_dq8_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + +void nes_waixing_wxzs2_device::device_start() +{ + common_start(); +} + +void nes_waixing_wxzs2_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); + set_nt_mirroring(PPU_MIRROR_VERT); +} + +void nes_waixing_fs304_device::device_start() +{ + common_start(); + save_item(NAME(m_reg)); +} + +void nes_waixing_fs304_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); + + memset(m_reg, 0x00, sizeof(m_reg)); +} + + + + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + Waixing Board Type A + + Games: Columbus - Ougon no Yoake (C), Ji Jia Zhan Shi, + Jia A Fung Yun, Wei Luo Chuan Qi + + This mapper is quite similar to MMC3, but with two differences: + mirroring is not the same, and when VROM banks 8,9 are accessed + they point to CHRRAM and not CHRROM. + + iNES: mapper 74 + + In MESS: Supported + + -------------------------------------------------*/ + +/* MIRROR_LOW and MIRROR_HIGH are swapped! */ +void nes_waixing_a_device::set_mirror(UINT8 nt) +{ + switch (nt) + { + case 0: + case 1: + set_nt_mirroring(nt ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + break; + case 2: + set_nt_mirroring(PPU_MIRROR_LOW); + break; + case 3: + set_nt_mirroring(PPU_MIRROR_HIGH); + break; + default: + LOG_MMC(("Mapper set NT to invalid value %02x", nt)); + break; + } +} + +/* Luo Ke Ren X only works with this */ +void nes_waixing_a_device::chr_cb(int start, int bank, int source) +{ + int chr_src = (bank <= 9) ? CHRRAM : CHRROM; + chr1_x(start, bank, chr_src); +} + +/* Ji Jia Zhan Shi only works with this */ +void nes_waixing_a1_device::chr_cb(int start, int bank, int source) +{ + int chr_src = ((bank == 8) || (bank == 9)) ? CHRRAM : CHRROM; + chr1_x(start, bank, chr_src); +} + +WRITE8_MEMBER(nes_waixing_a_device::waixing_write) +{ + LOG_MMC(("waixing_write, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x6001) + { + case 0x2000: + set_mirror(data); //maybe data & 0x03? + break; + + case 0x2001: + break; + + default: + txrom_write(space, offset, data, mem_mask); + break; + } +} + +READ8_MEMBER(nes_waixing_a_device::read_l) +{ + LOG_MMC(("waixing read_l, offset: %04x\n", offset)); + offset += 0x100; + if (offset >= 0x1000 && offset < 0x1400) + return mapper_ram[offset & 0x3ff]; + else + return 0xff; +} + +WRITE8_MEMBER(nes_waixing_a_device::write_l) +{ + LOG_MMC(("waixing write_l, offset: %04x, data: %02x\n", offset, data)); + offset += 0x100; + if (offset >= 0x1000 && offset < 0x1400) + mapper_ram[offset & 0x3ff] = data; +} + + +/*------------------------------------------------- + + Waixing Board Type B + + Games: Sugoro Quest (C) + + MMC3 clone. This is a minor modification of Mapper 74, + in the sense that it is the same board except for the + CHRRAM pages. + + iNES: mapper 191 + + In MESS: Supported. + + -------------------------------------------------*/ + +void nes_waixing_b_device::chr_cb(int start, int bank, int source) +{ + int chr_src = BIT(bank, 7) ? CHRRAM : CHRROM; + chr1_x(start, bank, chr_src); +} + +/*------------------------------------------------- + + Waixing Board Type C + + Games: Ying Lie Qun Xia Zhuan, Young Chivalry + + MMC3 clone. This is a minor modification of Mapper 74, + in the sense that it is the same board except for the + CHRRAM pages. + + iNES: mapper 192 + + In MESS: Supported. + + -------------------------------------------------*/ + +void nes_waixing_c_device::chr_cb(int start, int bank, int source) +{ + int chr_src = ((bank == 0x08) || (bank == 0x09) || (bank == 0x0a) || (bank == 0x0b)) ? CHRRAM : CHRROM; + chr1_x(start, bank, chr_src); +} + +/*------------------------------------------------- + + Waixing Board Type D + + Games: Super Robot Taisen (C) + + MMC3 clone. This is a minor modification of Mapper 74, + in the sense that it is the same board except for the + CHRRAM pages. + + iNES: mapper 194 + + In MESS: Supported. + + -------------------------------------------------*/ + +void nes_waixing_d_device::chr_cb(int start, int bank, int source) +{ + int chr_src = (bank < 0x02) ? CHRRAM : CHRROM; + chr1_x(start, bank, chr_src); +} + +/*------------------------------------------------- + + Waixing Board Type E + + Games: Captain Tsubasa Vol. II (C), Chaos World, God + Slayer (C), Zu Qiu Xiao Jiang + + MMC3 clone. This is a minor modification of Mapper 74, + in the sense that it is the same board except for the + CHRRAM pages. + + iNES: mapper 195 + + In MESS: Supported. + + -------------------------------------------------*/ + +void nes_waixing_e_device::chr_cb(int start, int bank, int source) +{ + int chr_src = (bank < 0x04) ? CHRRAM : CHRROM; + chr1_x(start, bank, chr_src); +} + + +/*------------------------------------------------- + + Waixing Board Type F + + Games: Tenchi wo Kurau II (C) + + MMC3 clone. + + iNES: mapper 198 + + In MESS: Preliminary support. + + -------------------------------------------------*/ + +void nes_waixing_f_device::chr_cb(int start, int bank, int source) +{ + chr1_x(start, bank, CHRRAM); +} + +void nes_waixing_f_device::prg_cb(int start, int bank) +{ +// if (bank > 0x3f) +// bank = 0x40 | (bank & 0xf); + prg8_x(start, bank); +} + +void nes_waixing_f_device::set_prg( int prg_base, int prg_mask ) +{ + UINT8 prg_flip = (m_latch & 0x40) ? 2 : 0; + + prg_cb(0, m_mmc_prg_bank[0 ^ prg_flip]); + prg_cb(1, m_mmc_prg_bank[1]); + prg_cb(2, m_mmc_prg_bank[2 ^ prg_flip]); + prg_cb(3, m_mmc_prg_bank[3]); +} + +WRITE8_MEMBER(nes_waixing_f_device::write_h) +{ + UINT8 cmd; + LOG_MMC(("waixing_f write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x6001) + { + case 0x0001: + cmd = m_latch & 0x07; + switch (cmd) + { + case 0: case 1: // these do not need to be separated: we take care of them in set_chr! + case 2: case 3: case 4: case 5: + m_mmc_vrom_bank[cmd] = data; + set_chr(m_chr_source, m_chr_base, m_chr_mask); + break; + case 6: + case 7: + case 8: + case 9: + m_mmc_prg_bank[cmd - 6] = data; + //printf("prg bank %d value %x\n", cmd - 6, data); + set_prg(m_prg_base, m_prg_mask); + break; + } + break; + + case 0x2001: + break; + + default: + waixing_write(space, offset, data, mem_mask); + break; + } +} + +/*------------------------------------------------- + + Waixing Board Type G + + Games: San Guo Zhi 2, Dragon Ball Z Gaiden (C), Dragon + Ball Z II (C) + + MMC3 clone, capable of switching all 4 PRG banks + + iNES: mapper 199 + + In MESS: Supported. + + -------------------------------------------------*/ + +void nes_waixing_g_device::chr_cb(int start, int bank, int source) +{ + int chr_src = (bank < 0x08) ? CHRRAM : CHRROM; + chr1_x(start, bank, chr_src); +} + +void nes_waixing_g_device::set_chr(UINT8 chr, int chr_base, int chr_mask) +{ + UINT8 chr_page = (m_latch & 0x80) >> 5; + + chr_cb(chr_page ^ 0, chr_base | (m_mmc_vrom_bank[0] & chr_mask), chr); + chr_cb(chr_page ^ 1, chr_base | (m_mmc_vrom_bank[6] & chr_mask), chr); + chr_cb(chr_page ^ 2, chr_base | (m_mmc_vrom_bank[1] & chr_mask), chr); + chr_cb(chr_page ^ 3, chr_base | (m_mmc_vrom_bank[7] & chr_mask), chr); + chr_cb(chr_page ^ 4, chr_base | (m_mmc_vrom_bank[2] & chr_mask), chr); + chr_cb(chr_page ^ 5, chr_base | (m_mmc_vrom_bank[3] & chr_mask), chr); + chr_cb(chr_page ^ 6, chr_base | (m_mmc_vrom_bank[4] & chr_mask), chr); + chr_cb(chr_page ^ 7, chr_base | (m_mmc_vrom_bank[5] & chr_mask), chr); +} + +WRITE8_MEMBER(nes_waixing_g_device::write_h) +{ + UINT8 cmd; + LOG_MMC(("waixing_g write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x6001) + { + case 0x0001: + cmd = m_latch & 0x0f; + switch (cmd) + { + case 0: case 1: + case 2: case 3: case 4: case 5: + m_mmc_vrom_bank[cmd] = data; + set_chr(m_chr_source, m_chr_base, m_chr_mask); + break; + case 6: + case 7: + case 8: + case 9: + m_mmc_prg_bank[cmd - 6] = data; + set_prg(m_prg_base, m_prg_mask); + break; + case 0x0a: case 0x0b: + m_mmc_vrom_bank[cmd - 4] = data; + set_chr(m_chr_source, m_chr_base, m_chr_mask); + break; + } + break; + + default: + waixing_write(space, offset, data, mem_mask); + break; + } +} + +/*------------------------------------------------- + + Waixing Board Type H + + Games: Ying Xiong Yuan Yi Jing Chuan Qi, Yong Zhe Dou E + Long - Dragon Quest VII + + MMC3 clone. More info to come. + + Notice that Chinese Zelda translation stops working if + WRAM protect bit is ignored (i.e. if writes to 0x2001 + are skipped)! OTOH, Chinese Monster Maker 1/2 translations + and Zheng Ba ShiJi stop working if WRAM protect is + accounted. So we split the board into two subtypes + + iNES: mapper 245 + + In MESS: Supported. + + -------------------------------------------------*/ + +void nes_waixing_h_device::chr_cb(int start, int bank, int source) +{ + if (source == CHRROM) + chr1_x(start, bank, source); +} + +WRITE8_MEMBER(nes_waixing_h_device::write_h) +{ + UINT8 cmd; + LOG_MMC(("waixing_h write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x6001) + { + case 0x0001: + cmd = m_latch & 0x07; + switch (cmd) + { + case 0: // in this case we set prg_base in addition to m_mmc_vrom_bank! + m_prg_base = (data << 5) & 0x40; + m_prg_mask = 0x3f; + set_prg(m_prg_base, m_prg_mask); + case 1: + case 2: case 3: case 4: case 5: + m_mmc_vrom_bank[cmd] = data; + set_chr(m_chr_source, m_chr_base, m_chr_mask); + break; + case 6: + case 7: + m_mmc_prg_bank[cmd - 6] = data; + set_prg(m_prg_base, m_prg_mask); + break; + case 0x0a: case 0x0b: // CHR switches in 1K banks only, and bank1 & bank3 are controlled by these + m_mmc_vrom_bank[cmd - 4] = data; + set_chr(m_chr_source, m_chr_base, m_chr_mask); + break; + } + break; + + case 0x2001: + break; + + default: + txrom_write(space, offset, data, mem_mask); + break; + } +} + +WRITE8_MEMBER(nes_waixing_h1_device::write_h) +{ + UINT8 cmd; + LOG_MMC(("waixing_h1 write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x6001) + { + case 0x0001: + cmd = m_latch & 0x07; + switch (cmd) + { + case 0: // in this case we set prg_base in addition to m_mmc_vrom_bank! + m_prg_base = (data << 5) & 0x40; + m_prg_mask = 0x3f; + set_prg(m_prg_base, m_prg_mask); + case 1: + case 2: case 3: case 4: case 5: + m_mmc_vrom_bank[cmd] = data; + set_chr(m_chr_source, m_chr_base, m_chr_mask); + break; + case 6: + case 7: + m_mmc_prg_bank[cmd - 6] = data; + set_prg(m_prg_base, m_prg_mask); + break; + case 0x0a: case 0x0b: // CHR switches in 1K banks only, and bank1 & bank3 are controlled by these + m_mmc_vrom_bank[cmd - 4] = data; + set_chr(m_chr_source, m_chr_base, m_chr_mask); + break; + } + break; + + default: + txrom_write(space, offset, data, mem_mask); + break; + } +} + +/*------------------------------------------------- + + Waixing Board Type J + + Games: Final Fantasy III (C) + + MMC3 clone. + + In MESS: Preliminary support. + + -------------------------------------------------*/ + +void nes_waixing_j_device::set_prg( int prg_base, int prg_mask ) +{ + UINT8 prg_flip = (m_latch & 0x40) ? 2 : 0; + + prg_cb(0, m_reg[0 ^ prg_flip]); + prg_cb(1, m_reg[1]); + prg_cb(2, m_reg[2 ^ prg_flip]); + prg_cb(3, m_reg[3]); +} + +WRITE8_MEMBER(nes_waixing_j_device::write_h) +{ + UINT8 cmd; + LOG_MMC(("waixing_f write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x6001) + { + case 0x0001: + cmd = m_latch & 0x07; + switch (cmd) + { + case 0: case 1: // these do not need to be separated: we take care of them in set_chr! + case 2: case 3: case 4: case 5: + m_mmc_vrom_bank[cmd] = data; + set_chr(m_chr_source, m_chr_base, m_chr_mask); + break; + case 6: + case 7: + case 8: + case 9: + m_reg[cmd - 6] = data; + set_prg(m_prg_base, m_prg_mask); + break; + } + break; + +// case 0x2001: +// break; + + default: + waixing_write(space, offset, data, mem_mask); + break; + } +} + +/*------------------------------------------------- + + Waixing SH2 Board + + Games: Fire Emblem (C) and Fire Emblem Gaiden (C) + + MMC3 clone with different access to CHR + + iNES: mapper 165 + + In MESS: Partially Supported. + + -------------------------------------------------*/ + +void nes_waixing_sh2_device::chr_cb(int start, int bank, int source) +{ + chr4_0(m_reg[0], m_reg[0] ? CHRRAM : CHRROM); + chr4_4(m_reg[1], m_reg[1] ? CHRRAM : CHRROM); +} + +READ8_MEMBER(nes_waixing_sh2_device::chr_r) +{ + int bank = offset >> 10; + UINT8 val = m_chr_access[bank][offset & 0x3ff]; // this would be usual return value + int chr_helper; + + switch (offset & 0xff8) + { + case 0xfd0: chr_helper = (bank & 0x4) | 0x0; break; + case 0xfe8: chr_helper = (bank & 0x4) | 0x2; break; + default: return val; + } + + m_reg[offset >> 12] = chr_helper; + if (offset & 0x1000) + chr4_4(m_reg[1], m_reg[1] ? CHRRAM : CHRROM); + else + chr4_0(m_reg[0], m_reg[0] ? CHRRAM : CHRROM); + + return val; +} + +/*------------------------------------------------- + + Waixing Board with Security Chip + + Games: Duo Bao Xiao Ying Hao - Guang Ming yu An Hei Chuan Shuo, + Myth Struggle, San Shi Liu Ji, Shui Hu Zhuan + + MMC3 clone + + iNES: mapper 249 + + In MESS: Partially Supported. + + -------------------------------------------------*/ + +void nes_waixing_sec_device::prg_cb(int start, int bank) +{ + if (m_reg) + bank = BITSWAP8(bank & 0x1f,7,6,5,2,1,3,4,0); + + prg8_x(start, bank); +} + +void nes_waixing_sec_device::chr_cb(int start, int bank, int source) +{ + if (m_reg) + bank = BITSWAP8(bank, 5,4,2,6,7,3,1,0); + + chr1_x(start, bank, source); +} + +WRITE8_MEMBER(nes_waixing_sec_device::write_l) +{ + LOG_MMC(("waixing_sec write_l, offset: %04x, data: %02x\n", offset, data)); + offset += 0x100; + + if (offset == 0x1000) + { + m_reg = data & 0x02; + set_prg(m_prg_base, m_prg_mask); + set_chr(m_chr_source, m_chr_base, m_chr_mask); + } +} + +/*------------------------------------------------- + + Waixing San Guo Zhi Board + + Games: San Guo Zhi + + This board uses Konami IRQ + + iNES: mapper 252 + + In MESS: Unsupported. + + -------------------------------------------------*/ + +// same as Konami IRQ +void nes_waixing_sgz_device::hblank_irq(int scanline, int vblank, int blanked) +{ + /* Increment & check the IRQ scanline counter */ + if (m_irq_enable && (++m_irq_count == 0x100)) + { + m_irq_count = m_irq_count_latch; + m_irq_enable = m_irq_enable_latch; + m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE); + } +} + +WRITE8_MEMBER(nes_waixing_sgz_device::write_h) +{ + UINT8 helper, bank; + LOG_MMC(("waixing_sgz write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x7000) + { + case 0x0000: + prg8_89(data); + break; + case 0x2000: + prg8_ab(data); + break; + case 0x3000: + case 0x4000: + case 0x5000: + case 0x6000: + bank = ((offset & 0x7000) - 0x3000) / 0x0800 + ((offset & 0x0008) >> 3); + helper = offset & 0x04; + if (helper) + m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0x0f) | ((data & 0x0f) << 4); + else + m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0xf0) | (data & 0x0f); + chr1_x(bank, m_mmc_vrom_bank[bank], CHRROM); + break; + case 0x7000: + switch (offset & 0x0c) + { + case 0x00: + m_irq_count_latch = (m_irq_count_latch & 0xf0) | (data & 0x0f); + break; + case 0x04: + m_irq_count_latch = (m_irq_count_latch & 0x0f) | ((data & 0x0f) << 4); + break; + case 0x08: + m_irq_enable = data & 0x02; + m_irq_count_latch = data & 0x01; + if (data & 0x02) + m_irq_count = m_irq_count_latch; + break; + case 0x0c: + m_irq_enable = m_irq_enable_latch; + break; + } + break; + } +} + + +/*------------------------------------------------- + + Waixing San Guo Zhong Lie Zhuan Board + + Games: Fan Kong Jing Ying, San Guo Zhong Lie Zhuan, Xing + Ji Zheng Ba + + iNES: mapper 178 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_waixing_sgzlz_device::write_l) +{ + LOG_MMC(("waixing_sgzlz write_l, offset: %04x, data: %02x\n", offset, data)); + + switch (offset) + { + case 0x700: + set_nt_mirroring(data ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + break; + case 0x701: + m_latch = (m_latch & 0x0c) | ((data >> 1) & 0x03); + prg32(m_latch); + break; + case 0x702: + m_latch = (m_latch & 0x03) | ((data << 2) & 0x0c); + break; + } +} + +/*------------------------------------------------- + + Waixing Final Fantasy V Board + + Games: Darkseed, Digital Dragon, Final Fantasy V, Pocket + Monster Red + + iNES: mapper 164 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_waixing_ffv_device::write_l) +{ + UINT8 helper; + LOG_MMC(("waixing_ffv write_l, offset: %04x, data: %02x\n", offset, data)); + offset += 0x100; /* the checks work better on addresses */ + + if ((offset & 0x1200) == 0x1000) + { + m_reg[BIT(offset, 8)] = data; + helper = BIT(m_reg[1], 0) << 5; + switch (m_reg[0] & 0x70) + { + case 0x00: + case 0x20: + case 0x40: + case 0x60: + prg16_89ab(helper | ((m_reg[0] >> 1) & 0x10) | (m_reg[0] & 0x0f)); + prg16_cdef(helper & 0x1f); + break; + case 0x50: + prg32((helper >> 1) | (m_reg[0] & 0x0f)); + break; + case 0x70: + prg16_89ab(helper | ((m_reg[0] << 1) & 0x10) | (m_reg[0] & 0x0f)); + prg16_cdef(helper & 0x1f); + break; + } + } +} + +/*------------------------------------------------- + + Waixing Zhan Shi Board + + Games: Wai Xing Zhan Shi + + Simple mapper: writes to 0x8000-0xffff sets prg32 banks to + (offset>>3)&f. written data&3 sets the mirroring (with + switched high/low compared to the standard one). + + A crc check is required to support Dragon Quest VIII (which + uses a slightly different board) + + iNES: mapper 242 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_waixing_wxzs_device::write_h) +{ + LOG_MMC(("waixing_zs write_h, offset: %04x, data: %02x\n", offset, data)); + + prg32(offset >> 3); + + switch (data & 0x03) + { + case 0: set_nt_mirroring(PPU_MIRROR_VERT); break; + case 1: set_nt_mirroring(PPU_MIRROR_HORZ); break; + case 2: set_nt_mirroring(PPU_MIRROR_LOW); break; + case 3: set_nt_mirroring(PPU_MIRROR_HIGH); break; + } +} + +/*------------------------------------------------- + + Waixing Dragon Quest VIII Board + + Games: Dragon Quest VIII + + Simple mapper: writes to 0x8000-0xffff sets prg32 banks to + (offset>>3)&f. + + iNES: mapper 242 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_waixing_dq8_device::write_h) +{ + LOG_MMC(("waixing_dq8 write_h, offset: %04x, data: %02x\n", offset, data)); + + prg32(offset >> 3); +} + + +/*------------------------------------------------- + + Waixing WXZS2 / PS2 board + + Games: Wai Xing Zhan Shi 2 (aka Phantasy Star 2), + Bao Xiao Tien Guo, Bio Hazard, Pokemon Gold, Subor (R) + + iNES: mapper 15 + + In MESS: Supported + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_waixing_wxzs2_device::write_h) +{ + UINT8 flip = (data & 0x80) >> 7; + UINT8 helper = (data & 0x7f) << 1; + + LOG_MMC(("waixing_wxzs2 write_h, offset: %04x, data: %02x\n", offset, data)); + + set_nt_mirroring(BIT(data, 6) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + + switch (offset & 0x0fff) + { + case 0x000: + prg8_89((helper + 0) ^ flip); + prg8_ab((helper + 1) ^ flip); + prg8_cd((helper + 2) ^ flip); + prg8_ef((helper + 3) ^ flip); + break; + case 0x001: + helper |= flip; + prg8_89(helper); + prg8_ab(helper + 1); + prg8_cd(helper + 1); + prg8_ef(helper + 1); + break; + case 0x002: + helper |= flip; + prg8_89(helper); + prg8_ab(helper); + prg8_cd(helper); + prg8_ef(helper); + break; + case 0x003: + helper |= flip; + prg8_89(helper); + prg8_ab(helper + 1); + prg8_cd(helper); + prg8_ef(helper + 1); + break; + } +} + +/*------------------------------------------------- + + Board UNL-FS304 + + Games: A Link to the Past by Waixing + + iNES: mapper 162? (only found in UNIF format) + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_waixing_fs304_device::write_l) +{ + LOG_MMC(("fs304 write_l, offset: %04x, data: %02x\n", offset, data)); + int bank; + offset += 0x100; + + if (offset >= 0x1000) + { + m_reg[(offset >> 8) & 3] = data; + bank = ((m_reg[2] & 0x0f) << 4) | BIT(m_reg[1], 1) | (m_reg[0] & 0x0e); + prg32(bank); + chr8(0, CHRRAM); + } +} -- cgit v1.2.3-70-g09d2