summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/bus/gameboy/rom.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/bus/gameboy/rom.cpp')
-rw-r--r--src/devices/bus/gameboy/rom.cpp1312
1 files changed, 1047 insertions, 265 deletions
diff --git a/src/devices/bus/gameboy/rom.cpp b/src/devices/bus/gameboy/rom.cpp
index d3e90d73f51..c3c7ab0e347 100644
--- a/src/devices/bus/gameboy/rom.cpp
+++ b/src/devices/bus/gameboy/rom.cpp
@@ -1,362 +1,1144 @@
// license:BSD-3-Clause
-// copyright-holders:Fabio Priuli, Wilbert Pol
+// copyright-holders:Vas Crabb, Wilbert Pol
/***********************************************************************************************************
Game Boy cart emulation
- Here we emulate carts with no RAM and simple bankswitch
+ Here we emulate carts without RAM banking.
+ TODO:
+ - YongYong:
+ - During start there are 2 writes to 5000 and 5003, it is still unknown what these do.
+ - Story of Lasama:
+ - This should display the Gowin logo on boot on both DMG and CGB (not implemented yet)
+ - Sachen MMC2:
+ - Does it monitor the address to detect RAM writes for logo spoofing, or just /CS?
+ - ATV Racing/Rocket Games:
+ - Does it monitor the address to detect RAM writes for logo spoofing, or just /CS?
+ - How does RAM banking work? Are over-size RAM chips just inaccessible?
+
***********************************************************************************************************/
#include "emu.h"
#include "rom.h"
+#include "cartbase.ipp"
-//-------------------------------------------------
-// gb_rom_device - constructor
-//-------------------------------------------------
+#include "bus/generic/slot.h"
-DEFINE_DEVICE_TYPE(GB_STD_ROM, gb_rom_device, "gb_rom", "GB Carts")
-DEFINE_DEVICE_TYPE(GB_ROM_TAMA5, gb_rom_tama5_device, "gb_rom_tama5", "GB Tamagotchi")
-DEFINE_DEVICE_TYPE(GB_ROM_WISDOM, gb_rom_wisdom_device, "gb_rom_wisdom", "GB Wisdom Tree Carts")
-DEFINE_DEVICE_TYPE(GB_ROM_YONG, gb_rom_yong_device, "gb_rom_yong", "GB Young Yong Carts")
-DEFINE_DEVICE_TYPE(GB_ROM_ATVRAC, gb_rom_atvrac_device, "gb_rom_atvrac", "GB ATV Racin'")
-DEFINE_DEVICE_TYPE(GB_ROM_LASAMA, gb_rom_lasama_device, "gb_rom_lasama", "GB LaSaMa")
+#include "corestr.h"
-DEFINE_DEVICE_TYPE(MEGADUCK_ROM, megaduck_rom_device, "megaduck_rom", "MegaDuck Carts")
+#include <memory>
+#include <optional>
+//#define VERBOSE 1
+//#define LOG_OUTPUT_FUNC osd_printf_info
+#include "logmacro.h"
-gb_rom_device::gb_rom_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
- : device_t(mconfig, type, tag, owner, clock)
- , device_gb_cart_interface(mconfig, *this)
-{
-}
-gb_rom_device::gb_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : gb_rom_device(mconfig, GB_STD_ROM, tag, owner, clock)
-{
-}
+namespace bus::gameboy {
-gb_rom_tama5_device::gb_rom_tama5_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : gb_rom_device(mconfig, GB_ROM_TAMA5, tag, owner, clock), m_tama5_data(0), m_tama5_addr(0), m_tama5_cmd(0), m_rtc_reg(0)
-{
-}
+namespace {
-gb_rom_wisdom_device::gb_rom_wisdom_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : gb_rom_device(mconfig, GB_ROM_WISDOM, tag, owner, clock)
-{
-}
+//**************************************************************************
+// Sachen MMC1/MMC2 ROM banking helper class (16 KiB * 256)
+//**************************************************************************
-gb_rom_yong_device::gb_rom_yong_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : gb_rom_device(mconfig, GB_ROM_YONG, tag, owner, clock)
+class sachen_mmc_device_base : public mbc_dual_uniform_device_base
{
-}
+protected:
+ sachen_mmc_device_base(machine_config const &mconfig, device_type type, char const *tag, device_t *owner, u32 clock) :
+ mbc_dual_uniform_device_base(mconfig, type, tag, owner, clock),
+ m_bank_mux_rom(0U),
+ m_bank_sel_rom{ 0U, 0U }
+ {
+ }
-gb_rom_atvrac_device::gb_rom_atvrac_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : gb_rom_device(mconfig, GB_ROM_ATVRAC, tag, owner, clock)
-{
-}
+ virtual void device_start() override ATTR_COLD
+ {
+ mbc_dual_uniform_device_base::device_start();
-gb_rom_lasama_device::gb_rom_lasama_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : gb_rom_device(mconfig, GB_ROM_LASAMA, tag, owner, clock)
-{
-}
+ save_item(NAME(m_bank_mux_rom));
+ save_item(NAME(m_bank_sel_rom));
+ }
+ virtual void device_reset() override ATTR_COLD
+ {
+ mbc_dual_uniform_device_base::device_reset();
-megaduck_rom_device::megaduck_rom_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
- : device_t(mconfig, type, tag, owner, clock)
- , device_gb_cart_interface(mconfig, *this)
-{
-}
+ m_bank_mux_rom = 0U;
+ m_bank_sel_rom[0] = 0U;
+ m_bank_sel_rom[1] = 1U;
+ update_banks();
+ }
-megaduck_rom_device::megaduck_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : megaduck_rom_device(mconfig, MEGADUCK_ROM, tag, owner, clock)
-{
-}
+ bool check_rom(std::string &message) ATTR_COLD
+ {
+ set_bank_bits_rom(8);
+ return mbc_dual_uniform_device_base::check_rom(message);
+ }
+ void install_bank_switch_handlers() ATTR_COLD
+ {
+ // A5, A3 and A2 are not connected to the controller (effective address mask 0xffd3)
+ cart_space()->install_write_handler(0x0000, 0x1fff, emu::rw_delegate(*this, FUNC(sachen_mmc_device_base::bank_rom_switch_outer)));
+ cart_space()->install_write_handler(0x2000, 0x3fff, emu::rw_delegate(*this, FUNC(sachen_mmc_device_base::bank_rom_switch_inner)));
+ cart_space()->install_write_handler(0x4000, 0x5fff, emu::rw_delegate(*this, FUNC(sachen_mmc_device_base::bank_rom_mux)));
+ }
-//-------------------------------------------------
-// shared_start
-//-------------------------------------------------
+ u8 rom_read(offs_t offset, bool spoof)
+ {
+ // holds A7 high when spoofing the logo
+ if (spoof)
+ offset |= 0x0080;
-void gb_rom_device::shared_start()
-{
- save_item(NAME(m_latch_bank));
- save_item(NAME(m_latch_bank2));
- save_item(NAME(m_ram_bank));
-}
+ // cartridge header area has address lines scrambled - A6 swapped with A0 and A4 swapped with A1
+ if (0x0100 == (offset & 0xff00))
+ offset = (offset & 0xff80) | bitswap<7>(offset, 0, 5, 1, 3, 2, 4, 6);
-//-------------------------------------------------
-// shared_reset
-//-------------------------------------------------
+ return (BIT(offset, 14) ? bank_rom_high_base() : bank_rom_low_base())[offset & 0x3fff];
+ }
-void gb_rom_device::shared_reset()
-{
- m_ram_bank = 0;
- m_latch_bank = 0;
- m_latch_bank2 = 1;
-}
+private:
+ void bank_rom_switch_outer(u8 data)
+ {
+ if (0x30 == (m_bank_sel_rom[1] & 0x30))
+ {
+ m_bank_sel_rom[0] = data;
+ update_banks();
+ }
+ }
+
+ void bank_rom_switch_inner(u8 data)
+ {
+ m_bank_sel_rom[1] = data ? data : 1;
+ u16 const hi(bank_rom_entry_high());
+ LOG(
+ "%s: Set ROM bank high = 0x%06X (0x%02X & 0x%02X | 0x%02X & 0x%02X)\n",
+ machine().describe_context(),
+ u32(hi) * 0x4000,
+ m_bank_sel_rom[0],
+ m_bank_mux_rom,
+ m_bank_sel_rom[1],
+ ~m_bank_mux_rom);
+ set_bank_rom_high(hi);
+ }
-//-------------------------------------------------
-// mapper specific start/reset
-//-------------------------------------------------
+ void bank_rom_mux(u8 data)
+ {
+ if (0x30 == (m_bank_sel_rom[1] & 0x30))
+ {
+ m_bank_mux_rom = data;
+ update_banks();
+ }
+ }
-void gb_rom_tama5_device::device_start()
-{
- shared_start();
- save_item(NAME(m_tama5_data));
- save_item(NAME(m_tama5_addr));
- save_item(NAME(m_tama5_cmd));
- save_item(NAME(m_regs));
- save_item(NAME(m_rtc_reg));
-}
-
-void gb_rom_tama5_device::device_reset()
+ u8 bank_rom_entry_low() const
+ {
+ return m_bank_sel_rom[0] & m_bank_mux_rom;
+ }
+
+ u8 bank_rom_entry_high() const
+ {
+ return (m_bank_sel_rom[0] & m_bank_mux_rom) | (m_bank_sel_rom[1] & ~m_bank_mux_rom);
+ }
+
+ void update_banks()
+ {
+ u16 const lo(bank_rom_entry_low());
+ u16 const hi(bank_rom_entry_high());
+ LOG(
+ "%s: Set ROM banks low = 0x%1$06X (0x%3$02X & 0x%5$02X), high = 0x%2$06X (0x%3$02X & 0x%5$02X | 0x%4$02X & 0x%6$02X)\n",
+ machine().describe_context(),
+ u32(lo) * 0x4000,
+ u32(hi) * 0x4000,
+ m_bank_sel_rom[0],
+ m_bank_sel_rom[1],
+ m_bank_mux_rom,
+ ~m_bank_mux_rom);
+ set_bank_rom_low(lo);
+ set_bank_rom_high(hi);
+ }
+
+ u8 m_bank_mux_rom;
+ u8 m_bank_sel_rom[2];
+};
+
+
+
+//**************************************************************************
+// Game Boy Color logo spoof used by Sachen and Rocket Games
+//**************************************************************************
+
+template <typename Base>
+class gbc_logo_spoof_device_base : public Base
{
- shared_reset();
- m_tama5_data = 0;
- m_tama5_addr= 0;
- m_tama5_cmd = 0;
- memset(m_regs, 0xff, sizeof(m_regs));
- m_rtc_reg = 0xff;
-}
+public:
+ using Base::logerror;
+
+protected:
+ gbc_logo_spoof_device_base(machine_config const &mconfig, device_type type, char const *tag, device_t *owner, u32 clock) :
+ Base(mconfig, type, tag, owner, clock),
+ m_ram_tap(),
+ m_notif_cart_space(),
+ m_counter(0U),
+ m_spoof_logo(0U),
+ m_installing_tap(false)
+ {
+ }
+
+ virtual void device_start() override ATTR_COLD
+ {
+ Base::device_start();
+
+ this->save_item(NAME(m_counter));
+ this->save_item(NAME(m_spoof_logo));
+ }
+
+ virtual void device_reset() override ATTR_COLD
+ {
+ Base::device_reset();
+
+ m_counter = 0U;
+ m_spoof_logo = 0U;
+
+ install_ram_tap();
+ m_notif_cart_space = this->cart_space()->add_change_notifier(
+ [this] (read_or_write mode)
+ {
+ if (u32(mode) & u32(read_or_write::WRITE))
+ install_ram_tap();
+ });
+ }
+
+ bool spoof_logo() const
+ {
+ return 1U == m_spoof_logo;
+ }
+
+ void rom_access()
+ {
+ if (!this->machine().side_effects_disabled())
+ {
+ // These cartridges work by counting low-to-high transitions on A15.
+ // CPU keeps A15 high while reading internal bootstrap ROM.
+ // Doing this on ROM reads is a good enough approximation for it to work.
+ if (0x30 != m_counter)
+ {
+ ++m_counter;
+ }
+ else
+ {
+ switch (m_spoof_logo)
+ {
+ case 0U:
+ m_counter = 1U;
+ [[fallthrough]];
+ case 1U:
+ ++m_spoof_logo;
+ m_notif_cart_space.reset();
+ m_ram_tap.remove();
+ LOG(
+ "%s: Spoof logo step %u\n",
+ this->machine().describe_context(),
+ m_spoof_logo);
+ }
+ }
+ }
+ }
+
+private:
+ void install_ram_tap()
+ {
+ if (!m_installing_tap)
+ {
+ m_installing_tap = true;
+ m_ram_tap.remove();
+ if (!m_spoof_logo)
+ {
+ m_ram_tap = this->cart_space()->install_write_tap(
+ 0xc000, 0xdfff,
+ "ram_tap_w",
+ [this] (offs_t offset, u8 &data, u8 mem_mask)
+ {
+ assert(!m_spoof_logo);
+
+ if (!this->machine().side_effects_disabled())
+ {
+ m_counter = 0U;
+ ++m_spoof_logo;
+ LOG(
+ "%s: Spoof logo step %u\n",
+ this->machine().describe_context(),
+ m_spoof_logo);
+ m_notif_cart_space.reset();
+ m_ram_tap.remove();
+ }
+ },
+ &m_ram_tap);
+ }
+ else
+ {
+ m_notif_cart_space.reset();
+ }
+ m_installing_tap = false;
+ }
+ }
+
+ memory_passthrough_handler m_ram_tap;
+ util::notifier_subscription m_notif_cart_space;
+
+ u8 m_counter;
+ u8 m_spoof_logo;
+ bool m_installing_tap;
+};
+
+
+//**************************************************************************
+// Mega Duck flat ROM (max 32 KiB)
+//**************************************************************************
-// these are identical to shared ones above, but megaduck cart class is not derived from gb cart class...
-void megaduck_rom_device::device_start()
+class megaduck_flat_device : public device_t, public device_gb_cart_interface
{
- save_item(NAME(m_latch_bank));
- save_item(NAME(m_latch_bank2));
- save_item(NAME(m_ram_bank));
-}
+public:
+ megaduck_flat_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock) :
+ megaduck_flat_device(mconfig, MEGADUCK_ROM_STD, tag, owner, clock)
+ {
+ }
+
+ virtual std::error_condition load(std::string &message) override ATTR_COLD
+ {
+ // if there's no ROM region, there's nothing to do
+ memory_region *const romregion(cart_rom_region());
+ if (!romregion || !romregion->bytes())
+ return std::error_condition();
+
+ // check for supported size
+ auto const bytes(romregion->bytes());
+ if (0x8000 < bytes)
+ {
+ message = "Unsupported cartridge ROM size (must be no larger than 32 KiB)";
+ return image_error::INVALIDLENGTH;
+ }
+
+ // install ROM
+ device_generic_cart_interface::install_non_power_of_two<0>(
+ bytes,
+ 0x7fff,
+ 0,
+ 0x0000,
+ [this, base = &romregion->as_u8()] (offs_t begin, offs_t end, offs_t mirror, offs_t src)
+ {
+ LOG(
+ "Install ROM 0x%04X-0x%04X at 0x%04X-0x%04X mirror 0x%04X\n",
+ src,
+ src + (end - begin),
+ begin,
+ end,
+ mirror);
+ cart_space()->install_rom(begin, end, mirror, &base[src]);
+ });
+
+ // all good
+ return std::error_condition();
+ }
+
+protected:
+ megaduck_flat_device(machine_config const &mconfig, device_type type, char const *tag, device_t *owner, u32 clock) :
+ device_t(mconfig, type, tag, owner, clock),
+ device_gb_cart_interface(mconfig, *this)
+ {
+ }
+
+ virtual void device_start() override ATTR_COLD
+ {
+ }
+};
-void megaduck_rom_device::device_reset()
+
+
+//**************************************************************************
+// Mega Duck banked ROM (16 KiB fixed + 16 KiB * 256 or 32 KiB * 256)
+//**************************************************************************
+
+class megaduck_banked_device : public device_t, public device_gb_cart_interface
{
- m_ram_bank = 0;
- m_latch_bank = 0;
- m_latch_bank2 = 1;
-}
+public:
+ megaduck_banked_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock) :
+ device_t(mconfig, MEGADUCK_ROM_BANKED, tag, owner, clock),
+ device_gb_cart_interface(mconfig, *this),
+ m_bank_rom_low(*this, "low"),
+ m_bank_rom_high(*this, "high"),
+ m_bank_mask_rom{ 0U, 0U }
+ {
+ }
+
+ virtual std::error_condition load(std::string &message) override ATTR_COLD
+ {
+ // if there's no ROM region, there's nothing to do
+ memory_region *const romregion(cart_rom_region());
+ if (!romregion || !romregion->bytes())
+ {
+ // setting default bank on reset causes a fatal error when no banks are configured
+ message = "No ROM data found";
+ return image_error::BADSOFTWARE;
+ }
+
+ // work out whether a fixed bank is required
+ auto const bytes(romregion->bytes());
+ char const *const fixedbank_explicit(get_feature("fixedbank"));
+ std::optional<bool> fixedbank;
+ if (fixedbank_explicit)
+ {
+ // explicitly specified in software list
+ if (util::streqlower(fixedbank_explicit, "yes") || util::streqlower(fixedbank_explicit, "true"))
+ {
+ fixedbank = true;
+ }
+ else if (util::streqlower(fixedbank_explicit, "no") || util::streqlower(fixedbank_explicit, "false"))
+ {
+ fixedbank = false;
+ }
+ else
+ {
+ message = "Invalid 'fixedbank' feature value (must be yes or no)";
+ return image_error::BADSOFTWARE;
+ }
+ }
+ else if (bytes & 0x7fff)
+ {
+ // if it isn't a multiple of 32 KiB, it only makes sense with a fixed bank
+ fixedbank = true;
+ }
+ else if ((0x4000 * 0x100) < bytes)
+ {
+ // if it's larger than 4 MiB, it doesn't make sense with a fixed bank
+ fixedbank = false;
+ }
+
+ // reject unsupported sizes
+ if ((bytes & 0x3fff) || ((0x8000 * 0x100) < bytes) || (fixedbank && (*fixedbank ? ((0x4000 * 0x100) < bytes) : (bytes & 0x7fff))))
+ {
+ message = "Unsupported cartridge ROM size (must be a multiple of bank size and no larger than 256 entries)";
+ return image_error::INVALIDLENGTH;
+ }
+
+ // configure banks - low bank has 32 KiB entries, high bank has 16 KiB entries
+ auto const base(&romregion->as_u8());
+ m_bank_mask_rom[0] = device_generic_cart_interface::map_non_power_of_two(
+ unsigned(bytes / 0x8000),
+ [this, base] (unsigned entry, unsigned page)
+ {
+ LOG(
+ "Install ROM 0x%04X-0x%04X in low bank entry %u\n",
+ page * 0x8000,
+ (page * 0x8000) + 0x7fff,
+ entry);
+ m_bank_rom_low->configure_entry(entry, &base[page * 0x8000]);
+ });
+ m_bank_mask_rom[1] = device_generic_cart_interface::map_non_power_of_two(
+ unsigned(bytes / 0x4000),
+ [this, base] (unsigned entry, unsigned page)
+ {
+ LOG(
+ "Install ROM 0x%04X-0x%04X in high bank entry %u\n",
+ page * 0x4000,
+ (page * 0x4000) + 0x3fff,
+ entry);
+ m_bank_rom_high->configure_entry(entry, &base[page * 0x4000]);
+ });
+
+ // install handlers
+ if (!fixedbank)
+ {
+ // can't tell whether this cartridge has a fixed low bank, take a bet each way
+ logerror("Installing banked ROM at 0x0000-0x3FFF and 0x4000-0x7FFF\n");
+ cart_space()->install_read_bank(0x0000, 0x3fff, m_bank_rom_low);
+ cart_space()->install_read_bank(0x4000, 0x7fff, m_bank_rom_high);
+ cart_space()->install_write_handler(0x0001, 0x0001, emu::rw_delegate(*this, FUNC(megaduck_banked_device::bank_rom_switch_high)));
+ cart_space()->install_write_handler(0xb000, 0xb000, emu::rw_delegate(*this, FUNC(megaduck_banked_device::bank_rom_switch)));
+ }
+ else if (*fixedbank)
+ {
+ // fixed ROM at 0x0000-0x3fff, banked ROM at 0x4000-0x7fff
+ logerror("Installing fixed ROM at 0x0000-0x3FFF and banked ROM at 0x4000-0x7FFF\n");
+ cart_space()->install_rom(0x0000, 0x3fff, base);
+ cart_space()->install_read_bank(0x4000, 0x7fff, m_bank_rom_high);
+ cart_space()->install_write_handler(0x0001, 0x0001, emu::rw_delegate(*this, FUNC(megaduck_banked_device::bank_rom_switch_high)));
+ }
+ else
+ {
+ // banked ROM at 0x0000-0x7fff
+ logerror("Installing banked ROM at 0x0000-0x7FFF\n");
+ cart_space()->install_read_bank(0x0000, 0x7fff, m_bank_rom_low);
+ cart_space()->install_write_handler(0xb000, 0xb000, emu::rw_delegate(*this, FUNC(megaduck_banked_device::bank_rom_switch_low)));
+ }
+
+ // all good
+ return std::error_condition();
+ }
+
+protected:
+ virtual void device_start() override ATTR_COLD
+ {
+ }
+
+ virtual void device_reset() override ATTR_COLD
+ {
+ m_bank_rom_low->set_entry(0 & m_bank_mask_rom[0]);
+ m_bank_rom_high->set_entry(1 & m_bank_mask_rom[1]);
+ }
+
+private:
+ void bank_rom_switch_low(u8 data)
+ {
+ u8 const lo = data & m_bank_mask_rom[0];
+ LOG(
+ "%s: Set ROM bank low = 0x%04X\n",
+ machine().describe_context(),
+ lo * 0x8000);
+ m_bank_rom_low->set_entry(lo);
+ }
+
+ void bank_rom_switch_high(u8 data)
+ {
+ u8 const hi = data & m_bank_mask_rom[1];
+ LOG(
+ "%s: Set ROM bank high = 0x%04X\n",
+ machine().describe_context(),
+ hi * 0x4000);
+ m_bank_rom_high->set_entry(hi);
+ }
+
+ void bank_rom_switch(u8 data)
+ {
+ u8 const lo = data & m_bank_mask_rom[0];
+ u8 const hi = ((data * 2) + 1) & m_bank_mask_rom[1];
+ LOG(
+ "%s: Set ROM banks low = 0x%04X, high = 0x%04X\n",
+ machine().describe_context(),
+ lo * 0x8000,
+ hi * 0x4000);
+ m_bank_rom_low->set_entry(lo);
+ m_bank_rom_high->set_entry(hi);
+ }
+
+ memory_bank_creator m_bank_rom_low;
+ memory_bank_creator m_bank_rom_high;
+ u8 m_bank_mask_rom[2];
+};
+
-/*-------------------------------------------------
- mapper specific handlers
- -------------------------------------------------*/
+//**************************************************************************
+// Game Boy flat ROM/RAM (max 32 KiB ROM, 8 KiB RAM)
+//**************************************************************************
-uint8_t gb_rom_device::read_rom(offs_t offset)
+class flat_rom_ram_device : public flat_ram_device_base<megaduck_flat_device>
{
- m_latch_bank = offset / 0x4000;
- return m_rom[rom_bank_map[m_latch_bank] * 0x4000 + (offset & 0x3fff)];
-}
+public:
+ flat_rom_ram_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock) :
+ flat_ram_device_base<megaduck_flat_device>(mconfig, GB_ROM_STD, tag, owner, clock)
+ {
+ }
+
+ virtual std::error_condition load(std::string &message) override ATTR_COLD
+ {
+ // first set up cartridge RAM if any
+ if (!check_ram(message))
+ return image_error::BADSOFTWARE;
+
+ // ROM is installed the same way as a Mega Duck flat ROM cartridge
+ std::error_condition const romresult(megaduck_flat_device::load(message));
+ if (romresult)
+ return romresult;
+ install_ram();
+
+ // all good
+ return std::error_condition();
+ }
+};
-uint8_t gb_rom_device::read_ram(offs_t offset)
+
+
+//**************************************************************************
+// M161 (32 KiB * 8)
+//**************************************************************************
+
+class m161_device : public flat_ram_device_base<banked_32k_device_base>
{
- if (!m_ram.empty())
- return m_ram[ram_bank_map[m_ram_bank] * 0x2000 + offset];
- else
- return 0xff;
-}
+public:
+ m161_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock) :
+ flat_ram_device_base<banked_32k_device_base>(mconfig, GB_ROM_M161, tag, owner, clock),
+ m_bank_lock(0U)
+ {
+ }
+
+ virtual std::error_condition load(std::string &message) override ATTR_COLD
+ {
+ // set up ROM
+ set_bank_bits_rom(8); // 74HC161A - 3-bit bank, 1-bit lockout
+ if (!check_rom(message))
+ return image_error::BADSOFTWARE;
+ install_rom();
+ install_ram();
+
+ // install bank switch handler
+ cart_space()->install_write_handler(0x0000, 0x7fff, emu::rw_delegate(*this, FUNC(m161_device::bank_rom_switch)));
+
+ // all good
+ return std::error_condition();
+ }
-void gb_rom_device::write_ram(offs_t offset, uint8_t data)
+private:
+ virtual void device_start() override ATTR_COLD
+ {
+ flat_ram_device_base<banked_32k_device_base>::device_start();
+
+ save_item(NAME(m_bank_lock));
+ }
+
+ virtual void device_reset() override ATTR_COLD
+ {
+ flat_ram_device_base<banked_32k_device_base>::device_reset();
+
+ m_bank_lock = 0U;
+
+ set_bank_rom(0);
+ }
+
+ void bank_rom_switch(offs_t offset, u8 data)
+ {
+ if (!m_bank_lock)
+ {
+ m_bank_lock = 1U; // D connected to Vcc
+ set_bank_rom(data & 0x07); // A/B/C connected to D0/D1/D2
+ }
+ }
+
+ u8 m_bank_lock;
+};
+
+
+
+//**************************************************************************
+// Wisdom Tree (theoretical 32 KiB * 16,386, limited to 32 KiB * 256)
+//**************************************************************************
+
+class wisdom_device : public flat_ram_device_base<banked_32k_device_base>
{
- if (!m_ram.empty())
- m_ram[ram_bank_map[m_ram_bank] * 0x2000 + offset] = data;
-}
+public:
+ wisdom_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock) :
+ flat_ram_device_base<banked_32k_device_base>(mconfig, GB_ROM_WISDOM, tag, owner, clock)
+ {
+ }
+
+ virtual std::error_condition load(std::string &message) override ATTR_COLD
+ {
+ // set up ROM
+ set_bank_bits_rom(8); // 8 MiB real-world limit with 74LS377 - change to 14 for 512 MiB theoretical limit
+ if (!check_rom(message))
+ return image_error::BADSOFTWARE;
+ install_rom();
+ install_ram();
+ set_bank_rom(0);
+ // install bank switch handler
+ cart_space()->install_write_handler(0x0000, 0x3fff, emu::rw_delegate(*this, FUNC(wisdom_device::bank_rom_switch)));
+
+ // all good
+ return std::error_condition();
+ }
+
+private:
+ void bank_rom_switch(offs_t offset, u8 data)
+ {
+ set_bank_rom(offset);
+ }
+};
-// Tamagotchi
-uint8_t gb_rom_tama5_device::read_rom(offs_t offset)
+
+//**************************************************************************
+// Yong Yong Pirate
+//**************************************************************************
+
+class yong_device : public flat_ram_device_base<mbc_device_base>
{
- if (offset < 0x4000)
- return m_rom[rom_bank_map[m_latch_bank] * 0x4000 + (offset & 0x3fff)];
- else
- return m_rom[rom_bank_map[m_latch_bank2] * 0x4000 + (offset & 0x3fff)];
-}
+public:
+ yong_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock) :
+ flat_ram_device_base<mbc_device_base>(mconfig, GB_ROM_YONG, tag, owner, clock)
+ {
+ }
+
+ virtual std::error_condition load(std::string &message) override ATTR_COLD
+ {
+ // set up ROM/RAM
+ set_bank_bits_rom(8);
+ if (!check_rom(message))
+ return image_error::BADSOFTWARE;
+ install_rom();
+ install_ram();
+
+ // install bank switch handler
+ cart_space()->install_write_handler(0x2000, 0x2000, emu::rw_delegate(*this, FUNC(yong_device::bank_rom_switch)));
+
+ // all good
+ return std::error_condition();
+ }
+
+protected:
+ virtual void device_reset() override ATTR_COLD
+ {
+ flat_ram_device_base<mbc_device_base>::device_reset();
+
+ set_bank_rom(1);
+ }
+
+private:
+ void bank_rom_switch(u8 data)
+ {
+ set_bank_rom(data);
+ }
+};
+
+
-uint8_t gb_rom_tama5_device::read_ram(offs_t offset)
+//**************************************************************************
+// MBC1 variant used by Yong Yong for Rockman 8
+//**************************************************************************
+
+class rockman8_device : public flat_ram_device_base<mbc_device_base>
{
- return m_rtc_reg;
-}
+public:
+ rockman8_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock) :
+ flat_ram_device_base<mbc_device_base>(mconfig, GB_ROM_ROCKMAN8, tag, owner, clock)
+ {
+ }
+
+ virtual std::error_condition load(std::string &message) override ATTR_COLD
+ {
+ // set up ROM/RAM
+ set_bank_bits_rom(5);
+ if (!check_rom(message))
+ return image_error::BADSOFTWARE;
+ install_rom();
+ install_ram();
+
+ // install bank switch handler
+ cart_space()->install_write_handler(0x2000, 0x3fff, emu::rw_delegate(*this, FUNC(rockman8_device::bank_rom_switch)));
+
+ // all good
+ return std::error_condition();
+ }
+
+protected:
+ virtual void device_reset() override ATTR_COLD
+ {
+ flat_ram_device_base<mbc_device_base>::device_reset();
+
+ set_bank_rom(1);
+ }
+
+private:
+ void bank_rom_switch(u8 data)
+ {
+ data &= 0x1f;
+ set_bank_rom(!data ? 1 : (0x0f < data) ? (data - 8) : data);
+ }
+};
+
+
-void gb_rom_tama5_device::write_ram(offs_t offset, uint8_t data)
+//**************************************************************************
+// MBC1 variant used by Yong Yong for Super Mario 3 Special
+//**************************************************************************
+/*
+ Mario special seems to be a 512k image (mirrored up to 1M or 2M [redump needed to establish this])
+ it consists of 13 unique 16k chunks laid out as follows
+ unique chunk --> bank in bin
+ 1st to 7th --> 0x00 to 0x06
+ 8th --> 0x08
+ 9th --> 0x0b
+ 10th --> 0x0c
+ 11th --> 0x0d
+ 12th --> 0x0f
+ 13th --> 0x13
+
+ According to old doc from Brian Provinciano, writing bit 5 in 0x5000-0x5fff should
+ change the bank layout, in the sense that writing to bank switch acts like if
+ the original ROm has a different layout (as if unique chunks were under permutations
+ (24), (365) and (8a9) with 0,1,7,b,c fixed) and the same table above is used.
+ However, no such a write ever happen (only bit 4 is written, but changing mode with
+ bit 4 breaks the graphics).
+ */
+
+class sm3sp_device : public flat_ram_device_base<mbc_device_base>
{
- switch (offset & 0x0001)
+public:
+ sm3sp_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock) :
+ flat_ram_device_base<mbc_device_base>(mconfig, GB_ROM_SM3SP, tag, owner, clock),
+ m_bank_rom_mode(0U)
{
- case 0x0000: /* Write to data register */
- switch (m_tama5_cmd)
- {
- case 0x00: /* Bits 0-3 for rom bank selection */
- m_latch_bank2 = (m_latch_bank2 & 0xf0) | (data & 0x0f);
- break;
- case 0x01: /* Bit 4(-7?) for rom bank selection */
- m_latch_bank2 = (m_latch_bank2 & 0x0f) | ((data & 0x0f) << 4);
- break;
- case 0x04: /* Data to write lo */
- m_tama5_data = (m_tama5_data & 0xf0) | (data & 0x0f);
- break;
- case 0x05: /* Data to write hi */
- m_tama5_data = (m_tama5_data & 0x0f) | ((data & 0x0f) << 4);
- break;
- case 0x06: /* Address selection hi */
- m_tama5_addr = (m_tama5_addr & 0x0f) | ((data & 0x0f) << 4);
- break;
- case 0x07: /* Address selection lo */
- /* This address always seems to written last, so we'll just
- execute the command here */
- m_tama5_addr = (m_tama5_addr & 0xf0) | (data & 0x0f);
- switch (m_tama5_addr & 0xe0)
- {
- case 0x00: /* Write memory */
- //logerror( "Write tama5 memory 0x%02X <- 0x%02X\n", m_tama5_addr & 0x1f, m_tama5_data);
- m_regs[m_tama5_addr & 0x1f] = m_tama5_data;
- break;
- case 0x20: /* Read memory */
- //logerror( "Read tama5 memory 0x%02X\n", m_tama5_addr & 0x1f);
- m_tama5_data = m_regs[m_tama5_addr & 0x1f];
- break;
- case 0x40: /* Unknown, some kind of read */
- if ((m_tama5_addr & 0x1f) == 0x12)
- m_tama5_data = 0xff;
- case 0x80: /* Unknown, some kind of read (when 07=01)/write (when 07=00/02) */
- default:
- logerror( "%s Unknown addressing mode\n", machine().describe_context() );
- break;
- }
- break;
- }
- break;
- case 0x0001: /* Write to control register */
- switch (data)
+ }
+
+ virtual std::error_condition load(std::string &message) override ATTR_COLD
+ {
+ // set up ROM/RAM
+ set_bank_bits_rom(5);
+ if (!check_rom(message))
+ return image_error::BADSOFTWARE;
+ install_rom();
+ install_ram();
+
+ // install bank switch handler
+ cart_space()->install_write_handler(0x2000, 0x2fff, emu::rw_delegate(*this, FUNC(sm3sp_device::bank_rom_switch)));
+ cart_space()->install_write_handler(0x5000, 0x5fff, emu::rw_delegate(*this, FUNC(sm3sp_device::bank_rom_mode)));
+
+ // all good
+ return std::error_condition();
+ }
+
+protected:
+ virtual void device_start() override ATTR_COLD
+ {
+ flat_ram_device_base<mbc_device_base>::device_start();
+
+ save_item(NAME(m_bank_rom_mode));
+ }
+
+ virtual void device_reset() override ATTR_COLD
+ {
+ flat_ram_device_base<mbc_device_base>::device_reset();
+
+ m_bank_rom_mode = 0U;
+
+ set_bank_rom(1);
+ }
+
+private:
+ void bank_rom_switch(u8 data)
+ {
+ /*
+ writing data to 0x2000-0x2fff switches bank according to the table below
+ (the value values corresponding to table[0x0f] is not confirmed, choices
+ 0,1,2,3,8,c,f freeze the game, while 4,5,6,7,b,d,0x13 work with glitches)
+
+ Table 1 confirmed...
+ 0 -> 0
+ 4 -> 2
+ 6 -> 3
+ 19 -> 5 (level 2 background graphics)
+ 1b -> 8 (level 3 background graphics)
+ 1c -> b (bonus house background graphics)
+ 1d -> d (level 4 background graphics)
+ 1e -> 6 (level 1 background graphics)
+ 1 (9 maybe, or 3)? f (5 maybe)? 2->1?
+ 16 -> 4-8? b?
+ */
+ static constexpr u8 BANK_TABLE[0x20] = {
+ 0x00,0x04,0x01,0x05, 0x02,0x06,0x03,0x05,
+ 0x08,0x0c,0x03,0x0d, 0x03,0x0b,0x0b,0x08 /* original doc put 0x0f here (i.e. 11th unique bank) */,
+ 0x05,0x06,0x0b,0x0d, 0x08,0x06,0x13,0x0b,
+ 0x08,0x05,0x05,0x08, 0x0b,0x0d,0x06,0x05 };
+
+ u8 const lookup(BANK_TABLE[data & 0x1f]);
+ u8 remap(lookup);
+ if (m_bank_rom_mode)
+ {
+ switch (lookup)
{
- case 0x00: /* Bits 0-3 for rom bank selection */
- case 0x01: /* Bits 4-7 for rom bank selection */
- case 0x04: /* Data write register lo */
- case 0x05: /* Data write register hi */
- case 0x06: /* Address register hi */
- case 0x07: /* Address register lo */
- break;
- case 0x0a: /* Are we ready for the next command? */
- m_rtc_reg = 0x01;
- break;
- case 0x0c: /* Data read register lo */
- m_rtc_reg = m_tama5_data & 0x0f;
- break;
- case 0x0d: /* Data read register hi */
- m_rtc_reg = (m_tama5_data & 0xf0) >> 4;
- break;
+ case 0x02: remap = 0x04; break;
+ case 0x03: remap = 0x06; break;
+ case 0x04: remap = 0x02; break;
+ case 0x05: remap = 0x03; break;
+ case 0x06: remap = 0x05; break;
+ case 0x0b: remap = 0x0d; break;
+ case 0x0c: remap = 0x0b; break;
+ case 0x0d: remap = 0x0c; break;
+
+ case 0x00:
+ case 0x01:
+ case 0x08:
+ case 0x0f:
+ case 0x13:
default:
- logerror( "%s Unknown tama5 command 0x%02X\n", machine().describe_context(), data );
break;
}
- m_tama5_cmd = data;
- break;
+ }
+ LOG(
+ "%s: Bank select 0x%02X -> 0x%02X -> 0x%02X\n",
+ machine().describe_context(),
+ data,
+ lookup,
+ remap);
+ set_bank_rom(remap);
}
-}
+ void bank_rom_mode(u8 data)
+ {
+ LOG("%s: Bank mode 0x%02X\n", machine().describe_context(), data);
+ m_bank_rom_mode = BIT(data, 5);
+ }
+
+ u8 m_bank_rom_mode;
+};
-// Wisdom Tree
-uint8_t gb_rom_wisdom_device::read_rom(offs_t offset)
-{
- return m_rom[rom_bank_map[m_latch_bank] * 0x4000 + offset];
-}
-void gb_rom_wisdom_device::write_bank(offs_t offset, uint8_t data)
+//**************************************************************************
+// Sachen MMC1 unlicensed
+//**************************************************************************
+
+class sachen_mmc1_device : public sachen_mmc_device_base
{
- if (offset < 0x4000)
- m_latch_bank = (offset << 1) & 0x1ff;
-}
+public:
+ sachen_mmc1_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock) :
+ sachen_mmc_device_base(mconfig, GB_ROM_SACHEN1, tag, owner, clock),
+ m_counter(0U)
+ {
+ }
+ virtual std::error_condition load(std::string &message) override ATTR_COLD
+ {
+ // configure ROM banks but don't install directly
+ if (!check_rom(message))
+ return image_error::BADSOFTWARE;
+ configure_bank_rom();
-// Yong Yong pirate
+ // actually install ROM and bank switch handlers
+ logerror("Installing banked ROM at 0x0000-0x3FFF and 0x4000-0x7FFF\n");
+ cart_space()->install_read_handler(0x0000, 0x7fff, emu::rw_delegate(*this, FUNC(sachen_mmc1_device::read_rom)));
+ install_bank_switch_handlers();
-uint8_t gb_rom_yong_device::read_rom(offs_t offset)
-{
- if (offset < 0x4000)
- return m_rom[rom_bank_map[m_latch_bank] * 0x4000 + (offset & 0x3fff)];
- else
- return m_rom[rom_bank_map[m_latch_bank2] * 0x4000 + (offset & 0x3fff)];
-}
+ // all good
+ return std::error_condition();
+ }
-void gb_rom_yong_device::write_bank(offs_t offset, uint8_t data)
-{
- if (offset == 0x2000)
- m_latch_bank2 = data;
-}
+protected:
+ virtual void device_start() override ATTR_COLD
+ {
+ sachen_mmc_device_base::device_start();
+
+ save_item(NAME(m_counter));
+ }
+ virtual void device_reset() override ATTR_COLD
+ {
+ sachen_mmc_device_base::device_reset();
-// ATV Racin pirate (incomplete)
+ m_counter = 0U;
+ }
-uint8_t gb_rom_atvrac_device::read_rom(offs_t offset)
-{
- if (offset < 0x4000)
- return m_rom[rom_bank_map[m_latch_bank] * 0x4000 + (offset & 0x3fff)];
- else
- return m_rom[rom_bank_map[m_latch_bank2] * 0x4000 + (offset & 0x3fff)];
-}
+private:
+ u8 read_rom(offs_t offset)
+ {
+ if (!machine().side_effects_disabled())
+ {
+ // These cartridges work by counting low-to-high transitions on A15.
+ // CPU keeps A15 high while reading internal bootstrap ROM.
+ // Doing this on ROM reads is a good enough approximation for it to work.
+ if (0x31 != m_counter)
+ ++m_counter;
+ }
+
+ return rom_read(offset, 0x31 != m_counter);
+ }
+
+ u8 m_counter;
+};
+
+
+
+//**************************************************************************
+// Sachen MMC2 unlicensed
+//**************************************************************************
-void gb_rom_atvrac_device::write_bank(offs_t offset, uint8_t data)
+class sachen_mmc2_device : public gbc_logo_spoof_device_base<sachen_mmc_device_base>
{
- if (offset == 0x3f00)
+public:
+ sachen_mmc2_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock) :
+ gbc_logo_spoof_device_base<sachen_mmc_device_base>(mconfig, GB_ROM_SACHEN2, tag, owner, clock)
{
- if (data == 0)
- data = 1;
- m_latch_bank2 = m_latch_bank | data;
}
- if (offset == 0x3fc0)
- m_latch_bank = data * 16;
-}
-// La Sa Ma pirate (incomplete)
+ virtual std::error_condition load(std::string &message) override ATTR_COLD
+ {
+ // configure ROM banks but don't install directly
+ if (!check_rom(message))
+ return image_error::BADSOFTWARE;
+ configure_bank_rom();
+
+ // actually install ROM and bank switch handlers
+ logerror("Installing banked ROM at 0x0000-0x3FFF and 0x4000-0x7FFF\n");
+ cart_space()->install_read_handler(0x0000, 0x7fff, emu::rw_delegate(*this, FUNC(sachen_mmc2_device::read_rom)));
+ install_bank_switch_handlers();
+
+ // all good
+ return std::error_condition();
+ }
+
+private:
+ u8 read_rom(offs_t offset)
+ {
+ rom_access();
+ return rom_read(offset, spoof_logo());
+ }
+};
+
+
+
+//**************************************************************************
+// Rocket Games unlicensed (incomplete)
+//**************************************************************************
-uint8_t gb_rom_lasama_device::read_rom(offs_t offset)
+class rocket_device : public flat_ram_device_base<gbc_logo_spoof_device_base<mbc_dual_device_base> >
{
- if (offset < 0x4000)
- return m_rom[rom_bank_map[m_latch_bank] * 0x4000 + (offset & 0x3fff)];
- else
- return m_rom[rom_bank_map[m_latch_bank2] * 0x4000 + (offset & 0x3fff)];
-}
+public:
+ rocket_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock) :
+ flat_ram_device_base<gbc_logo_spoof_device_base<mbc_dual_device_base> >(mconfig, GB_ROM_ROCKET, tag, owner, clock)
+ {
+ }
+
+ virtual std::error_condition load(std::string &message) override ATTR_COLD
+ {
+ // configure ROM banks but don't install directly
+ set_bank_bits_rom(8, 4);
+ if (!check_rom(message))
+ return image_error::BADSOFTWARE;
+ configure_bank_rom();
+ install_ram();
+
+ // actually install ROM and bank switch handlers
+ logerror("Installing banked ROM at 0x0000-0x3FFF and 0x4000-0x7FFF\n");
+ cart_space()->install_read_handler(0x0000, 0x7fff, emu::rw_delegate(*this, FUNC(rocket_device::read_rom)));
+ cart_space()->install_write_handler(0x3f00, 0x3f00, emu::rw_delegate(*this, FUNC(rocket_device::bank_rom_switch_fine)));
+ cart_space()->install_write_handler(0x3fc0, 0x3fc0, emu::rw_delegate(*this, FUNC(rocket_device::bank_rom_switch_coarse)));
+
+ // all good
+ return std::error_condition();
+ }
+
+protected:
+ virtual void device_reset() override ATTR_COLD
+ {
+ flat_ram_device_base<gbc_logo_spoof_device_base<mbc_dual_device_base> >::device_reset();
+
+ set_bank_rom_coarse(0);
+ set_bank_rom_fine(1);
+ }
+
+private:
+ u8 read_rom(offs_t offset)
+ {
+ // logo spoofing logic
+ rom_access();
+
+ // fetch the banked ROM data
+ u8 const data((BIT(offset, 14) ? bank_rom_high_base() : bank_rom_low_base())[offset & 0x3fff]);
+ if (spoof_logo() && (0x0104 <= offset) && (0x133 >= offset))
+ {
+ static constexpr u8 TRANSFORM[] = {
+ 0xdf, 0xce, 0x97, 0x78, 0xcd, 0x2f, 0xf0, 0x0b, 0x0b, 0xea, 0x78, 0x83, 0x08, 0x1d, 0x9a, 0x45,
+ 0x11, 0x2b, 0xe1, 0x11, 0xf8, 0x88, 0xf8, 0x8e, 0xfe, 0x88, 0x2a, 0xc4, 0xff, 0xfc, 0xd9, 0x87,
+ 0x22, 0xab, 0x67, 0x7d, 0x77, 0x2c, 0xa8, 0xee, 0xff, 0x9b, 0x99, 0x91, 0xaa, 0x9b, 0x33, 0x3e };
+ return data ^ TRANSFORM[offset - 0x104];
+ }
+ else
+ {
+ return data;
+ }
+ }
+
+ void bank_rom_switch_fine(u8 data)
+ {
+ set_bank_rom_fine(data ? data : 1);
+ }
+
+ void bank_rom_switch_coarse(u8 data)
+ {
+ set_bank_rom_coarse(data);
+ }
+};
+
+
-void gb_rom_lasama_device::write_bank(offs_t offset, uint8_t data)
+//**************************************************************************
+// Story of Lasama pirate (incomplete)
+//**************************************************************************
+
+class lasama_device : public flat_ram_device_base<mbc_dual_device_base>
{
- if (offset == 0x2080)
+public:
+ lasama_device(machine_config const &mconfig, char const *tag, device_t *owner, uint32_t clock) :
+ flat_ram_device_base<mbc_dual_device_base>(mconfig, GB_ROM_LASAMA, tag, owner, clock)
+ {
+ }
+
+ virtual std::error_condition load(std::string &message) override ATTR_COLD
+ {
+ // set up ROM/RAM
+ set_bank_bits_rom(1, 2);
+ if (!check_rom(message))
+ return image_error::BADSOFTWARE;
+ install_rom();
+ install_ram();
+
+ // install bank switch handlers
+ cart_space()->install_write_handler(0x2080, 0x2080, emu::rw_delegate(*this, FUNC(lasama_device::ctrl_2080_w)));
+ cart_space()->install_write_handler(0x6000, 0x6000, emu::rw_delegate(*this, FUNC(lasama_device::ctrl_6000_w)));
+
+ // all good
+ return std::error_condition();
+ }
+
+protected:
+ virtual void device_reset() override ATTR_COLD
+ {
+ flat_ram_device_base<mbc_dual_device_base>::device_reset();
+
+ set_bank_rom_coarse(0);
+ set_bank_rom_fine(1);
+ }
+
+private:
+ void ctrl_2080_w(u8 data)
{
- // Actual banking?
- m_latch_bank2 = m_latch_bank | (data & 0x03);
+ // high ROM fine bank?
+ set_bank_rom_fine(data & 0x03);
}
- if (offset == 0x6000)
+
+ void ctrl_6000_w(u8 data)
{
// On boot the following two get written right after each other:
// 02
// BE
- // Disable logo switching?
- if (!(data & 0x80))
- m_latch_bank = (data & 0x02) << 1;
+ // disable logo switching?
+ if (!BIT(data, 7))
+ set_bank_rom_coarse(BIT(data, 1));
}
-}
+};
+} // anonymous namespace
-// MegaDuck carts
+} // namespace bus::gameboy
-uint8_t megaduck_rom_device::read_rom(offs_t offset)
-{
- if (offset < 0x4000)
- return m_rom[rom_bank_map[m_latch_bank] * 0x4000 + (offset & 0x3fff)];
- else
- return m_rom[rom_bank_map[m_latch_bank2] * 0x4000 + (offset & 0x3fff)];
-}
-void megaduck_rom_device::write_bank(offs_t offset, uint8_t data)
-{
- if (offset == 0x0001)
- m_latch_bank2 = data;
-}
+// device type definition
+DEFINE_DEVICE_TYPE_PRIVATE(MEGADUCK_ROM_STD, device_gb_cart_interface, bus::gameboy::megaduck_flat_device, "megaduck_rom", "Mega Duck Flat ROM Cartridge")
+DEFINE_DEVICE_TYPE_PRIVATE(MEGADUCK_ROM_BANKED, device_gb_cart_interface, bus::gameboy::megaduck_banked_device, "megaduck_rom_banked", "Mega Duck Banked ROM Cartridge")
-void megaduck_rom_device::write_ram(offs_t offset, uint8_t data)
-{
- m_latch_bank = data * 2;
- m_latch_bank2 = data * 2 + 1;
-}
+DEFINE_DEVICE_TYPE_PRIVATE(GB_ROM_STD, device_gb_cart_interface, bus::gameboy::flat_rom_ram_device, "gb_rom", "Game Boy Flat ROM Cartridge")
+DEFINE_DEVICE_TYPE_PRIVATE(GB_ROM_M161, device_gb_cart_interface, bus::gameboy::m161_device, "gb_rom_m161", "Game Boy M161 Cartridge")
+DEFINE_DEVICE_TYPE_PRIVATE(GB_ROM_WISDOM, device_gb_cart_interface, bus::gameboy::wisdom_device, "gb_rom_wisdom", "Game Boy Wisdom Tree Cartridge")
+DEFINE_DEVICE_TYPE_PRIVATE(GB_ROM_YONG, device_gb_cart_interface, bus::gameboy::yong_device, "gb_rom_yong", "Game Boy Young Yong Cartridge")
+DEFINE_DEVICE_TYPE_PRIVATE(GB_ROM_ROCKMAN8, device_gb_cart_interface, bus::gameboy::rockman8_device, "gb_rom_rockman8", "Game Boy Rockman 8 Cartridge")
+DEFINE_DEVICE_TYPE_PRIVATE(GB_ROM_SM3SP, device_gb_cart_interface, bus::gameboy::sm3sp_device, "gb_rom_sm3sp", "Game Boy Super Mario 3 Special Cartridge")
+DEFINE_DEVICE_TYPE_PRIVATE(GB_ROM_SACHEN1, device_gb_cart_interface, bus::gameboy::sachen_mmc1_device, "gb_rom_sachen1", "Game Boy Sachen MMC1 Cartridge")
+DEFINE_DEVICE_TYPE_PRIVATE(GB_ROM_SACHEN2, device_gb_cart_interface, bus::gameboy::sachen_mmc2_device, "gb_rom_sachen2", "Game Boy Sachen MMC2 Cartridge")
+DEFINE_DEVICE_TYPE_PRIVATE(GB_ROM_ROCKET, device_gb_cart_interface, bus::gameboy::rocket_device, "gb_rom_rocket", "Game Boy Rocket Games Cartridge")
+DEFINE_DEVICE_TYPE_PRIVATE(GB_ROM_LASAMA, device_gb_cart_interface, bus::gameboy::lasama_device, "gb_rom_lasama", "Game Boy Story of Lasama Cartridge")