summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/bus/megadrive/rom.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/bus/megadrive/rom.c')
-rw-r--r--src/devices/bus/megadrive/rom.c1422
1 files changed, 1422 insertions, 0 deletions
diff --git a/src/devices/bus/megadrive/rom.c b/src/devices/bus/megadrive/rom.c
new file mode 100644
index 00000000000..bc81477cc09
--- /dev/null
+++ b/src/devices/bus/megadrive/rom.c
@@ -0,0 +1,1422 @@
+// license:BSD-3-Clause
+// copyright-holders:Fabio Priuli
+/***********************************************************************************************************
+
+
+ MegaDrive / Genesis cart emulation
+
+
+ Here we emulate bankswitch / protection / NVRAM found on generic carts with no additional hardware
+
+
+ Emulation of the pirate carts is heavily indebted to the reverse engineering efforts made
+ by David Haywood (for HazeMD) and by EkeEke (for genplus-gx)
+
+ ***********************************************************************************************************/
+
+#include "emu.h"
+#include "rom.h"
+#include "cpu/m68000/m68000.h"
+
+
+//-------------------------------------------------
+// md_rom_device - constructor
+//-------------------------------------------------
+
+// BASE CARTS + NVRAM
+const device_type MD_STD_ROM = &device_creator<md_std_rom_device>;
+const device_type MD_ROM_SRAM = &device_creator<md_rom_sram_device>;
+const device_type MD_ROM_FRAM = &device_creator<md_rom_fram_device>;
+
+// BASE CARTS + BANKSWITCH AT RESET
+const device_type MD_ROM_CM2IN1 = &device_creator<md_rom_cm2in1_device>;
+
+// BASE CARTS + PROTECTION / BANKSWITCH
+const device_type MD_ROM_SSF2 = &device_creator<md_rom_ssf2_device>;
+const device_type MD_ROM_BUGSLIFE = &device_creator<md_rom_bugslife_device>;
+const device_type MD_ROM_SMOUSE = &device_creator<md_rom_smouse_device>;
+const device_type MD_ROM_SMW64 = &device_creator<md_rom_smw64_device>;
+const device_type MD_ROM_SMB = &device_creator<md_rom_smb_device>;
+const device_type MD_ROM_SMB2 = &device_creator<md_rom_smb2_device>;
+const device_type MD_ROM_SBUBL = &device_creator<md_rom_sbubl_device>;
+const device_type MD_ROM_RX3 = &device_creator<md_rom_rx3_device>;
+const device_type MD_ROM_MJLOV = &device_creator<md_rom_mjlov_device>;
+const device_type MD_ROM_KOF98 = &device_creator<md_rom_kof98_device>;
+const device_type MD_ROM_KOF99 = &device_creator<md_rom_kof99_device>;
+const device_type MD_ROM_SOULB = &device_creator<md_rom_soulb_device>;
+const device_type MD_ROM_CHINF3 = &device_creator<md_rom_chinf3_device>;
+const device_type MD_ROM_16MJ2 = &device_creator<md_rom_16mj2_device>;
+const device_type MD_ROM_ELFWOR = &device_creator<md_rom_elfwor_device>;
+const device_type MD_ROM_YASECH = &device_creator<md_rom_yasech_device>;
+const device_type MD_ROM_LION2 = &device_creator<md_rom_lion2_device>;
+const device_type MD_ROM_LION3 = &device_creator<md_rom_lion3_device>;
+const device_type MD_ROM_MCPIR = &device_creator<md_rom_mcpirate_device>;
+const device_type MD_ROM_POKEA = &device_creator<md_rom_pokea_device>;
+const device_type MD_ROM_POKESTAD = &device_creator<md_rom_pokestad_device>;
+const device_type MD_ROM_REALTEC = &device_creator<md_rom_realtec_device>;
+const device_type MD_ROM_REDCL = &device_creator<md_rom_redcl_device>;
+const device_type MD_ROM_SQUIR = &device_creator<md_rom_squir_device>;
+const device_type MD_ROM_TEKKENSP = &device_creator<md_rom_tekkensp_device>;
+const device_type MD_ROM_TOPF = &device_creator<md_rom_topf_device>;
+const device_type MD_ROM_RADICA = &device_creator<md_rom_radica_device>;
+const device_type MD_ROM_BEGGARP = &device_creator<md_rom_beggarp_device>;
+const device_type MD_ROM_WUKONG = &device_creator<md_rom_wukong_device>;
+
+
+md_std_rom_device::md_std_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),
+ device_md_cart_interface( mconfig, *this )
+{
+}
+
+md_std_rom_device::md_std_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, MD_STD_ROM, "MD Standard cart", tag, owner, clock, "md_std_rom", __FILE__),
+ device_md_cart_interface( mconfig, *this )
+{
+}
+
+md_rom_sram_device::md_rom_sram_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : md_std_rom_device(mconfig, MD_ROM_SRAM, "MD Standard cart + SRAM", tag, owner, clock, "md_rom_sram", __FILE__)
+{
+}
+
+md_rom_fram_device::md_rom_fram_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : md_std_rom_device(mconfig, MD_ROM_FRAM, "MD Standard cart + FRAM", tag, owner, clock, "md_rom_fram", __FILE__)
+{
+}
+
+md_rom_ssf2_device::md_rom_ssf2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : md_std_rom_device(mconfig, MD_ROM_SSF2, "MD Super SF2", tag, owner, clock, "md_rom_ssf2", __FILE__)
+{
+}
+
+md_rom_cm2in1_device::md_rom_cm2in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : md_std_rom_device(mconfig, MD_ROM_CM2IN1, "MD Codemasters 2in1", tag, owner, clock, "md_rom_cm2in1", __FILE__)
+{
+}
+
+md_rom_mcpirate_device::md_rom_mcpirate_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : md_std_rom_device(mconfig, MD_ROM_MCPIR, "MD Pirate Multicarts (Various)", tag, owner, clock, "md_rom_mcpirate", __FILE__)
+{
+}
+
+md_rom_bugslife_device::md_rom_bugslife_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : md_std_rom_device(mconfig, MD_ROM_BUGSLIFE, "MD A Bug's Life", tag, owner, clock, "md_rom_bugslife", __FILE__)
+{
+}
+
+md_rom_smouse_device::md_rom_smouse_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : md_std_rom_device(mconfig, MD_ROM_SMOUSE, "MD Huan Le Tao Qi Shu / Smart Mouse", tag, owner, clock, "md_rom_smouse", __FILE__)
+{
+}
+
+md_rom_smb_device::md_rom_smb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : md_std_rom_device(mconfig, MD_ROM_SMB, "MD Super Mario Bros.", tag, owner, clock, "md_rom_smb", __FILE__)
+{
+}
+
+md_rom_smb2_device::md_rom_smb2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : md_std_rom_device(mconfig, MD_ROM_SMB2, "MD Super Mario Bros. 2", tag, owner, clock, "md_rom_smb2", __FILE__)
+{
+}
+
+md_rom_smw64_device::md_rom_smw64_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : md_std_rom_device(mconfig, MD_ROM_SMW64, "MD Super Mario World 64", tag, owner, clock, "md_rom_smw64", __FILE__)
+{
+}
+
+md_rom_sbubl_device::md_rom_sbubl_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : md_std_rom_device(mconfig, MD_ROM_SBUBL, "MD Super Bubble Bobble", tag, owner, clock, "md_rom_sbubl", __FILE__)
+{
+}
+
+md_rom_rx3_device::md_rom_rx3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : md_std_rom_device(mconfig, MD_ROM_RX3, "MD Rockman X3", tag, owner, clock, "md_rom_rx3", __FILE__)
+{
+}
+
+md_rom_mjlov_device::md_rom_mjlov_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : md_std_rom_device(mconfig, MD_ROM_MJLOV, "MD Ma Jiang Qing Ren / Mahjong Lover", tag, owner, clock, "md_rom_mjlov", __FILE__)
+{
+}
+
+md_rom_kof98_device::md_rom_kof98_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : md_std_rom_device(mconfig, MD_ROM_KOF98, "MD KOF 98", tag, owner, clock, "md_rom_kof98", __FILE__)
+{
+}
+
+md_rom_kof99_device::md_rom_kof99_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : md_std_rom_device(mconfig, MD_ROM_KOF99, "MD KOF 99 (and others)", tag, owner, clock, "md_rom_kof99", __FILE__)
+{
+}
+
+md_rom_soulb_device::md_rom_soulb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : md_std_rom_device(mconfig, MD_ROM_SOULB, "MD Soul Blade", tag, owner, clock, "md_rom_soulb", __FILE__)
+{
+}
+
+md_rom_chinf3_device::md_rom_chinf3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : md_std_rom_device(mconfig, MD_ROM_CHINF3, "MD Chinese Fighter 3", tag, owner, clock, "md_rom_chinf3", __FILE__)
+{
+}
+
+md_rom_16mj2_device::md_rom_16mj2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : md_std_rom_device(mconfig, MD_ROM_16MJ2, "MD 16 Mahjong Tiles II", tag, owner, clock, "md_rom_16mj2", __FILE__)
+{
+}
+
+md_rom_elfwor_device::md_rom_elfwor_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : md_std_rom_device(mconfig, MD_ROM_ELFWOR, "MD Linghuan Daoshi Super Magician / Elf Wor", tag, owner, clock, "md_rom_elfwor", __FILE__)
+{
+}
+
+md_rom_yasech_device::md_rom_yasech_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : md_std_rom_device(mconfig, MD_ROM_YASECH, "MD Ya Se Chuan Shuo", tag, owner, clock, "md_rom_yasech", __FILE__)
+{
+}
+
+md_rom_lion2_device::md_rom_lion2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : md_std_rom_device(mconfig, MD_ROM_LION2, "MD Lion King 2", tag, owner, clock, "md_rom_lion2", __FILE__)
+{
+}
+
+md_rom_lion3_device::md_rom_lion3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : md_std_rom_device(mconfig, MD_ROM_LION3, "MD Lion King 3", tag, owner, clock, "md_rom_lion3", __FILE__)
+{
+}
+
+md_rom_pokea_device::md_rom_pokea_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : md_std_rom_device(mconfig, MD_ROM_POKEA, "MD Pokemon (Alt Protection)", tag, owner, clock, "md_rom_pokea", __FILE__)
+{
+}
+
+md_rom_pokestad_device::md_rom_pokestad_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : md_std_rom_device(mconfig, MD_ROM_POKESTAD, "MD Pokemon Stadium", tag, owner, clock, "md_rom_pokestad", __FILE__)
+{
+}
+
+md_rom_realtec_device::md_rom_realtec_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : md_std_rom_device(mconfig, MD_ROM_REALTEC, "MD Realtec", tag, owner, clock, "md_rom_realtec", __FILE__)
+{
+}
+
+md_rom_redcl_device::md_rom_redcl_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : md_std_rom_device(mconfig, MD_ROM_REDCL, "MD Redcliff", tag, owner, clock, "md_rom_redcl", __FILE__)
+{
+}
+
+md_rom_squir_device::md_rom_squir_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : md_std_rom_device(mconfig, MD_ROM_SQUIR, "MD Squirrel King", tag, owner, clock, "md_rom_squir", __FILE__)
+{
+}
+
+md_rom_tekkensp_device::md_rom_tekkensp_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : md_std_rom_device(mconfig, MD_ROM_TEKKENSP, "MD Tekken Special", tag, owner, clock, "md_rom_tekkensp", __FILE__)
+{
+}
+
+md_rom_topf_device::md_rom_topf_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : md_std_rom_device(mconfig, MD_ROM_TOPF, "MD Top Fighter", tag, owner, clock, "md_rom_topf", __FILE__)
+{
+}
+
+md_rom_radica_device::md_rom_radica_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : md_std_rom_device(mconfig, MD_ROM_RADICA, "MD Radica TV games", tag, owner, clock, "md_rom_radica", __FILE__)
+{
+}
+
+md_rom_beggarp_device::md_rom_beggarp_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : md_std_rom_device(mconfig, MD_ROM_BEGGARP, "MD Beggar Prince", tag, owner, clock, "md_rom_beggarp", __FILE__)
+{
+}
+
+md_rom_wukong_device::md_rom_wukong_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : md_std_rom_device(mconfig, MD_ROM_WUKONG, "MD Legend of Wukong", tag, owner, clock, "md_rom_wukong", __FILE__)
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void md_rom_ssf2_device::device_start()
+{
+ save_item(NAME(m_bank));
+ save_item(NAME(m_lastoff));
+ save_item(NAME(m_lastdata));
+}
+
+void md_rom_ssf2_device::device_reset()
+{
+ for (int i = 0; i < 7; i++)
+ m_bank[i] = i;
+ m_lastoff = -1;
+ m_lastdata = -1;
+}
+
+void md_rom_cm2in1_device::device_start()
+{
+ m_base = -1;
+ save_item(NAME(m_base));
+}
+
+void md_rom_cm2in1_device::device_reset()
+{
+ m_base++;
+ m_base &= 1;
+}
+
+void md_rom_mcpirate_device::device_start()
+{
+ save_item(NAME(m_bank));
+}
+
+void md_rom_mcpirate_device::device_reset()
+{
+ m_bank = 0;
+}
+
+void md_rom_chinf3_device::device_start()
+{
+ m_bank = 0;
+ save_item(NAME(m_bank));
+}
+
+void md_rom_chinf3_device::device_reset()
+{
+}
+
+void md_rom_lion2_device::device_start()
+{
+ save_item(NAME(m_prot1_data));
+ save_item(NAME(m_prot2_data));
+}
+
+void md_rom_lion2_device::device_reset()
+{
+ m_prot1_data = 0;
+ m_prot2_data = 0;
+}
+
+void md_rom_lion3_device::device_start()
+{
+ save_item(NAME(m_reg));
+ save_item(NAME(m_bank));
+}
+
+void md_rom_lion3_device::device_reset()
+{
+ m_reg[0] = 0;
+ m_reg[1] = 0;
+ m_reg[2] = 0;
+ m_bank = 0;
+}
+
+void md_rom_pokestad_device::device_start()
+{
+ save_item(NAME(m_bank));
+}
+
+void md_rom_pokestad_device::device_reset()
+{
+ m_bank = 0;
+}
+
+void md_rom_realtec_device::device_start()
+{
+ save_item(NAME(m_bank_addr));
+ save_item(NAME(m_bank_size));
+ save_item(NAME(m_old_bank_addr));
+}
+
+void md_rom_realtec_device::device_reset()
+{
+ m_bank_addr = 0;
+ m_bank_size = 0;
+ m_old_bank_addr = -1;
+}
+
+void md_rom_squir_device::device_start()
+{
+ save_item(NAME(m_latch));
+}
+
+void md_rom_squir_device::device_reset()
+{
+ m_latch = 0;
+}
+
+void md_rom_smw64_device::device_start()
+{
+ save_item(NAME(m_latch0));
+ save_item(NAME(m_latch1));
+ save_item(NAME(m_reg));
+ save_item(NAME(m_ctrl));
+}
+
+void md_rom_smw64_device::device_reset()
+{
+ m_latch0 = 0xf;
+ m_latch1 = 0xf;
+ memset(m_reg, 0, sizeof(m_reg));
+ memset(m_ctrl, 0, sizeof(m_ctrl));
+}
+
+void md_rom_tekkensp_device::device_start()
+{
+ save_item(NAME(m_reg));
+}
+
+void md_rom_tekkensp_device::device_reset()
+{
+ m_reg = 0;
+}
+
+void md_rom_topf_device::device_start()
+{
+ save_item(NAME(m_latch));
+ save_item(NAME(m_bank));
+}
+
+void md_rom_topf_device::device_reset()
+{
+ m_latch = 0;
+ m_bank[0] = m_bank[1] = m_bank[2] = 0;
+}
+
+void md_rom_radica_device::device_start()
+{
+ save_item(NAME(m_bank));
+}
+
+void md_rom_radica_device::device_reset()
+{
+ m_bank = 0;
+}
+
+void md_rom_beggarp_device::device_start()
+{
+ save_item(NAME(m_mode));
+ save_item(NAME(m_lock));
+}
+
+void md_rom_beggarp_device::device_reset()
+{
+ m_mode = 0;
+ m_lock = 0;
+}
+
+void md_rom_wukong_device::device_start()
+{
+ save_item(NAME(m_mode));
+}
+
+void md_rom_wukong_device::device_reset()
+{
+ m_mode = 0;
+}
+
+/*-------------------------------------------------
+ mapper specific handlers
+ -------------------------------------------------*/
+
+/*-------------------------------------------------
+ CART + SRAM
+ -------------------------------------------------*/
+
+READ16_MEMBER(md_rom_sram_device::read)
+{
+ // since a lot of generic carts ends up here if loaded from fullpath
+ // we access nvram only if m_nvram_handlers_installed has been turned on
+ if (m_nvram_handlers_installed)
+ {
+ if (offset >= m_nvram_start/2 && offset <= m_nvram_end/2 && m_nvram_active)
+ return m_nvram[offset - m_nvram_start/2];
+ }
+ if (offset < 0x400000/2)
+ return m_rom[MD_ADDR(offset)];
+ else
+ return 0xffff;
+}
+
+WRITE16_MEMBER(md_rom_sram_device::write)
+{
+ // since a lot of generic carts ends up here if loaded from fullpath
+ // we access nvram only if m_nvram_handlers_installed has been turned on
+ if (m_nvram_handlers_installed)
+ {
+ if (offset >= m_nvram_start/2 && offset <= m_nvram_end/2 && m_nvram_active && !m_nvram_readonly)
+ m_nvram[offset - m_nvram_start/2] = data;
+ }
+}
+
+WRITE16_MEMBER(md_rom_sram_device::write_a13)
+{
+ if (offset == 0xf0/2)
+ {
+ /* unsure if this is actually supposed to toggle or just switch on? yet to encounter game that uses this */
+ m_nvram_active = BIT(data, 0);
+ m_nvram_readonly = BIT(data, 1);
+
+ // since a lot of generic carts ends up here if loaded from fullpath
+ // we turn on nvram (with m_nvram_handlers_installed) only if they toggle it on by writing here!
+ if (m_nvram_active && !m_nvram_handlers_installed)
+ m_nvram_handlers_installed = 1;
+ }
+}
+
+/*-------------------------------------------------
+ CART + FRAM [almost same as SRAM... merge common parts?]
+ -------------------------------------------------*/
+
+READ16_MEMBER(md_rom_fram_device::read)
+{
+ if (offset >= m_nvram_start/2 && offset <= m_nvram_end/2 && m_nvram_active)
+ return m_nvram[offset - m_nvram_start/2];
+ if (offset < 0x400000/2)
+ return m_rom[MD_ADDR(offset)];
+ else
+ return 0xffff;
+}
+
+WRITE16_MEMBER(md_rom_fram_device::write)
+{
+ if (offset >= m_nvram_start/2 && offset <= m_nvram_end/2 && m_nvram_active)
+ m_nvram[offset - m_nvram_start/2] = data;
+}
+
+WRITE16_MEMBER(md_rom_fram_device::write_a13)
+{
+ if (offset == 0xf0/2)
+ m_nvram_active = BIT(data, 0);
+}
+
+
+READ16_MEMBER(md_rom_fram_device::read_a13)
+{
+ if (offset == 0xf0/2)
+ return m_nvram_active;
+ else
+ return 0xffff;
+}
+
+/*-------------------------------------------------
+ SUPER STREET FIGHTERS 2
+ -------------------------------------------------*/
+
+READ16_MEMBER(md_rom_ssf2_device::read)
+{
+ if (offset < 0x400000/2)
+ return m_rom[offset];
+ else
+ return 0xffff;
+}
+
+// I'm not very fond of the code below...
+WRITE16_MEMBER(md_rom_ssf2_device::write_a13)
+{
+ if (offset >= 0xf0/2)
+ {
+ offset -= 0xf0/2;
+ if ((m_lastoff != offset) || (m_lastdata != data))
+ {
+ m_lastoff = offset;
+ m_lastdata = data;
+ if (offset) // bank 0 is not modified
+ {
+ UINT16 *ROM = get_rom_base();
+ m_bank[offset] = data & 0xf;
+ memcpy(ROM + offset * 0x080000/2, ROM + 0x400000/2 + (m_bank[offset] * 0x080000)/2, 0x080000);
+ }
+ }
+ }
+}
+
+/*-------------------------------------------------
+ CODEMASTERS 2 IN 1 (RESET BASED)
+ -------------------------------------------------*/
+
+#define MD_ADDR_CM2IN1(a) (m_base == 0 ? ((a << 1) & 0x1fffff)/2 : (((a << 1) & 0x1fffff) + 0x200000)/2)
+
+READ16_MEMBER(md_rom_cm2in1_device::read)
+{
+ if (offset < 0x400000/2)
+ return m_rom[MD_ADDR_CM2IN1(offset)];
+ else
+ return 0xffff;
+}
+
+
+/*-------------------------------------------------
+ PIRATE MULTICARTS
+ -------------------------------------------------*/
+
+READ16_MEMBER(md_rom_mcpirate_device::read)
+{
+ if (offset < 0x400000/2)
+ return m_rom[(((m_bank * 0x10000) + (offset << 1)) & (m_rom_size - 1))/2];
+ else
+ return read(space, offset - 0x400000/2, 0xffff);
+}
+
+WRITE16_MEMBER(md_rom_mcpirate_device::write_a13)
+{
+ offset <<= 1;
+ if (offset < 0x40)
+ m_bank = offset;
+}
+
+/*-------------------------------------------------
+ A BUG'S LIFE
+ -------------------------------------------------*/
+
+READ16_MEMBER(md_rom_bugslife_device::read_a13)
+{
+ if (offset == 0x00/2) return 0x28;
+ if (offset == 0x02/2) return 0x01;
+ if (offset == 0x3e/2) return 0x1f;
+ else return 0xffff;
+}
+
+/*-------------------------------------------------
+ CHINESE FIGHTER 3
+ -------------------------------------------------*/
+
+READ16_MEMBER(md_rom_chinf3_device::read)
+{
+ if (offset < 0x100000/2)
+ {
+ if (!m_bank)
+ return m_rom[offset & 0xfffff/2];
+ else
+ return m_rom[(offset & 0xffff/2) + (m_bank * 0x10000)/2];
+ }
+
+ // PROTECTION in 0x400000 - 0x4fffff
+ /* not 100% correct, there may be some relationship between the reads here
+ and the writes made at the start of the game.. */
+ if (offset >= 0x400000/2 && offset < 0x500000/2)
+ {
+ UINT32 retdat = 0;
+ /*
+ 04dc10 chifi3, prot_r? 2800
+ 04cefa chifi3, prot_r? 65262
+ */
+ if (space.machine().device("maincpu")->safe_pc() == 0x01782) // makes 'VS' screen appear
+ {
+ retdat = space.machine().device("maincpu")->state().state_int(M68K_D3) & 0xff;
+ retdat <<= 8;
+ return retdat;
+ }
+ else if (space.machine().device("maincpu")->safe_pc() == 0x1c24) // background gfx etc.
+ {
+ retdat = space.machine().device("maincpu")->state().state_int(M68K_D3) & 0xff;
+ retdat <<= 8;
+ return retdat;
+ }
+ else if (space.machine().device("maincpu")->safe_pc() == 0x10c4a) // unknown
+ {
+ return space.machine().rand();
+ }
+ else if (space.machine().device("maincpu")->safe_pc() == 0x10c50) // unknown
+ {
+ return space.machine().rand();
+ }
+ else if (space.machine().device("maincpu")->safe_pc() == 0x10c52) // relates to the game speed..
+ {
+ retdat = space.machine().device("maincpu")->state().state_int(M68K_D4) & 0xff;
+ retdat <<= 8;
+ return retdat;
+ }
+ else if (space.machine().device("maincpu")->safe_pc() == 0x061ae)
+ {
+ retdat = space.machine().device("maincpu")->state().state_int(M68K_D3) & 0xff;
+ retdat <<= 8;
+ return retdat;
+ }
+ else if (space.machine().device("maincpu")->safe_pc() == 0x061b0)
+ {
+ retdat = space.machine().device("maincpu")->state().state_int(M68K_D3) & 0xff;
+ retdat <<= 8;
+ return retdat;
+ }
+ else
+ {
+ logerror("%06x chifi3, prot_r? %04x\n", space.machine().device("maincpu")->safe_pc(), offset);
+ }
+ return 0;
+ }
+
+ // non-protection accesses
+ if (offset < 0x400000/2)
+ return m_rom[MD_ADDR(offset)];
+ else
+ return 0xffff;
+}
+
+WRITE16_MEMBER(md_rom_chinf3_device::write)
+{
+ if (offset >= 0x600000/2 && offset < 0x700000/2)
+ {
+ if (data == 0xf100) // *hit player
+ m_bank = 1;
+ else if (data == 0xd700) // title screen..
+ m_bank = 7;
+ else if (data == 0xd300) // character hits floor
+ m_bank = 3;
+ else if (data == 0x0000)
+ m_bank = 0;
+ else
+ logerror("%06x chifi3, bankw? %04x %04x\n", space.device().safe_pc(), offset, data);
+ }
+}
+
+/*-------------------------------------------------
+ 16 MAHJONG II
+ -------------------------------------------------*/
+
+READ16_MEMBER(md_rom_16mj2_device::read)
+{
+ if (offset == 0x400004/2) return 0xc900;
+
+ // non-protection accesses
+ if (offset < 0x400000/2)
+ return m_rom[MD_ADDR(offset)];
+ else
+ return 0xffff;
+}
+
+/*-------------------------------------------------
+ LINGHUAN DAOSHI SUPER MAGICIAN / ELF WOR
+ -------------------------------------------------*/
+
+READ16_MEMBER(md_rom_elfwor_device::read)
+{
+ // It returns (0x55 @ 0x400000 OR 0xc9 @ 0x400004) AND (0x0f @ 0x400002 OR 0x18 @ 0x400006).
+ // It is probably best to add handlers for all 4 addresses
+ if (offset == 0x400000/2) return 0x5500;
+ if (offset == 0x400002/2) return 0x0f00;
+ if (offset == 0x400004/2) return 0xc900;
+ if (offset == 0x400006/2) return 0x1800;
+
+ // non-protection accesses
+ if (offset < 0x400000/2)
+ return m_rom[MD_ADDR(offset)];
+ else
+ return 0xffff;
+}
+
+/*-------------------------------------------------
+ HUAN LE TAO QI SHU / SMART MOUSE
+ -------------------------------------------------*/
+
+READ16_MEMBER(md_rom_smouse_device::read)
+{
+ if (offset == 0x400000/2) return 0x5500;
+ if (offset == 0x400002/2) return 0x0f00;
+ if (offset == 0x400004/2) return 0xaa00;
+ if (offset == 0x400006/2) return 0xf000;
+
+ // non-protection accesses
+ if (offset < 0x400000/2)
+ return m_rom[MD_ADDR(offset)];
+ else
+ return 0xffff;
+}
+
+/*-------------------------------------------------
+ YA SE CHUAN SHUO
+ -------------------------------------------------*/
+
+READ16_MEMBER(md_rom_yasech_device::read)
+{
+ if (offset == 0x400000/2) return 0x6300;
+ if (offset == 0x400002/2) return 0x9800;
+ if (offset == 0x400004/2) return 0xc900;
+ if (offset == 0x400006/2) return 0x1800;
+
+ // non-protection accesses
+ if (offset < 0x400000/2)
+ return m_rom[MD_ADDR(offset)];
+ else
+ return 0xffff;
+}
+
+/*-------------------------------------------------
+ KOF98
+ -------------------------------------------------*/
+
+READ16_MEMBER(md_rom_kof98_device::read)
+{
+ if (offset == 0x480000/2) return 0xaa00;
+ if (offset == 0x4800e0/2) return 0xaa00;
+ if (offset == 0x4824a0/2) return 0xaa00;
+ if (offset == 0x488880/2) return 0xaa00;
+ if (offset == 0x4a8820/2) return 0x0a00;
+ if (offset == 0x4f8820/2) return 0x0000;
+
+ // non-protection accesses
+ if (offset < 0x400000/2)
+ return m_rom[MD_ADDR(offset)];
+ else
+ return 0xffff;
+}
+
+/*-------------------------------------------------
+ KOF 99
+ -------------------------------------------------*/
+
+READ16_MEMBER(md_rom_kof99_device::read_a13)
+{
+ if (offset == 0x00/2) return 0x00; // startup protection check, chinese message if != 0
+ if (offset == 0x02/2) return 0x01; // write 02 to a13002.. shift right 1?
+ if (offset == 0x3e/2) return 0x1f; // write 3e to a1303e.. shift right 1?
+ else return 0xffff;
+}
+
+/*-------------------------------------------------
+ LION KING 2
+ -------------------------------------------------*/
+
+READ16_MEMBER(md_rom_lion2_device::read)
+{
+ if (offset == 0x400002/2) return m_prot1_data;
+ if (offset == 0x400006/2) return m_prot2_data;
+
+ // non-protection accesses
+ if (offset < 0x400000/2)
+ return m_rom[MD_ADDR(offset)];
+ else
+ return 0xffff;
+}
+
+WRITE16_MEMBER(md_rom_lion2_device::write)
+{
+ if (offset == 0x400000/2) m_prot1_data = data;
+ if (offset == 0x400004/2) m_prot2_data = data;
+}
+
+/*-------------------------------------------------
+ LION KING 3
+ -------------------------------------------------*/
+
+#define MD_LION3_ADDR(a) (((offset << 1) | (m_bank << 15)) & (m_rom_size - 1))/2
+
+READ16_MEMBER(md_rom_lion3_device::read)
+{
+ if (offset < 0x100000/2)
+ return m_rom[MD_LION3_ADDR(offset)];
+ else if (offset >= 0x600000/2 && offset < 0x700000/2)
+ {
+ switch (offset & 0x7)
+ {
+ case 0:
+ return m_reg[0];
+ case 1:
+ return m_reg[1];
+ case 2:
+ return m_reg[2];
+ default:
+ logerror("protection read, unknown offset %x\n", offset & 0x7);
+ break;
+ }
+ return 0;
+ }
+
+ if (offset < 0x400000/2)
+ return m_rom[MD_ADDR(offset)];
+ else
+ return 0xffff;
+}
+
+WRITE16_MEMBER(md_rom_lion3_device::write)
+{
+ if (offset >= 0x600000/2 && offset < 0x700000/2)
+ {
+// printf("protection write, offset %d data %d\n", offset & 0x7, data);
+ switch (offset & 0x7)
+ {
+ case 0x0:
+ m_reg[0] = data & 0xff;
+ break;
+ case 0x1:
+ m_reg[1] = data & 0xff;
+ break;
+ default:
+ logerror("protection write, unknown offset %d\n", offset & 0x7);
+ break;
+ }
+
+ // update m_reg[2]
+ switch (m_reg[1] & 3)
+ {
+ case 0x0:
+ m_reg[2] = (m_reg[0] << 1);
+ break;
+ case 0x1:
+ m_reg[2] = (m_reg[0] >> 1);
+ break;
+ case 0x2:
+ m_reg[2] = (m_reg[0] >> 4) | ((m_reg[0] & 0x0f) << 4);
+ break;
+ case 0x3:
+ default:
+ m_reg[2] = (BIT(m_reg[0], 7) << 0)
+ | (BIT(m_reg[0], 6) << 1)
+ | (BIT(m_reg[0], 5) << 2)
+ | (BIT(m_reg[0], 4) << 3)
+ | (BIT(m_reg[0], 3) << 4)
+ | (BIT(m_reg[0], 2) << 5)
+ | (BIT(m_reg[0], 1) << 6)
+ | (BIT(m_reg[0], 0) << 7);
+ break;
+ }
+
+ }
+ if (offset >= 0x700000/2)
+ m_bank = data & 0xff;
+}
+
+/*-------------------------------------------------
+ MA JIANG QING REN / MAHJONG LOVER
+ -------------------------------------------------*/
+
+READ16_MEMBER(md_rom_mjlov_device::read)
+{
+ if (offset == 0x400000/2) return 0x9000;
+ if (offset == 0x401000/2) return 0xd300;
+
+ // non-protection accesses
+ if (offset < 0x400000/2)
+ return m_rom[MD_ADDR(offset)];
+ else
+ return 0xffff;
+}
+
+
+/*-------------------------------------------------
+ SUPER BUBBLE BOBBLE MD
+ -------------------------------------------------*/
+
+READ16_MEMBER(md_rom_sbubl_device::read)
+{
+ if (offset == 0x400000/2) return 0x5500;
+ if (offset == 0x400002/2) return 0x0f00;
+
+ // non-protection accesses
+ if (offset < 0x400000/2)
+ return m_rom[MD_ADDR(offset)];
+ else
+ return 0xffff;
+}
+
+/*-------------------------------------------------
+ SOUL BLADE
+ -------------------------------------------------*/
+
+READ16_MEMBER(md_rom_soulb_device::read)
+{
+ if (offset == 0x400002/2) return 0x9800;
+ if (offset == 0x400004/2) return 0xc900;
+ if (offset == 0x400006/2) return 0xf000;
+
+ // non-protection accesses
+ if (offset < 0x400000/2)
+ return m_rom[MD_ADDR(offset)];
+ else
+ return 0xffff;
+}
+
+/*-------------------------------------------------
+ POKEMON STADIUM / KAIJU
+ -------------------------------------------------*/
+
+#define MD_POKESTAD_ADDR(a) (((offset << 1) | (m_bank << 15)) & (m_rom_size - 1))/2
+
+READ16_MEMBER(md_rom_pokestad_device::read)
+{
+ if (offset < 0x100000/2)
+ return m_rom[MD_POKESTAD_ADDR(offset)];
+
+ // non-protection accesses
+ if (offset < 0x400000/2)
+ return m_rom[MD_ADDR(offset)];
+ else
+ return 0xffff;
+}
+
+WRITE16_MEMBER(md_rom_pokestad_device::write)
+{
+ if (offset >= 0x700000/2 && offset < 0x800000/2)
+ m_bank = data & 0x7f;
+}
+
+/*-------------------------------------------------
+ POKEMON ALT
+ -------------------------------------------------*/
+
+READ16_MEMBER(md_rom_pokea_device::read_a13)
+{
+ if (offset == 0x00/2) return 0x14;
+ if (offset == 0x02/2) return 0x01;
+ if (offset == 0x3e/2) return 0x1f;
+ else return 0xffff;
+}
+
+/*-------------------------------------------------
+ REALTEC
+ -------------------------------------------------*/
+
+READ16_MEMBER(md_rom_realtec_device::read)
+{
+ if (offset < (m_bank_size * 0x20000)) // two banks of same (variable) size at the bottom of the rom
+ return m_rom[MD_ADDR((offset + (m_bank_addr * 0x20000)/2))];
+ return m_rom[MD_ADDR(((offset & 0x1fff/2) + 0x7e000/2))]; // otherwise it accesses the final 8k of the image
+}
+
+WRITE16_MEMBER(md_rom_realtec_device::write)
+{
+ if (offset == 0x400000/2)
+ {
+ m_old_bank_addr = m_bank_addr;
+ m_bank_addr = (m_bank_addr & 0x7) | ((data >> 9) & 0x7) << 3;
+ }
+ if (offset == 0x402000/2)
+ {
+ m_bank_addr = 0;
+ m_bank_size = (data >> 8) & 0x1f;
+ }
+ if (offset == 0x404000/2)
+ {
+ m_old_bank_addr = m_bank_addr;
+ m_bank_addr = (m_bank_addr & 0xf8) | ((data >> 8) & 0x3);
+ }
+}
+
+/*-------------------------------------------------
+ RED CLIFF
+ -------------------------------------------------*/
+
+READ16_MEMBER(md_rom_redcl_device::read)
+{
+ if (offset == 0x400000/2) return 0x55 << 8;
+ if (offset == 0x400004/2) return -0x56 << 8;
+
+ // non-protection accesses
+ if (offset < 0x400000/2)
+ return m_rom[MD_ADDR(offset)];
+ else
+ return 0xffff;
+}
+
+/*-------------------------------------------------
+ ROCKMAN X3
+ -------------------------------------------------*/
+
+READ16_MEMBER(md_rom_rx3_device::read_a13)
+{
+ if (offset == 0)
+ return 0x0c;
+ else
+ return 0xffff;
+}
+
+/*-------------------------------------------------
+ SQUIRREL KING
+ -------------------------------------------------*/
+
+READ16_MEMBER(md_rom_squir_device::read)
+{
+ if ((offset >= 0x400000/2) && (offset < 0x400008/2))
+ return m_latch;
+
+ // non-protection accesses
+ if (offset < 0x400000/2)
+ return m_rom[MD_ADDR(offset)];
+ else
+ return 0xffff;
+}
+
+WRITE16_MEMBER(md_rom_squir_device::write)
+{
+ if (offset >= 0x400000/2 && offset < 0x400008/2)
+ m_latch = data;
+}
+
+/*-------------------------------------------------
+ SUPER MARIO BROS
+ -------------------------------------------------*/
+
+READ16_MEMBER(md_rom_smb_device::read_a13)
+{
+ if (offset == 0)
+ return 0x0c;
+ else
+ return 0xffff;
+}
+
+/*-------------------------------------------------
+ SUPER MARIO BROS 2
+ -------------------------------------------------*/
+
+READ16_MEMBER(md_rom_smb2_device::read_a13)
+{
+ if (offset == 0)
+ return 0x0a;
+ else
+ return 0xffff;
+}
+
+/*-------------------------------------------------
+ SUPER MARIO WORLD 64
+ -------------------------------------------------*/
+
+READ16_MEMBER(md_rom_smw64_device::read)
+{
+ // 0x000000-0x0fffff: lower 512KB ROM (up to 0x07ffff) + mirror
+ // 0x600000-0x6fffff: internal hardware (up to 0x67ffff) + mirror
+ // Namely,
+ // * 60xxx = bank1 of the upper 512KB ROM
+ // * 61xxx = bank2 of the upper 512KB ROM
+ // * 62xxx = alternate 4KB chunks of 0x0000 ~ 0xffff
+ // * 63xxx = same as 62xxx
+ // * 64xxx = returns 0x0000
+ // * 65xxx = same as 64xxx
+ // * 66xxx = CTRL/DATA
+ // * 67xxx = CTRL/DATA
+ if (offset < 0x100000/2)
+ return m_rom[offset & 0x3ffff];
+
+ if ((offset >= 0x600000/2) && (offset < 0x610000/2))
+ return m_rom[(m_latch0 * 0x10000)/2 + (offset & 0x7fff)];
+ if ((offset >= 0x610000/2) && (offset < 0x620000/2))
+ return m_rom[(m_latch1 * 0x10000)/2 + (offset & 0x7fff)];
+
+ if ((offset >= 0x620000/2) && (offset < 0x640000/2))
+ return (offset & 0x1000/2) ? 0x0000 : 0xffff;
+ if ((offset >= 0x640000/2) && (offset < 0x660000/2))
+ return 0x0000;
+
+ if ((offset >= 0x660000/2) && (offset < 0x670000/2))
+ {
+ offset &= 7;
+ switch (offset)
+ {
+ case 0x0:
+ case 0x2:
+ case 0x4:
+ return m_reg[offset/2]; // DATA1, DATA2, DATA3
+ case 0x1:
+ case 0x3:
+ case 0x5:
+ return m_reg[offset/2] + 1; // DATA1+1, DATA2+1, DATA3+1
+ case 0x6:
+ return m_reg[2] + 2; // DATA3+2
+ case 0x7:
+ return m_reg[2] + 3; // DATA3+3
+ }
+ }
+ if ((offset >= 0x670000/2) && (offset < 0x680000/2))
+ {
+ UINT16 data = (m_ctrl[1] & 0x80) ? ((m_ctrl[2] & 0x40) ? (m_reg[4] & m_reg[5]) : (m_reg[4] ^ 0xff)) : 0x0000;
+ if (offset & 0x1) // odd offset, return lower 7 bits of the above
+ return data & 0x7f;
+ else // even offset, return whole data above, but also update the regs if CTRL3 has 0x80 set
+ {
+ if (m_ctrl[2] & 0x80) // update regs if CTRL3 has bit7 set
+ {
+ if (m_ctrl[2] & 0x20)
+ m_reg[2] = (m_reg[5] << 2) & 0xfc; // DATA3
+ else
+ m_reg[0] = ((m_reg[4] << 1) ^ m_reg[3]) & 0xfe; // DATA1
+ }
+ return data;
+ }
+ }
+ return 0xffff;
+}
+
+WRITE16_MEMBER(md_rom_smw64_device::write)
+{
+ // 0x600000-0x6fffff: internal hardware (up to 0x67ffff) + mirror
+ // Namely,
+ // * 62xxx/63xxx = unknown/unmapped
+ // * 65xxx/66xxx = unknown/unmapped
+ // * remaining ranges = CTRL/DATA
+ if ((offset >= 0x600000/2) && (offset < 0x610000/2))
+ {
+ if (offset & 1)
+ {
+ if ((m_ctrl[0] & 7) == 0)
+ m_reg[0] = ((m_reg[0] ^ m_reg[3]) ^ data) & 0xfe; // DATA1
+ if ((m_ctrl[0] & 7) == 1)
+ m_reg[1] = data & 0xfe; // DATA2
+ if ((m_ctrl[0] & 7) == 7)
+ m_latch1 = 8 + ((data & 0x1c) >> 2); // ROM BANKSWITCH $61
+ m_reg[3] = data; // DATA4
+ }
+ else
+ m_ctrl[0] = data; // CTRL1
+ }
+ if ((offset >= 0x610000/2) && (offset < 0x620000/2))
+ {
+ if (offset & 1)
+ m_ctrl[1] = data; // CTRL2
+ }
+ if ((offset >= 0x640000/2) && (offset < 0x650000/2))
+ {
+ if (offset & 1)
+ m_reg[5] = data; // DATA6
+ else
+ m_reg[4] = data; // DATA5
+ }
+ if ((offset >= 0x670000/2) && (offset < 0x680000/2))
+ {
+ if (!(offset & 1))
+ {
+ m_ctrl[2] = data; // CTRL3
+ if (m_ctrl[1] & 0x80)
+ m_latch0 = 8 + ((data & 0x1c) >> 2); // ROM BANKSWITCH $60
+ }
+ }
+}
+
+/*-------------------------------------------------
+ TEKKEN SPECIAL
+ -------------------------------------------------*/
+
+READ16_MEMBER(md_rom_tekkensp_device::read)
+{
+ if (offset < 0x400000/2)
+ return m_rom[MD_ADDR(offset)];
+ else if ((offset & 0x07) == 1 && m_reg)
+ return (m_reg - 1) << 8;
+ else
+ return 0xffff;
+}
+
+WRITE16_MEMBER(md_rom_tekkensp_device::write)
+{
+ if (offset < 0x400000/2)
+ return;
+
+ // thanks to EkeEke for the documentation
+ switch (offset & 0x07)
+ {
+ case 0x00:
+ // data output reset ? (game writes $FF before & after protection check)
+ m_reg = 0;
+ break;
+ case 0x01:
+ // read only ?
+ break;
+ case 0x06:
+ // data output mode bit 0 ? (game writes $01)
+ break;
+ case 0x07:
+ // data output mode bit 1 ? (never written by game)
+ break;
+ default:
+ if (data & 0x100) // data input (only connected to D0 ?)
+ {
+ // 4-bit hardware register ($400004 corresponds to bit0, $400006 to bit1, etc)
+ int shift = (offset - 2) & 3;
+ m_reg |= (1 << shift);
+ }
+ break;
+ }
+}
+
+/*-------------------------------------------------
+ TOP FIGHTER
+ -------------------------------------------------*/
+
+READ16_MEMBER(md_rom_topf_device::read)
+{
+ //cpu #0 (PC=0004CBAE): unmapped program memory word read from 006A35D4 & 00FF -- wants regD7
+ if (offset == 0x645b44/2)
+ {
+ //cpu #0 (PC=0004DE00): unmapped program memory word write to 00689B80 = 004A & 00FF
+ //cpu #0 (PC=0004DE08): unmapped program memory word write to 00 = 00B5 & 00FF
+ //cpu #0 (PC=0004DE0C): unmapped program memory word read from 00645B44 & 00FF
+
+ return 0x9f;//0x25;
+ }
+ if (offset == 0x6bd294/2)
+ {
+ /*
+ cpu #0 (PC=00177192): unmapped program memory word write to 006BD240 = 00A8 & 00FF
+ cpu #0 (PC=0017719A): unmapped program memory word write to 006BD2D2 = 0098 & 00FF
+ cpu #0 (PC=001771A2): unmapped program memory word read from 006BD294 & 00FF
+ */
+
+ if (space.device().safe_pc()==0x1771a2) return 0x50;
+ else
+ {
+ m_latch++;
+ logerror("%06x topfig_6BD294_r %04x\n",space.device().safe_pc(), m_latch);
+ return m_latch;
+ }
+ }
+ if (offset == 0x6f5344/2)
+ {
+ if (space.device().safe_pc()==0x4C94E)
+ return space.machine().device("maincpu")->state().state_int((M68K_D0)) & 0xff;
+ else
+ {
+ m_latch++;
+ logerror("%06x topfig_6F5344_r %04x\n", space.device().safe_pc(), m_latch);
+ return m_latch;
+ }
+ }
+
+ if (offset >= 0x20000/2 && offset < 0x28000/2)
+ return m_rom[offset + (m_bank[0] * 0x188000)/2];
+
+ if (offset >= 0x58000/2 && offset < 0x60000/2)
+ return m_rom[offset + (m_bank[1] * 0x20000)/2];
+
+ if (offset >= 0x60000/2 && offset < 0x68000/2)
+ return m_rom[offset + (m_bank[2] * 0x110000)/2];
+
+ // non-protection accesses
+ if (offset < 0x400000/2)
+ return m_rom[MD_ADDR(offset)];
+ else
+ return 0xffff;
+}
+
+WRITE16_MEMBER(md_rom_topf_device::write)
+{
+ if (offset >= 0x700000/2 && offset < 0x800000/2)
+ {
+ if (data == 0x002a)
+ m_bank[2] = 1; // == 0x2e*0x8000?!
+ else if (data==0x0035) // characters ingame
+ m_bank[0] = 1; // == 0x35*0x8000
+ else if (data==0x000f) // special moves
+ m_bank[1] = 1; // == 0xf*0x8000
+ else if (data==0x0000)
+ {
+ m_bank[0] = 0;
+ m_bank[1] = 0;
+ m_bank[2] = 0;
+ }
+ else
+ logerror("%06x offset %06x, data %04x\n", space.device().safe_pc(), offset, data);
+ }
+}
+
+/*-------------------------------------------------
+ RADICA TV GAMES [to be split...]
+ -------------------------------------------------*/
+
+READ16_MEMBER(md_rom_radica_device::read)
+{
+ return m_rom[(((m_bank * 0x10000) + (offset << 1)) & (m_rom_size - 1))/2];
+}
+
+READ16_MEMBER(md_rom_radica_device::read_a13)
+{
+ if (offset < 0x80)
+ m_bank = offset & 0x3f;
+ return 0;
+}
+
+/*-------------------------------------------------
+ BEGGAR PRINCE
+ This game uses cart which is the same as SEGA_SRAM
+ + bankswitch mechanism for first 256KB of the image:
+ depending on bit7 of the value written at 0xe00/2,
+ accesses to 0x00000-0x3ffff go to the first 256KB
+ of ROM, or to the second to last 256KB chunk (usually
+ mapped to 0x380000-0x3bffff). SRAM is mapped at
+ the end of ROM.
+ -------------------------------------------------*/
+
+READ16_MEMBER(md_rom_beggarp_device::read)
+{
+ if (offset >= m_nvram_start/2 && offset <= m_nvram_end/2 && m_nvram_active)
+ return m_nvram[offset & 0x3fff];
+
+ if (offset < 0x040000/2)
+ return m_mode ? m_rom[offset + 0x380000/2] : m_rom[offset];
+ else if (offset < 0x400000/2)
+ return m_rom[offset & 0x1fffff];
+
+ return 0xffff;
+}
+
+WRITE16_MEMBER(md_rom_beggarp_device::write)
+{
+ if (offset >= 0x0e00/2 && offset < 0x0f00/2)
+ m_mode = BIT(data, 7);
+
+ if (offset >= m_nvram_start/2 && offset <= m_nvram_end/2 && m_nvram_active && !m_nvram_readonly)
+ m_nvram[offset & 0x3fff] = data;
+}
+
+WRITE16_MEMBER(md_rom_beggarp_device::write_a13)
+{
+ if (offset == 0xf0/2)
+ {
+ /* unsure if this is actually supposed to toggle or just switch on? yet to encounter game that uses this */
+ m_nvram_active = BIT(data, 0);
+ m_nvram_readonly = BIT(data, 1);
+
+ // since a lot of generic carts ends up here if loaded from fullpath
+ // we turn on nvram (with m_nvram_handlers_installed) only if they toggle it on by writing here!
+ if (m_nvram_active)
+ m_nvram_handlers_installed = 1;
+ }
+}
+
+/*-------------------------------------------------
+ LEGEND OF WUKONG
+ This game uses cart which is the same as SEGA_SRAM
+ + bankswitch mechanism for last 128KB of the image:
+ first 2MB of ROM is loaded in 0-0x200000 and
+ mirrored in 0x200000-0x400000, but depending on
+ bit7 of the value written at 0xe00/2 accesses to
+ 0x200000-0x21ffff go either to the "physical" address
+ (i.e. last 128K of ROM) or to the "memory" address
+ (i.e. mirror of first 128K)
+ -------------------------------------------------*/
+
+READ16_MEMBER(md_rom_wukong_device::read)
+{
+ if (offset >= m_nvram_start/2 && offset <= m_nvram_end/2 && m_nvram_active)
+ return m_nvram[offset - m_nvram_start/2];
+
+ // here can access both last 128K of the ROM and the first 128K, depending of bit7 of m_mode
+ if (offset >= 0x200000/2 && offset < 0x220000/2)
+ return !m_mode ? m_rom[offset] : m_rom[offset & 0xffff];
+ else if (offset < 0x400000/2)
+ return m_rom[offset & 0xfffff];
+ else
+ return 0xffff;
+}
+
+WRITE16_MEMBER(md_rom_wukong_device::write)
+{
+ if (offset < 0x100000/2) // it actually writes to 0xe00/2
+ m_mode = BIT(data, 7);
+
+ if (offset >= m_nvram_start/2 && offset <= m_nvram_end/2 && m_nvram_active && !m_nvram_readonly)
+ m_nvram[offset - m_nvram_start/2] = data;
+}
+
+WRITE16_MEMBER(md_rom_wukong_device::write_a13)
+{
+ if (offset == 0xf0/2)
+ {
+ /* unsure if this is actually supposed to toggle or just switch on? yet to encounter game that uses this */
+ m_nvram_active = BIT(data, 0);
+ m_nvram_readonly = BIT(data, 1);
+
+ // since a lot of generic carts ends up here if loaded from fullpath
+ // we turn on nvram (with m_nvram_handlers_installed) only if they toggle it on by writing here!
+ if (m_nvram_active)
+ m_nvram_handlers_installed = 1;
+ }
+}