summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/bus/nes/bandai.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/bus/nes/bandai.cpp')
-rw-r--r--src/devices/bus/nes/bandai.cpp479
1 files changed, 479 insertions, 0 deletions
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<nes_oekakids_device>;
+const device_type NES_FCG = &device_creator<nes_fcg_device>;
+const device_type NES_LZ93D50 = &device_creator<nes_lz93d50_device>;
+const device_type NES_LZ93D50_24C01 = &device_creator<nes_lz93d50_24c01_device>;
+const device_type NES_LZ93D50_24C02 = &device_creator<nes_lz93d50_24c02_device>;
+const device_type NES_FJUMP2 = &device_creator<nes_fjump2_device>;
+
+
+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<cpu_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<cpu_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<cpu_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;
+ }
+}