diff options
Diffstat (limited to 'src/devices/bus/gameboy/ntnew.cpp')
-rw-r--r-- | src/devices/bus/gameboy/ntnew.cpp | 179 |
1 files changed, 179 insertions, 0 deletions
diff --git a/src/devices/bus/gameboy/ntnew.cpp b/src/devices/bus/gameboy/ntnew.cpp new file mode 100644 index 00000000000..fa54065bf2e --- /dev/null +++ b/src/devices/bus/gameboy/ntnew.cpp @@ -0,0 +1,179 @@ +// license:BSD-3-Clause +// copyright-holders:Vas Crabb +/*************************************************************************** + + Memory controller used for newer NT/Makon games + + Appears to start in a mode similar to Nintendo MBC3, with a fixed 16 KiB + ROM bank at 0x0000 and a switchable 16 KiB ROM bank at 0x4000, but allows + switching to a mode with selectable 8 KiB ROM banks at 0x4000 and 0x6000. + + It isn't clear how many static RAM pages are actually supported. Many + cartridges included 32K*8 static RAMs despite the headers declaring smaller + sizes and the games using no more than 8 KiB. The maximum supported ROM + size is also unknown. + + Pretty much everything here is guessed based on the games' behaviour. The + exact address ranges the memory controller responds to are unknown. There + may be additional features that are not emulated. + + ***************************************************************************/ + +#include "emu.h" +#include "ntnew.h" + +#include "cartbase.ipp" + +//#define VERBOSE 1 +//#define LOG_OUTPUT_FUNC osd_printf_info +#include "logmacro.h" + + +namespace bus::gameboy { + +namespace { + +class ntnew_device : public mbc_ram_device_base<mbc_8k_device_base> +{ +public: + ntnew_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock); + + virtual std::error_condition load(std::string &message) override ATTR_COLD; + +protected: + virtual void device_start() override ATTR_COLD; + virtual void device_reset() override ATTR_COLD; + +private: + void enable_ram(offs_t offset, u8 data); + void bank_switch_rom(offs_t offset, u8 data); + void bank_switch_ram(u8 data); + + memory_view m_view_ram; + + u8 m_bank_8k; +}; + + +ntnew_device::ntnew_device( + machine_config const &mconfig, + char const *tag, + device_t *owner, + u32 clock) : + mbc_ram_device_base<mbc_8k_device_base>(mconfig, GB_ROM_NTNEW, tag, owner, clock), + m_view_ram(*this, "ram"), + m_bank_8k(0U) +{ +} + + +std::error_condition ntnew_device::load(std::string &message) +{ + // set up ROM and RAM + set_bank_bits_rom(8); + set_bank_bits_ram(4); + if (!check_rom(message) || !check_ram(message)) + return image_error::BADSOFTWARE; + cart_space()->install_view(0xa000, 0xbfff, m_view_ram); + install_rom(*cart_space(), *cart_space(), *cart_space()); + install_ram(m_view_ram[0]); + + // install handlers + cart_space()->install_write_handler( + 0x0000, 0x1fff, + emu::rw_delegate(*this, FUNC(ntnew_device::enable_ram))); + cart_space()->install_write_handler( + 0x2000, 0x2fff, + emu::rw_delegate(*this, FUNC(ntnew_device::bank_switch_rom))); + cart_space()->install_write_handler( + 0x4000, 0x5fff, + emu::rw_delegate(*this, FUNC(ntnew_device::bank_switch_ram))); + + // all good + return std::error_condition(); +} + + +void ntnew_device::device_start() +{ + mbc_ram_device_base<mbc_8k_device_base>::device_start(); + + save_item(NAME(m_bank_8k)); +} + + +void ntnew_device::device_reset() +{ + mbc_ram_device_base<mbc_8k_device_base>::device_reset(); + + m_view_ram.disable(); + m_bank_8k = 0U; + + set_bank_rom_low(2); + set_bank_rom_high(3); + set_bank_ram(0); +} + + +void ntnew_device::enable_ram(offs_t offset, u8 data) +{ + // TODO: what range actually triggers this, and does it still trigger RAM enable? + if (((offset & 0x1f00) == 0x1400) & (0x55 == data)) + { + LOG("%s: 8K ROM banking enabled\n", machine().describe_context()); + m_bank_8k = 1U; + } + + // TODO: how many bits are checked? + bool const enable(0x0a == (data & 0x0f)); + LOG( + "%s: Cartridge RAM %s\n", + machine().describe_context(), + enable ? "enabled" : "disabled"); + if (enable) + m_view_ram.select(0); + else + m_view_ram.disable(); +} + + +void ntnew_device::bank_switch_rom(offs_t offset, u8 data) +{ + if (m_bank_8k) + { + // TODO: what ranges does the controller actually respond to? + switch (offset & 0x0f00) + { + case 0x0000: + if (!(data & 0xfe)) + data |= 0x02; + set_bank_rom_low(data); + return; + + case 0x0400: + if (!(data & 0xfe)) + data |= 0x02; + set_bank_rom_high(data); + return; + } + } + + data <<= 1; + if (!(data & 0xfe)) + data |= 0x02; + set_bank_rom_low(data); + set_bank_rom_high(data | 0x01); +} + + +void ntnew_device::bank_switch_ram(u8 data) +{ + set_bank_ram(data & 0x0f); +} + +} // anonymous namespace + +} // namespace bus::gameboy + + +DEFINE_DEVICE_TYPE_PRIVATE(GB_ROM_NTNEW, device_gb_cart_interface, bus::gameboy::ntnew_device, "gb_rom_ntnew", "Game Boy newer Kasheng/Makon Cartridge") |