summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/bus/vcs/rom.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/bus/vcs/rom.c')
-rwxr-xr-xsrc/devices/bus/vcs/rom.c1050
1 files changed, 1050 insertions, 0 deletions
diff --git a/src/devices/bus/vcs/rom.c b/src/devices/bus/vcs/rom.c
new file mode 100755
index 00000000000..b689db7094e
--- /dev/null
+++ b/src/devices/bus/vcs/rom.c
@@ -0,0 +1,1050 @@
+// license:BSD-3-Clause
+// copyright-holders:Fabio Priuli
+/***********************************************************************************************************
+
+ A2600 VCS ROM cart emulation
+ Simple cart hardware with no additional hw
+
+ Mapper implementation based on the wonderful docs by Kevtris
+ http://blog.kevtris.org/blogfiles/Atari%202600%20Mappers.txt
+
+ (also inspired by previous work by Wilbert Pol et al.)
+
+ ***********************************************************************************************************/
+
+
+#include "emu.h"
+#include "rom.h"
+
+
+//-------------------------------------------------
+// a26_rom_*k_device - constructor
+//-------------------------------------------------
+
+const device_type A26_ROM_2K = &device_creator<a26_rom_2k_device>;
+const device_type A26_ROM_4K = &device_creator<a26_rom_4k_device>;
+const device_type A26_ROM_F4 = &device_creator<a26_rom_f4_device>;
+const device_type A26_ROM_F6 = &device_creator<a26_rom_f6_device>;
+const device_type A26_ROM_F8 = &device_creator<a26_rom_f8_device>;
+const device_type A26_ROM_F8_SW = &device_creator<a26_rom_f8_sw_device>;
+const device_type A26_ROM_FA = &device_creator<a26_rom_fa_device>;
+const device_type A26_ROM_FE = &device_creator<a26_rom_fe_device>;
+const device_type A26_ROM_3E = &device_creator<a26_rom_3e_device>;
+const device_type A26_ROM_3F = &device_creator<a26_rom_3f_device>;
+const device_type A26_ROM_E0 = &device_creator<a26_rom_e0_device>;
+const device_type A26_ROM_E7 = &device_creator<a26_rom_e7_device>;
+const device_type A26_ROM_UA = &device_creator<a26_rom_ua_device>;
+const device_type A26_ROM_CV = &device_creator<a26_rom_cv_device>;
+const device_type A26_ROM_DC = &device_creator<a26_rom_dc_device>;
+const device_type A26_ROM_FV = &device_creator<a26_rom_fv_device>;
+const device_type A26_ROM_JVP = &device_creator<a26_rom_jvp_device>;
+const device_type A26_ROM_4IN1 = &device_creator<a26_rom_4in1_device>;
+const device_type A26_ROM_8IN1 = &device_creator<a26_rom_8in1_device>;
+const device_type A26_ROM_32IN1 = &device_creator<a26_rom_32in1_device>;
+
+
+a26_rom_2k_device::a26_rom_2k_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_vcs_cart_interface( mconfig, *this )
+{
+}
+
+a26_rom_2k_device::a26_rom_2k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, A26_ROM_2K, "Atari VCS 2600 2K ROM Carts", tag, owner, clock, "vcs_2k", __FILE__),
+ device_vcs_cart_interface( mconfig, *this )
+{
+}
+
+
+a26_rom_4k_device::a26_rom_4k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : a26_rom_2k_device(mconfig, A26_ROM_4K, "Atari VCS 2600 4K ROM Carts", tag, owner, clock, "vcs_4k", __FILE__)
+{
+}
+
+
+a26_rom_f6_device::a26_rom_f6_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)
+ : a26_rom_2k_device(mconfig, type, name, tag, owner, clock, shortname, source),
+ m_base_bank(-1) // set to -1 to help the Xin1 multicart...
+{
+}
+
+a26_rom_f6_device::a26_rom_f6_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : a26_rom_2k_device(mconfig, A26_ROM_F6, "Atari VCS 2600 ROM Carts w/F6 bankswitch", tag, owner, clock, "vcs_f6", __FILE__),
+ m_base_bank(-1) // set to -1 to help the Xin1 multicart...
+{
+}
+
+
+a26_rom_f4_device::a26_rom_f4_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : a26_rom_f6_device(mconfig, A26_ROM_F4, "Atari VCS 2600 ROM Carts w/F4 bankswitch", tag, owner, clock, "vcs_f4", __FILE__)
+{
+}
+
+
+a26_rom_f8_device::a26_rom_f8_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)
+ : a26_rom_f6_device(mconfig, type, name, tag, owner, clock, shortname, source)
+{
+}
+
+a26_rom_f8_device::a26_rom_f8_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : a26_rom_f6_device(mconfig, A26_ROM_F8, "Atari VCS 2600 ROM Carts w/F8 bankswitch", tag, owner, clock, "vcs_f8", __FILE__)
+{
+}
+
+a26_rom_f8_sw_device::a26_rom_f8_sw_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : a26_rom_f8_device(mconfig, A26_ROM_F8_SW, "Atari VCS 2600 ROM Cart Snow White", tag, owner, clock, "vcs_f8_sw", __FILE__)
+{
+}
+
+a26_rom_fa_device::a26_rom_fa_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : a26_rom_f6_device(mconfig, A26_ROM_FA, "Atari VCS 2600 ROM Carts w/FA bankswitch", tag, owner, clock, "vcs_fa", __FILE__)
+{
+}
+
+
+a26_rom_fe_device::a26_rom_fe_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : a26_rom_2k_device(mconfig, A26_ROM_FE, "Atari VCS 2600 ROM Carts w/FE bankswitch", tag, owner, clock, "vcs_fe", __FILE__)
+{
+}
+
+
+a26_rom_3e_device::a26_rom_3e_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : a26_rom_f6_device(mconfig, A26_ROM_3E, "Atari VCS 2600 ROM Carts w/3E bankswitch", tag, owner, clock, "vcs_3e", __FILE__)
+{
+}
+
+
+a26_rom_3f_device::a26_rom_3f_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : a26_rom_f6_device(mconfig, A26_ROM_3F, "Atari VCS 2600 ROM Carts w/3F bankswitch", tag, owner, clock, "vcs_3f", __FILE__)
+{
+}
+
+
+a26_rom_e0_device::a26_rom_e0_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : a26_rom_f6_device(mconfig, A26_ROM_E0, "Atari VCS 2600 ROM Carts w/E0 bankswitch", tag, owner, clock, "vcs_e0", __FILE__)
+{
+}
+
+
+a26_rom_e7_device::a26_rom_e7_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : a26_rom_f6_device(mconfig, A26_ROM_E7, "Atari VCS 2600 ROM Carts w/E7 bankswitch", tag, owner, clock, "vcs_e7", __FILE__)
+{
+}
+
+
+a26_rom_ua_device::a26_rom_ua_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : a26_rom_f6_device(mconfig, A26_ROM_UA, "Atari VCS 2600 ROM Carts w/UA bankswitch", tag, owner, clock, "vcs_ua", __FILE__)
+{
+}
+
+
+a26_rom_cv_device::a26_rom_cv_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : a26_rom_2k_device(mconfig, A26_ROM_CV, "Atari VCS 2600 ROM Carts w/Commavid bankswitch", tag, owner, clock, "vcs_cv", __FILE__)
+{
+}
+
+
+a26_rom_dc_device::a26_rom_dc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : a26_rom_f6_device(mconfig, A26_ROM_DC, "Atari VCS 2600 ROM Carts w/Dynacom bankswitch", tag, owner, clock, "vcs_dc", __FILE__)
+{
+}
+
+
+a26_rom_fv_device::a26_rom_fv_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : a26_rom_f6_device(mconfig, A26_ROM_FV, "Atari VCS 2600 ROM Carts w/FV bankswitch", tag, owner, clock, "vcs_fv", __FILE__)
+{
+}
+
+
+a26_rom_jvp_device::a26_rom_jvp_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : a26_rom_f6_device(mconfig, A26_ROM_JVP, "Atari VCS 2600 ROM Carts w/JVP bankswitch", tag, owner, clock, "vcs_jvp", __FILE__)
+{
+}
+
+
+a26_rom_4in1_device::a26_rom_4in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : a26_rom_f6_device(mconfig, A26_ROM_4IN1, "Atari VCS 2600 ROM Cart 4 in 1", tag, owner, clock, "vcs_4in1", __FILE__)
+{
+}
+
+
+a26_rom_8in1_device::a26_rom_8in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : a26_rom_f8_device(mconfig, A26_ROM_8IN1, "Atari VCS 2600 ROM Cart 8 in 1", tag, owner, clock, "vcs_8in1", __FILE__)
+{
+}
+
+
+a26_rom_32in1_device::a26_rom_32in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : a26_rom_f6_device(mconfig, A26_ROM_32IN1, "Atari VCS 2600 ROM Cart 32 in 1", tag, owner, clock, "vcs_32in1", __FILE__)
+{
+}
+
+
+void a26_rom_2k_device::device_start()
+{
+}
+
+void a26_rom_2k_device::device_reset()
+{
+}
+
+void a26_rom_f6_device::device_start()
+{
+ save_item(NAME(m_base_bank));
+}
+
+void a26_rom_f6_device::device_reset()
+{
+ m_base_bank = 0;
+}
+
+void a26_rom_f4_device::device_reset()
+{
+ m_base_bank = 7;
+}
+
+void a26_rom_f8_sw_device::device_reset()
+{
+ // Snow White proto starts from bank 1!!!
+ m_base_bank = 1;
+}
+
+void a26_rom_fe_device::device_start()
+{
+ save_item(NAME(m_base_bank));
+ save_item(NAME(m_trigger_on_next_access));
+}
+
+void a26_rom_fe_device::device_reset()
+{
+ m_base_bank = 0;
+ m_trigger_on_next_access = 0;
+}
+
+void a26_rom_3e_device::device_start()
+{
+ save_item(NAME(m_base_bank));
+ save_item(NAME(m_ram_bank));
+ save_item(NAME(m_ram_enable));
+}
+
+void a26_rom_3e_device::device_reset()
+{
+ m_num_bank = m_rom_size / 0x800;
+ m_base_bank = m_num_bank - 1;
+ m_ram_bank = 0;
+ m_ram_enable = 0;
+}
+
+void a26_rom_3f_device::device_reset()
+{
+ m_num_bank = m_rom_size / 0x800;
+ m_base_bank = m_num_bank - 1;
+}
+
+void a26_rom_e0_device::device_start()
+{
+ save_item(NAME(m_base_banks));
+}
+
+void a26_rom_e0_device::device_reset()
+{
+ m_base_banks[0] = 4;
+ m_base_banks[1] = 5;
+ m_base_banks[2] = 6;
+ m_base_banks[3] = 7;
+}
+
+void a26_rom_e7_device::device_start()
+{
+ save_item(NAME(m_base_bank));
+ save_item(NAME(m_ram_bank));
+}
+
+void a26_rom_e7_device::device_reset()
+{
+ m_base_bank = 0;
+ m_ram_bank = 0;
+}
+
+void a26_rom_ua_device::device_reset()
+{
+ m_base_bank = 0;
+}
+
+void a26_rom_fv_device::device_start()
+{
+ save_item(NAME(m_base_bank));
+ save_item(NAME(m_locked));
+}
+
+void a26_rom_fv_device::device_reset()
+{
+ m_base_bank = 0;
+ m_locked = 0;
+}
+
+
+void a26_rom_4in1_device::device_reset()
+{
+ m_base_bank++;
+ m_base_bank &= 3;
+}
+
+
+void a26_rom_8in1_device::device_start()
+{
+ save_item(NAME(m_base_bank));
+ save_item(NAME(m_reset_bank));
+}
+
+void a26_rom_8in1_device::device_reset()
+{
+ // we use here two different bank counter: the main one for the 8x8K chunks,
+ // and the usual one (m_base_bank) for the 4K bank of the current game
+ m_reset_bank++;
+ m_reset_bank &= 7;
+ m_base_bank = 0;
+}
+
+
+void a26_rom_32in1_device::device_reset()
+{
+ m_base_bank++;
+ m_base_bank &= 0x1f;
+}
+
+
+/*-------------------------------------------------
+ mapper specific handlers
+ -------------------------------------------------*/
+
+/*-------------------------------------------------
+ BASE 2K & 4K Carts:
+ no bankswitch
+
+ GAMES: a large majority
+ -------------------------------------------------*/
+
+READ8_MEMBER(a26_rom_2k_device::read_rom)
+{
+ // Super Chip RAM reads are mapped in 0x1080-0x10ff
+ if (!m_ram.empty() && offset >= 0x80 && offset < 0x100)
+ {
+ return m_ram[offset & (m_ram.size() - 1)];
+ }
+
+ return m_rom[offset & (m_rom_size - 1)];
+}
+
+/*-------------------------------------------------
+ "F4 Bankswitch" Carts:
+ read/write access to 0x1ff4-0x1ffb determines the
+ 4K ROM bank to be read
+
+ GAMES: Fatal Run
+ -------------------------------------------------*/
+
+READ8_MEMBER(a26_rom_f4_device::read_rom)
+{
+ // Super Chip RAM reads are mapped in 0x1080-0x10ff
+ if (!m_ram.empty() && offset >= 0x80 && offset < 0x100)
+ {
+ return m_ram[offset & (m_ram.size() - 1)];
+ }
+
+ // update banks
+ if (!space.debugger_access())
+ {
+ switch (offset)
+ {
+ case 0x0ff4:
+ case 0x0ff5:
+ case 0x0ff6:
+ case 0x0ff7:
+ case 0x0ff8:
+ case 0x0ff9:
+ case 0x0ffa:
+ case 0x0ffb:
+ m_base_bank = offset - 0x0ff4;
+ break;
+ }
+ }
+
+ return m_rom[offset + (m_base_bank * 0x1000)];
+}
+
+WRITE8_MEMBER(a26_rom_f4_device::write_bank)
+{
+ // Super Chip RAM writes are mapped in 0x1000-0x107f
+ if (!m_ram.empty() && offset < 0x80)
+ {
+ m_ram[offset & (m_ram.size() - 1)] = data;
+ return;
+ }
+
+ switch (offset)
+ {
+ case 0x0ff4:
+ case 0x0ff5:
+ case 0x0ff6:
+ case 0x0ff7:
+ case 0x0ff8:
+ case 0x0ff9:
+ case 0x0ffa:
+ case 0x0ffb:
+ m_base_bank = offset - 0x0ff4;
+ break;
+ default:
+ logerror("Write Bank outside expected range (0x%X).\n", offset + 0x1000);
+ break;
+ }
+}
+
+/*-------------------------------------------------
+ "F6 Bankswitch" Carts:
+ read/write access to 0x1ff6-0x1ff9 determines the
+ 4K ROM bank to be read
+
+ GAMES: Atari 16K games, like Crossbow, Crystal
+ Castles and the 2-in-1 carts
+
+ -------------------------------------------------*/
+
+READ8_MEMBER(a26_rom_f6_device::read_rom)
+{
+ // Super Chip RAM reads are mapped in 0x1080-0x10ff
+ if (!m_ram.empty() && offset >= 0x80 && offset < 0x100)
+ {
+ return m_ram[offset & (m_ram.size() - 1)];
+ }
+
+ // update banks
+ if (!space.debugger_access())
+ {
+ switch (offset)
+ {
+ case 0x0ff6:
+ case 0x0ff7:
+ case 0x0ff8:
+ case 0x0ff9:
+ m_base_bank = offset - 0x0ff6;
+ break;
+ }
+ }
+
+ return m_rom[offset + (m_base_bank * 0x1000)];
+}
+
+WRITE8_MEMBER(a26_rom_f6_device::write_bank)
+{
+ // Super Chip RAM writes are mapped in 0x1000-0x107f
+ if (!m_ram.empty() && offset < 0x80)
+ {
+ m_ram[offset & (m_ram.size() - 1)] = data;
+ return;
+ }
+
+ switch (offset)
+ {
+ case 0x0ff6:
+ case 0x0ff7:
+ case 0x0ff8:
+ case 0x0ff9:
+ m_base_bank = offset - 0x0ff6;
+ break;
+ default:
+ logerror("Write Bank outside expected range (0x%X).\n", offset + 0x1000);
+ break;
+ }
+}
+
+DIRECT_UPDATE_MEMBER(a26_rom_f6_device::cart_opbase)
+{
+ if ((address & 0x1fff) >= 0x1ff6 && (address & 0x1fff) <= 0x1ff9)
+ {
+ if (!direct.space().debugger_access())
+ write_bank(direct.space(), (address & 0x1fff) - 0x1ff6, 0);
+ }
+ return address;
+}
+
+/*-------------------------------------------------
+ "F8 Bankswitch" Carts:
+ read/write access to 0x1ff8-0x1ff9 determines the
+ 4K ROM bank to be read
+
+ GAMES: Atari 8K games, like Asteroids, Battlezone
+ and Taz
+
+ -------------------------------------------------*/
+
+READ8_MEMBER(a26_rom_f8_device::read_rom)
+{
+ // Super Chip RAM reads are mapped in 0x1080-0x10ff
+ if (!m_ram.empty() && offset >= 0x80 && offset < 0x100)
+ {
+ return m_ram[offset & (m_ram.size() - 1)];
+ }
+
+ // update banks
+ if (!space.debugger_access())
+ {
+ switch (offset)
+ {
+ case 0x0ff8:
+ case 0x0ff9:
+ m_base_bank = offset - 0x0ff8;
+ break;
+ }
+ }
+
+ return m_rom[offset + (m_base_bank * 0x1000)];
+}
+
+WRITE8_MEMBER(a26_rom_f8_device::write_bank)
+{
+ // Super Chip RAM writes are mapped in 0x1000-0x107f
+ if (!m_ram.empty() && offset < 0x80)
+ {
+ m_ram[offset & (m_ram.size() - 1)] = data;
+ return;
+ }
+
+ switch (offset)
+ {
+ case 0x0ff8:
+ case 0x0ff9:
+ m_base_bank = offset - 0x0ff8;
+ break;
+ default:
+ logerror("Write Bank outside expected range (0x%X).\n", offset + 0x1000);
+ break;
+ }
+}
+
+/*-------------------------------------------------
+ "FA Bankswitch" Carts:
+ read/write access to 0x1ff8-0x1ffa determines the
+ 4K ROM bank to be read
+ These games contained the CBS RAM+ chip (256bytes
+ of RAM)
+
+ GAMES: CBS RAM Plus games like Omega Race and Tunnel
+ Runner
+
+ -------------------------------------------------*/
+
+READ8_MEMBER(a26_rom_fa_device::read_rom)
+{
+ // CBS RAM+ reads are mapped in 0x1100-0x11ff
+ if (!m_ram.empty() && offset >= 0x100 && offset < 0x200)
+ {
+ return m_ram[offset & (m_ram.size() - 1)];
+ }
+
+ // update banks
+ if (!space.debugger_access())
+ {
+ switch (offset)
+ {
+ case 0x0ff8:
+ case 0x0ff9:
+ case 0x0ffa:
+ m_base_bank = offset - 0x0ff8;
+ break;
+ }
+ }
+
+ return m_rom[offset + (m_base_bank * 0x1000)];
+}
+
+WRITE8_MEMBER(a26_rom_fa_device::write_bank)
+{
+ // CBS RAM+ writes are mapped in 0x1000-0x10ff
+ if (!m_ram.empty() && offset < 0x100)
+ {
+ m_ram[offset & (m_ram.size() - 1)] = data;
+ }
+
+ switch (offset)
+ {
+ case 0x0ff8:
+ case 0x0ff9:
+ case 0x0ffa:
+ m_base_bank = offset - 0x0ff8;
+ break;
+ default:
+ logerror("Write Bank outside expected range (0x%X).\n", offset + 0x1000);
+ break;
+ }
+}
+
+/*-------------------------------------------------
+ "FE Bankswitch" Carts:
+ read/write access to 0x01fe-0x1ff determines the
+ 4K ROM bank to be read
+
+ GAMES: Activision 8K games like Decathlon
+
+ -------------------------------------------------*/
+/*
+
+ There seems to be a kind of lag between the writing to address 0x1FE and the
+ Activision switcher springing into action. It waits for the next byte to arrive
+ on the data bus, which is the new PCH in the case of a JSR, and the PCH of the
+ stored PC on the stack in the case of an RTS.
+
+ depending on last byte & 0x20 -> 0x00 -> switch to bank #1
+ -> 0x20 -> switch to bank #0
+
+ */
+
+READ8_MEMBER(a26_rom_fe_device::read_rom)
+{
+ UINT8 data;
+
+ // Super Chip RAM reads are mapped in 0x1080-0x10ff
+ if (!m_ram.empty() && offset >= 0x80 && offset < 0x100)
+ {
+ return m_ram[offset & (m_ram.size() - 1)];
+ }
+
+ data = m_rom[offset + (m_base_bank * 0x1000)];
+
+ if (!space.debugger_access())
+ {
+ if (m_trigger_on_next_access)
+ {
+ m_base_bank = BIT(data, 5) ? 0 : 1;
+ m_trigger_on_next_access = 0;
+ }
+ }
+
+ return data;
+}
+
+WRITE8_MEMBER(a26_rom_fe_device::write_ram)
+{
+ // Super Chip RAM writes are mapped in 0x1000-0x107f
+ if (!m_ram.empty() && offset < 0x80)
+ {
+ m_ram[offset & (m_ram.size() - 1)] = data;
+ }
+}
+
+READ8_MEMBER(a26_rom_fe_device::read_bank)
+{
+ UINT8 data = space.read_byte(0xfe + offset);
+
+ if (!space.debugger_access())
+ {
+ switch (offset & 1)
+ {
+ case 0:
+ // The next byte on the data bus determines which bank to switch to
+ m_trigger_on_next_access = 1;
+ break;
+
+ case 1:
+ if (m_trigger_on_next_access)
+ {
+ m_base_bank = BIT(data, 5) ? 0 : 1;
+ m_trigger_on_next_access = 0;
+ }
+ break;
+ }
+ }
+ return data;
+}
+
+WRITE8_MEMBER(a26_rom_fe_device::write_bank)
+{
+ space.write_byte(0xfe, data);
+ if (!space.debugger_access())
+ {
+ // The next byte on the data bus determines which bank to switch to
+ m_trigger_on_next_access = 1;
+ }
+}
+
+/*-------------------------------------------------
+ "3E Bankswitch" Carts:
+ write access to 0x3e determines the 2K ROM bank to
+ be read, write access to 0x3f determines the RAM bank
+ to be read
+
+ GAMES: Boulder Dash (Homebrew)
+
+ -------------------------------------------------*/
+
+READ8_MEMBER(a26_rom_3e_device::read_rom)
+{
+ if (!m_ram.empty() && m_ram_enable && offset < 0x400)
+ return m_ram[offset + (m_ram_bank * 0x400)];
+
+ if (offset >= 0x800)
+ return m_rom[(offset & 0x7ff) + (m_num_bank - 1) * 0x800];
+ else
+ return m_rom[offset + m_base_bank * 0x800];
+}
+
+WRITE8_MEMBER(a26_rom_3e_device::write_bank)
+{
+ if (offset == 0x3f)
+ {
+ m_base_bank = data & (m_num_bank - 1);
+ m_ram_enable = 0;
+ }
+ else if (offset == 0x3e)
+ {
+ m_ram_bank = data & 0x1f;
+ m_ram_enable = 1;
+ }
+}
+
+WRITE8_MEMBER(a26_rom_3e_device::write_ram)
+{
+ if (!m_ram.empty() && m_ram_enable && offset >= 0x400 && offset < 0x800)
+ m_ram[(offset & 0x3ff) + (m_ram_bank * 0x400)] = data;
+}
+
+
+/*-------------------------------------------------
+ "3F Bankswitch" Carts:
+ write access to 0x00-0x3f determines the 2K ROM bank
+ to be read
+
+ GAMES: Tigervision 8K games like Espial and Miner
+ 2049er. Extended version with bankswitch up to 512K
+ shall be supported as well (but we lack a test case)
+
+ -------------------------------------------------*/
+
+READ8_MEMBER(a26_rom_3f_device::read_rom)
+{
+ if (offset >= 0x800)
+ return m_rom[(offset & 0x7ff) + (m_num_bank - 1) * 0x800];
+ else
+ return m_rom[offset + m_base_bank * 0x800];
+}
+
+WRITE8_MEMBER(a26_rom_3f_device::write_bank)
+{
+ m_base_bank = data & (m_num_bank - 1);
+}
+
+/*-------------------------------------------------
+ "E0 Bankswitch" Carts:
+ read/write access to 0x1fe0-0x1ff8 determines the
+ 1K ROM bank to be read in each 1K chunk (0x1c00-0x1fff
+ always points to the last 1K of the ROM)
+
+ GAMES: Parker Bros. 8K games like Gyruss and Popeye
+
+ -------------------------------------------------*/
+
+READ8_MEMBER(a26_rom_e0_device::read_rom)
+{
+ // update banks
+ if (!space.debugger_access())
+ {
+ if (offset >= 0xfe0 && offset <= 0xff8)
+ m_base_banks[(offset >> 3) & 3] = offset & 7;
+ }
+
+ return m_rom[(offset & 0x3ff) + (m_base_banks[(offset >> 10) & 3] * 0x400)];
+}
+
+WRITE8_MEMBER(a26_rom_e0_device::write_bank)
+{
+ if (offset >= 0xfe0 && offset <= 0xff8)
+ m_base_banks[(offset >> 3) & 3] = offset & 7;
+}
+
+
+/*-------------------------------------------------
+ "E7 Bankswitch" Carts:
+ this PCB can handle up to 16K of ROM and 2K of RAM,
+ with the following layout
+ 1000-17ff is selectable bank
+ 1800-19ff is RAM
+ 1a00-1fff is fixed to the last 0x600 of ROM
+
+ The selectable bank can be ROM (if selected by
+ 0x1fe0-0x1fe6 access) or a first 1K of RAM (if
+ selected by 0x1fe7 access).
+ The other 256byte RAM bank can be one of the
+ four different chunks forming the other 1K of RAM
+ (the bank is selected by accessing 0x1fe8-0x1feb)
+
+ GAMES: M Network 16K games like Burgertime and
+ Bump'n Jump
+
+ -------------------------------------------------*/
+
+READ8_MEMBER(a26_rom_e7_device::read_rom)
+{
+ // update banks
+ if (!space.debugger_access())
+ {
+ if (offset >= 0xfe0 && offset <= 0xfe7)
+ m_base_bank = offset - 0xfe0;
+ if (offset >= 0xfe8 && offset <= 0xfeb)
+ m_ram_bank = offset - 0xfe8;
+ }
+
+ if (!m_ram.empty())
+ {
+ // 1K of RAM
+ if (m_base_bank == 0x07 && offset >= 0x400 && offset < 0x800)
+ return m_ram[0x400 + (offset & 0x3ff)];
+ // the other 1K of RAM
+ if (offset >= 0x900 && offset < 0xa00)
+ {
+ offset -= 0x900;
+ return m_ram[offset + (m_ram_bank * 0x100)];
+ }
+ }
+
+ if (offset > 0x800)
+ return m_rom[(offset & 0x7ff) + 0x3800];
+ else
+ return m_rom[(offset & 0x7ff) + (m_base_bank * 0x800)];
+}
+
+WRITE8_MEMBER(a26_rom_e7_device::write_bank)
+{
+ if (offset >= 0xfe0 && offset <= 0xfe7)
+ m_base_bank = offset - 0xfe0;
+ if (offset >= 0xfe8 && offset <= 0xfeb)
+ m_ram_bank = offset - 0xfe8;
+
+ if (!m_ram.empty())
+ {
+ // 1K of RAM
+ if (m_base_bank == 0x07 && offset < 0x400)
+ m_ram[0x400 + (offset & 0x3ff)] = data;
+ // the other 1K of RAM
+ if (offset >= 0x800 && offset < 0x900)
+ {
+ offset -= 0x800;
+ m_ram[offset + (m_ram_bank * 0x100)] = data;
+ }
+ }
+}
+
+/*-------------------------------------------------
+ "UA Bankswitch" Carts:
+ read/write access to 0x200-0x27f determines the
+ 4K ROM bank to be read (0x220-0x23f for low 4K,
+ 0x240-0x27f for high 4K)
+
+ GAMES: UA Ltd. 8K games like Funky Flash and
+ Pleaides
+
+ -------------------------------------------------*/
+
+READ8_MEMBER(a26_rom_ua_device::read_rom)
+{
+ return m_rom[(offset + (m_base_bank * 0x1000)) & (m_rom_size - 1)];
+}
+
+READ8_MEMBER(a26_rom_ua_device::read_bank)
+{
+ if (!space.debugger_access())
+ m_base_bank = offset >> 6;
+
+ return 0;
+}
+
+WRITE8_MEMBER(a26_rom_ua_device::write_bank)
+{
+ m_base_bank = offset >> 6;
+}
+
+
+/*-------------------------------------------------
+ Commavid Carts:
+ It allows for both ROM and RAM on the cartridge,
+ without using bankswitching. There's 2K of ROM
+ and 1K of RAM.
+
+ GAMES: Magicard and Video Life by Commavid
+
+ -------------------------------------------------*/
+
+READ8_MEMBER(a26_rom_cv_device::read_rom)
+{
+ if (!m_ram.empty() && offset < 0x400)
+ {
+ return m_ram[offset & (m_ram.size() - 1)];
+ }
+
+ // games shall not read from 0x1400-0x17ff (RAM write)
+ // but we fall back to ROM just in case...
+ return m_rom[offset & 0x7ff];
+}
+
+WRITE8_MEMBER(a26_rom_cv_device::write_bank)
+{
+ if (!m_ram.empty() && offset >= 0x400 && offset < 0x800)
+ {
+ m_ram[offset & (m_ram.size() - 1)] = data;
+ }
+}
+
+
+/*-------------------------------------------------
+ Dynacom Megaboy Carts (aka "F0 Banswitch"):
+ read/write access to 0x1ff0 determines the 4K ROM
+ bank to be read (each access increases the bank index
+ up to 16, since the cart was 64K wide)
+
+ GAMES: Megaboy by Dynacom
+
+ -------------------------------------------------*/
+
+READ8_MEMBER(a26_rom_dc_device::read_rom)
+{
+ if (!space.debugger_access())
+ {
+ if (offset == 0xff0)
+ m_base_bank = (m_base_bank + 1) & 0x0f;
+ }
+
+ if (offset == 0xfec)
+ return m_base_bank;
+
+ return m_rom[offset + (m_base_bank * 0x1000)];
+}
+
+WRITE8_MEMBER(a26_rom_dc_device::write_bank)
+{
+ if (offset == 0xff0)
+ m_base_bank = (m_base_bank + 1) & 0x0f;
+}
+
+
+/*-------------------------------------------------
+ "FV Bankswitch" Carts:
+ The first access to 0x1fd0 switch the bank, but
+ only if pc() & 0x1f00 == 0x1f00!
+
+ GAMES: Challenge by HES
+
+ -------------------------------------------------*/
+
+READ8_MEMBER(a26_rom_fv_device::read_rom)
+{
+ if (!space.debugger_access())
+ {
+ if (offset == 0xfd0)
+ {
+ if (!m_locked && (machine().device<cpu_device>("maincpu")->pc() & 0x1f00) == 0x1f00)
+ {
+ m_locked = 1;
+ m_base_bank = m_base_bank ^ 0x01;
+ }
+ }
+ }
+
+ return m_rom[offset + (m_base_bank * 0x1000)];
+}
+
+WRITE8_MEMBER(a26_rom_fv_device::write_bank)
+{
+ if (offset == 0xfd0)
+ {
+ if (!m_locked && (machine().device<cpu_device>("maincpu")->pc() & 0x1f00) == 0x1f00)
+ {
+ m_locked = 1;
+ m_base_bank = m_base_bank ^ 0x01;
+ }
+ }
+}
+
+
+/*-------------------------------------------------
+ "JVP Bankswitch" Carts:
+ read/write access to 0x0fa0-0x0fc0 determines the
+ 4K ROM bank to be read (notice that this overlaps
+ the RIOT, currently handled in the main driver until
+ I can better investigate the behavior)
+
+ GAMES: No test case!?!
+
+ -------------------------------------------------*/
+
+READ8_MEMBER(a26_rom_jvp_device::read_rom)
+{
+ return m_rom[offset + (m_base_bank * 0x1000)];
+}
+
+WRITE8_MEMBER(a26_rom_jvp_device::write_bank)
+{
+ switch (offset)
+ {
+ case 0x00:
+ case 0x20:
+ m_base_bank ^= 1;
+ break;
+ default:
+ //printf("%04X: write to unknown mapper address %02X\n", m_maincpu->pc(), 0xfa0 + offset);
+ break;
+ }
+}
+
+
+/*-------------------------------------------------
+ 4 in 1 Carts (Reset based):
+ the 4K bank changes at each reset
+
+ GAMES: 4 in 1 carts
+
+ -------------------------------------------------*/
+
+READ8_MEMBER(a26_rom_4in1_device::read_rom)
+{
+ return m_rom[offset + (m_base_bank * 0x1000)];
+}
+
+
+/*-------------------------------------------------
+ 8 in 1 Carts (Reset based):
+ the 8K banks change at each reset, and internally
+ each game runs as a F8-bankswitched cart
+
+ GAMES: 8 in 1 cart
+
+ -------------------------------------------------*/
+
+READ8_MEMBER(a26_rom_8in1_device::read_rom)
+{
+ if (!space.debugger_access())
+ {
+ switch (offset)
+ {
+ case 0x0ff8:
+ case 0x0ff9:
+ m_base_bank = offset - 0x0ff8;
+ break;
+ }
+ }
+
+ return m_rom[offset + (m_base_bank * 0x1000) + (m_reset_bank * 0x2000)];
+}
+
+
+/*-------------------------------------------------
+ 32 in 1 Carts (Reset based):
+ the 2K banks change at each reset
+
+ GAMES: 32 in 1 cart
+
+ -------------------------------------------------*/
+
+READ8_MEMBER(a26_rom_32in1_device::read_rom)
+{
+ return m_rom[(offset & 0x7ff) + (m_base_bank * 0x800)];
+}