From f4b23f173771db595251ea3e1117445f28a8baf0 Mon Sep 17 00:00:00 2001 From: Vas Crabb Date: Tue, 4 Oct 2022 12:48:26 +1100 Subject: bus/gameboy: Moved MBC3/MBC30 to their own file as separate devices. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit New working software list additions ----------------------------------- gbcolor.xml: Juéduì Wǔlì (China), Wàixīng Tànxiǎn zhī Xīngqiú Dàzhàn (China) [Robyn A1200, taizou] --- hash/apple2gs_flop_orig.xml | 2 +- hash/gbcolor.xml | 39 ++- scripts/src/bus.lua | 2 + src/devices/bus/gameboy/carts.cpp | 3 +- src/devices/bus/gameboy/mbc.cpp | 543 ---------------------------- src/devices/bus/gameboy/mbc.h | 1 - src/devices/bus/gameboy/mbc3.cpp | 721 ++++++++++++++++++++++++++++++++++++++ src/devices/bus/gameboy/mbc3.h | 19 + src/devices/cpu/mn1880/mn1880.cpp | 2 +- src/mame/atari/atarigt.cpp | 2 +- src/mame/jaleco/armchamp.cpp | 6 +- 11 files changed, 783 insertions(+), 557 deletions(-) create mode 100644 src/devices/bus/gameboy/mbc3.cpp create mode 100644 src/devices/bus/gameboy/mbc3.h diff --git a/hash/apple2gs_flop_orig.xml b/hash/apple2gs_flop_orig.xml index 3dda1807eae..1a5a1ab8a5f 100644 --- a/hash/apple2gs_flop_orig.xml +++ b/hash/apple2gs_flop_orig.xml @@ -4041,7 +4041,7 @@ license:CC0 First Letters and Words (Version 1.0) ???? - First Byte + First Byte diff --git a/hash/gbcolor.xml b/hash/gbcolor.xml index 4d5402d0448..f02c541ffaa 100644 --- a/hash/gbcolor.xml +++ b/hash/gbcolor.xml @@ -26816,10 +26816,10 @@ license:CC0 - - + + - + @@ -26831,10 +26831,37 @@ license:CC0 - - + + - + + + + + + + Juéduì Wǔlì (China) + 200? + Sintax + + + + + + + + + + + + Wàixīng Tànxiǎn zhī Xīngqiú Dàzhàn (China) + 200? + Sintax + + + + + diff --git a/scripts/src/bus.lua b/scripts/src/bus.lua index 7c646731f36..4fabd53ea76 100644 --- a/scripts/src/bus.lua +++ b/scripts/src/bus.lua @@ -3709,6 +3709,8 @@ if (BUSES["GAMEBOY"]~=null) then MAME_DIR .. "src/devices/bus/gameboy/mbc.h", MAME_DIR .. "src/devices/bus/gameboy/mbc2.cpp", MAME_DIR .. "src/devices/bus/gameboy/mbc2.h", + MAME_DIR .. "src/devices/bus/gameboy/mbc3.cpp", + MAME_DIR .. "src/devices/bus/gameboy/mbc3.h", MAME_DIR .. "src/devices/bus/gameboy/mbc6.cpp", MAME_DIR .. "src/devices/bus/gameboy/mbc6.h", MAME_DIR .. "src/devices/bus/gameboy/mbc7.cpp", diff --git a/src/devices/bus/gameboy/carts.cpp b/src/devices/bus/gameboy/carts.cpp index 8bb63cf3cbd..dbd4924d71b 100644 --- a/src/devices/bus/gameboy/carts.cpp +++ b/src/devices/bus/gameboy/carts.cpp @@ -15,6 +15,7 @@ #include "huc3.h" #include "mbc.h" #include "mbc2.h" +#include "mbc3.h" #include "mbc6.h" #include "mbc7.h" #include "mmm01.h" @@ -80,7 +81,7 @@ void gameboy_cartridges(device_slot_interface &device) device.option_add_internal(slotoptions::GB_MBC1, GB_ROM_MBC1); device.option_add_internal(slotoptions::GB_MBC2, GB_ROM_MBC2); device.option_add_internal(slotoptions::GB_MBC3, GB_ROM_MBC3); - device.option_add_internal(slotoptions::GB_MBC30, GB_ROM_MBC3); // MBC3 and MBC30 treated as the same thing for now + device.option_add_internal(slotoptions::GB_MBC30, GB_ROM_MBC30); device.option_add_internal(slotoptions::GB_MBC5, GB_ROM_MBC5); device.option_add_internal(slotoptions::GB_MBC6, GB_ROM_MBC6); device.option_add_internal(slotoptions::GB_MBC7_2K, GB_ROM_MBC7_2K); diff --git a/src/devices/bus/gameboy/mbc.cpp b/src/devices/bus/gameboy/mbc.cpp index a31b8d8f858..4bad4a2522d 100644 --- a/src/devices/bus/gameboy/mbc.cpp +++ b/src/devices/bus/gameboy/mbc.cpp @@ -31,34 +31,6 @@ Regular ROM aliasing rules apply. - MBC3 Mapper - =========== - - The MBC3 mapper cartridges can include a RTC chip. - - 0000-1FFF - Writing to this area enables (value 0x0A) or disables (not 0x0A) the - SRAM and RTC registers. - 2000-3FFF - Writing to this area selects the ROM bank to appear at 4000-7FFF. - Bits 6-0 are used to select the bank number. If a value of - 0bX0000000 is written then this is automatically changed into - 0bX0000001 by the mapper. - 4000-5FFF - Writing to this area selects the RAM bank or the RTC register to - read. - XXXX00bb - Select RAM bank bb. - XXXX1rrr - Select RTC register rrr. Accepted values for rrr are: - 000 - Seconds (0x00-0x3B) - 001 - Minutes (0x00-0x3B) - 010 - Hours (0x00-0x17) - 011 - Bits 7-0 of the day counter - 100 - bit 0 - Bit 8 of the day counter - bit 6 - Halt RTC timer ( 0 = timer active, 1 = halted) - bit 7 - Day counter overflow flag - 6000-7FFF - Writing 0x00 followed by 0x01 latches the RTC data. This latching - method is used for reading the RTC registers. - - Regular ROM aliasing rules apply. - - MBC5 Mapper =========== @@ -73,11 +45,6 @@ TODO: - * What does MBC3 do with the RAM bank outputs when RTC is selected? - * How do MBC3 invalid second/minute/hour values roll over? - * For convenience, MBC3 and MBC30 are emulated as one device for now. - - MBC3 only has 2 RAM bank outputs, but it will allow 3 like MBC30 here. - - MBC30 supposedly has 8 ROM bank outputs, but the one game using it only needs 7. * MBC5 logo spoofing class implements several strategies. It's likely not all carts using it use all the strategies. Strategies implemented by each cartridge should be identified. * HK0701 and HK0819 seem to differ in that HK0819 fully decodes ROM addresses while HK0701 mirrors - we @@ -96,8 +63,6 @@ #include "bus/generic/slot.h" -#include "dirtc.h" - #include "corestr.h" #include @@ -188,12 +153,7 @@ protected: set_bank_ram(data & m_bank_lines[1]); } - auto &view_aux(unsigned entry) { return m_view_ram[entry + 1]; } - void set_view_aux(unsigned entry) { m_view_ram.select(entry + 1); } - private: - static inline constexpr unsigned PAGE_RAM_SIZE = 0x2000; - memory_view m_view_ram; u16 m_bank_lines[2]; @@ -566,508 +526,6 @@ private: -//************************************************************************** -// MBC3 (max 8 MiB ROM, max 32 KiB SRAM, RTC) -//************************************************************************** - -class mbc3_device : public rom_mbc_device_base, public device_rtc_interface, public device_nvram_interface -{ -public: - mbc3_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock) : - rom_mbc_device_base(mconfig, GB_ROM_MBC3, tag, owner, clock), - device_rtc_interface(mconfig, *this), - device_nvram_interface(mconfig, *this), - m_timer_rtc(nullptr), - m_machine_seconds(0), - m_has_rtc_xtal(false), - m_has_battery(false), - m_rtc_enable(0U), - m_rtc_select(0U), - m_rtc_latch(0U) - { - } - - virtual image_init_result load(std::string &message) override ATTR_COLD - { - // check for RTC oscillator and backup battery - if (loaded_through_softlist()) - { - // there's a feature tag indicating presence or absence of RTC crystal - char const *const rtcfeature(get_feature("rtc")); - if (rtcfeature) - { - // explicitly specified in software list - if (util::streqlower(rtcfeature, "yes") || util::streqlower(rtcfeature, "true")) - { - logerror("Real-time clock crystal present\n"); - m_has_rtc_xtal = true; - } - else if (util::streqlower(rtcfeature, "no") || util::streqlower(rtcfeature, "false")) - { - logerror("No real-time clock crystal present\n"); - m_has_rtc_xtal = false; - } - else - { - message = "Invalid 'rtc' feature value (must be yes or no)"; - return image_init_result::FAIL; - } - } - else - { - logerror("No 'rtc' feature found, assuming no real-time clock crystal present\n"); - m_has_rtc_xtal = false; - } - - // if there's an NVRAM region, there must be a backup battery - if (cart_nvram_region()) - { - logerror("Found 'nvram' region, backup battery must be present\n"); - m_has_battery = true; - } - else - { - logerror("No 'nvram' region found, assuming no backup battery present\n"); - m_has_battery = true; - } - } - else - { - gbxfile::leader_1_0 leader; - u8 const *extra; - u32 extralen; - if (gbxfile::get_data(gbx_footer_region(), leader, extra, extralen)) - { - m_has_rtc_xtal = bool(leader.rtc); - m_has_battery = bool(leader.batt); - logerror( - "GBX format image specifies %sreal-time clock crystal present, %sbackup battery present\n", - m_has_rtc_xtal ? "" : "no ", - m_has_battery ? "" : "no "); - } - else - { - // try probing the header - memory_region *const romregion(cart_rom_region()); - if (romregion && (romregion->bytes() > cartheader::OFFSET_TYPE)) - { - u8 const carttype((&romregion->as_u8())[cartheader::OFFSET_TYPE]); - switch (carttype) - { - case cartheader::TYPE_MBC3_RTC_BATT: - case cartheader::TYPE_MBC3_RTC_RAM_BATT: - m_has_rtc_xtal = true; - m_has_battery = true; - break; - case cartheader::TYPE_MBC3: - m_has_rtc_xtal = false; - m_has_battery = false; - break; - case cartheader::TYPE_MBC3_RAM: - case cartheader::TYPE_MBC3_RAM_BATT: - m_has_rtc_xtal = false; - m_has_battery = true; - break; - default: - osd_printf_warning( - "[%s] Unrecognized cartridge type 0x%02X in header, assuming no real-time clock crystal or backup battery present\n", - tag(), - carttype); - m_has_rtc_xtal = false; - m_has_battery = false; - } - logerror( - "Cartridge type 0x%02X in header, %sreal-time clock crystal present, %sbackup battery present\n", - carttype, - m_has_rtc_xtal ? "" : "no ", - m_has_battery ? "" : "no "); - } - } - } - - // set up ROM and RAM - if (!install_memory(message, 3, 7)) - return image_init_result::FAIL; - - // install bank switching handlers - cart_space()->install_write_handler( - 0x0000, 0x1fff, - write8smo_delegate(*this, FUNC(mbc3_device::enable_ram_rtc))); - cart_space()->install_write_handler( - 0x2000, 0x3fff, - write8smo_delegate(*this, FUNC(mbc3_device::bank_switch_fine))); - cart_space()->install_write_handler( - 0x4000, 0x5fff, - write8smo_delegate(*this, FUNC(mbc3_device::select_ram_rtc))); - cart_space()->install_write_handler( - 0x6000, 0x7fff, - write8smo_delegate(*this, FUNC(mbc3_device::latch_rtc))); - - // install real-time clock handlers - view_aux(0).install_read_handler( - 0xa000, 0xbfff, - read8mo_delegate(*this, FUNC(mbc3_device::read_rtc))); - view_aux(0).install_write_handler( - 0xa000, 0xbfff, - write8smo_delegate(*this, FUNC(mbc3_device::write_rtc))); - - // if real-time clock crystal is present, start it ticking - if (m_has_rtc_xtal) - { - logerror("Real-time clock crystal present, starting timer\n"); - m_timer_rtc->adjust(attotime(1, 0), 0, attotime(1, 0)); - } - - // all good - return image_init_result::PASS; - }; - -protected: - virtual void device_start() override ATTR_COLD - { - rom_mbc_device_base::device_start(); - - m_timer_rtc = timer_alloc(FUNC(mbc3_device::rtc_advance_seconds), this); - - save_item(NAME(m_rtc_regs)); - save_item(NAME(m_rtc_enable)); - save_item(NAME(m_rtc_select)); - save_item(NAME(m_rtc_latch)); - } - - virtual void device_reset() override ATTR_COLD - { - rom_mbc_device_base::device_reset(); - - m_rtc_enable = 0U; - m_rtc_select = 0U; - m_rtc_latch = 0U; - - set_bank_rom_coarse(0); - set_bank_rom_fine(1); - set_ram_enable(false); - set_bank_ram(0); - } - - virtual void rtc_clock_updated( - int year, - int month, - int day, - int day_of_week, - int hour, - int minute, - int second) override ATTR_COLD - { - if (!m_has_rtc_xtal && !m_has_battery) - { - logerror("No real-time clock crystal or no battery present, not updating for elapsed time\n"); - } - else if (std::numeric_limits::min() == m_machine_seconds) - { - logerror("Failed to load machine time from previous session, not updating for elapsed time\n"); - } - else if (BIT(m_rtc_regs[0][4], 6)) - { - logerror("Real-time clock halted, not updating for elapsed time\n"); - } - else - { - // do a simple seconds elapsed since last run calculation - system_time current; - machine().current_datetime(current); - s64 delta(std::make_signed_t(current.time) - m_machine_seconds); - logerror("Previous session time, %d current time %d, delta %d\n", current.time, m_machine_seconds, delta); - if (0 > delta) - { - // This happens if the user runs the emulation faster - // than real time, exits, and then starts again without - // waiting for the difference between emulated and real - // time to elapse. - logerror("Previous session ended in the future, not updating for elapsed time\n"); - } - else - { - logerror( - "Time before applying delta %u %02u:%02u:%02u%s\n", - (u16(BIT(m_rtc_regs[0][4], 0)) << 8) | m_rtc_regs[0][3], - m_rtc_regs[0][2], - m_rtc_regs[0][1], - m_rtc_regs[0][0], - BIT(m_rtc_regs[0][4], 7) ? " (overflow)" : ""); - - // annoyingly, we can get two rollovers if we started with an invalid value - unsigned seconds(delta % 60); - delta /= 60; - if (60 <= m_rtc_regs[0][0]) - { - m_rtc_regs[0][0] = 0U; - --seconds; - ++delta; - } - if (60 <= (m_rtc_regs[0][0] + seconds)) - ++delta; - m_rtc_regs[0][0] = (m_rtc_regs[0][0] + seconds) % 60; - - // minutes is the same - unsigned minutes(delta % 60); - delta /= 60; - if (60 <= m_rtc_regs[0][1]) - { - m_rtc_regs[0][1] = 0U; - --minutes; - ++delta; - } - if (60 <= (m_rtc_regs[0][1] + minutes)) - ++delta; - m_rtc_regs[0][1] = (m_rtc_regs[0][1] + minutes) % 60; - - // hours just has a different rollover point - unsigned hours(delta % 24); - delta /= 24; - if (24 <= m_rtc_regs[0][2]) - { - m_rtc_regs[0][2] = 0U; - --hours; - ++delta; - } - if (24 <= (m_rtc_regs[0][2] + hours)) - ++delta; - m_rtc_regs[0][2] = (m_rtc_regs[0][2] + hours) % 24; - - // days has simple binary rollover - unsigned days(delta % 256); - if (256 <= (m_rtc_regs[0][3] + days)) - ++delta; - m_rtc_regs[0][3] += days; - - // set overflow flag if appropriate - if ((1 < delta) || (BIT(m_rtc_regs[0][4], 0) && delta)) - m_rtc_regs[0][4] |= 0x80; - m_rtc_regs[0][4] ^= BIT(delta, 0); - - logerror( - "Time after applying delta %u %02u:%02u:%02u%s\n", - (u16(BIT(m_rtc_regs[0][4], 0)) << 8) | m_rtc_regs[0][3], - m_rtc_regs[0][2], - m_rtc_regs[0][1], - m_rtc_regs[0][0], - BIT(m_rtc_regs[0][4], 7) ? " (overflow)" : ""); - } - } - } - - virtual void nvram_default() override ATTR_COLD - { - // TODO: proper cold RTC state - m_machine_seconds = std::numeric_limits::min(); - for (unsigned i = 0U; std::size(m_rtc_regs[0]) > i; ++i) - m_rtc_regs[0][i] = RTC_MASK[i]; - } - - virtual bool nvram_read(util::read_stream &file) override ATTR_COLD - { - if (m_has_battery) - { - // read previous machine time (seconds since epoch) and RTC registers - u64 seconds; - std::size_t actual; - if (file.read(&seconds, sizeof(seconds), actual) || (sizeof(seconds) != actual)) - return false; - m_machine_seconds = big_endianize_int64(seconds); - - if (file.read(&m_rtc_regs[0][0], sizeof(m_rtc_regs[0]), actual) || (sizeof(m_rtc_regs[0]) != actual)) - return false; - } - else - { - logerror("No battery present, not loading real-time clock register contents\n"); - } - return true; - } - - virtual bool nvram_write(util::write_stream &file) override ATTR_COLD - { - // save current machine time as seconds since epoch and RTC registers - system_time current; - machine().current_datetime(current); - u64 const seconds(big_endianize_int64(s64(std::make_signed_t(current.time)))); - std::size_t written; - if (file.write(&seconds, sizeof(seconds), written) || (sizeof(seconds) != written)) - return false; - if (file.write(&m_rtc_regs[0][0], sizeof(m_rtc_regs[0]), written) || (sizeof(m_rtc_regs[0]) != written)) - return false; - return true; - } - - virtual bool nvram_can_write() const override ATTR_COLD - { - return m_has_battery; - } - -private: - static inline constexpr u8 RTC_MASK[]{ 0x3f, 0x3f, 0x1f, 0xff, 0xc1 }; - static inline constexpr u8 RTC_ROLLOVER[]{ 0x3c, 0x3c, 0x18, 0x00, 0x00 }; - - TIMER_CALLBACK_MEMBER(rtc_advance_seconds) - { - if (BIT(m_rtc_regs[0][4], 6)) - return; - - if (rtc_increment(0)) - return; - if (rtc_increment(1)) - return; - if (rtc_increment(2)) - return; - if (++m_rtc_regs[0][3]) - return; - - if (BIT(m_rtc_regs[0][4], 0)) - { - LOG("Day counter overflow"); - m_rtc_regs[0][4] |= 0x80; - } - m_rtc_regs[0][4] ^= 0x01; - } - - void enable_ram_rtc(u8 data) - { - m_rtc_enable = (0x0a == (data & 0x0f)) ? 1U : 0U; - if (!m_rtc_enable) - { - set_ram_enable(false); - } - else if (BIT(m_rtc_select, 3)) - { - LOG( - "%s: RTC register %u enabled\n", - machine().describe_context(), - m_rtc_select & 0x07); - set_view_aux(0); - } - else - { - set_ram_enable(true); - } - } - - void bank_switch_fine(u8 data) - { - data &= 0x7f; - set_bank_rom_fine(data ? data : 1); - } - - void select_ram_rtc(u8 data) - { - // TODO: what happens with the RAM bank outputs when the RTC is selected? - // TODO: what happens for 4-7? - // TODO: is the high nybble ignored altogether? - bank_switch_coarse(data & 0x07); - m_rtc_select = data; - if (m_rtc_enable) - { - if (BIT(data, 3)) - { - LOG( - "%s: RTC register %u enabled\n", - machine().describe_context(), - data & 0x07); - set_view_aux(0); - } - else - { - set_ram_enable(true); - } - } - } - - void latch_rtc(u8 data) - { - // FIXME: does it just check the least significant bit, or does it look for 0x00 and 0x01? - LOG("Latch RTC 0x%02X -> 0x%02X\n", m_rtc_latch, data); - if (!BIT(m_rtc_latch, 0) && BIT(data, 0)) - { - LOG("%s: Latching RTC registers\n", machine().describe_context()); - std::copy(std::begin(m_rtc_regs[0]), std::end(m_rtc_regs[0]), std::begin(m_rtc_regs[1])); - } - m_rtc_latch = data; - } - - u8 read_rtc(address_space &space) - { - u8 const reg(m_rtc_select & 0x07); - if (std::size(m_rtc_regs[1]) > reg) - { - LOG( - "%s: Read RTC register %u = 0x%02X\n", - machine().describe_context(), - reg, - m_rtc_regs[1][reg]); - return m_rtc_regs[1][reg]; - } - else - { - LOG( - "%s: Read invalid RTC register %u\n", - machine().describe_context(), - reg); - return space.unmap(); - } - } - - void write_rtc(u8 data) - { - u8 const reg(m_rtc_select & 0x07); - if (std::size(m_rtc_regs[0]) > reg) - { - LOG( - "%s: Write RTC register %u = 0x%02X\n", - machine().describe_context(), - reg, - data); - if (4U == reg) - { - // TODO: are bits 5-1 physically present, and if not, what do they read as? - // TODO: how does halting the RTC interact with the prescaler? - data &= 0xc1; - m_rtc_regs[0][reg] = data; - } - else - { - m_rtc_regs[0][reg] = data; - } - } - else - { - LOG( - "%s: Write invalid RTC register %u = 0x%02X\n", - machine().describe_context(), - reg, - data); - } - } - - u8 rtc_increment(unsigned index) - { - m_rtc_regs[0][index] = (m_rtc_regs[0][index] + 1) & RTC_MASK[index]; - if (RTC_ROLLOVER[index] == (m_rtc_regs[0][index] & RTC_ROLLOVER[index])) - m_rtc_regs[0][index] = 0U; - return m_rtc_regs[0][index]; - } - - emu_timer *m_timer_rtc; - s64 m_machine_seconds; - bool m_has_rtc_xtal; - bool m_has_battery; - - u8 m_rtc_regs[2][5]; - u8 m_rtc_enable; - u8 m_rtc_select; - u8 m_rtc_latch; -}; - - - //************************************************************************** // MBC5 (max 128 MiB ROM, max 128 KiB SRAM) //************************************************************************** @@ -1896,7 +1354,6 @@ private: // device type definition DEFINE_DEVICE_TYPE_PRIVATE(GB_ROM_MBC1, device_gb_cart_interface, bus::gameboy::mbc1_device, "gb_rom_mbc1", "Game Boy MBC1 Cartridge") -DEFINE_DEVICE_TYPE_PRIVATE(GB_ROM_MBC3, device_gb_cart_interface, bus::gameboy::mbc3_device, "gb_rom_mbc3", "Game Boy MBC3/MBC30 Cartridge") DEFINE_DEVICE_TYPE_PRIVATE(GB_ROM_MBC5, device_gb_cart_interface, bus::gameboy::mbc5_device, "gb_rom_mbc5", "Game Boy MBC5 Cartridge") DEFINE_DEVICE_TYPE_PRIVATE(GB_ROM_SINTAX, device_gb_cart_interface, bus::gameboy::sintax_device, "gb_rom_sintax", "Game Boy Sintax MBC5 Cartridge") DEFINE_DEVICE_TYPE_PRIVATE(GB_ROM_CHONGWU, device_gb_cart_interface, bus::gameboy::chongwu_device, "gb_rom_chongwu", "Game Boy Chongwu Xiao Jingling Pokemon Pikecho Cartridge") diff --git a/src/devices/bus/gameboy/mbc.h b/src/devices/bus/gameboy/mbc.h index f7e7301a5c3..6d492a779a2 100644 --- a/src/devices/bus/gameboy/mbc.h +++ b/src/devices/bus/gameboy/mbc.h @@ -9,7 +9,6 @@ DECLARE_DEVICE_TYPE(GB_ROM_MBC1, device_gb_cart_interface) -DECLARE_DEVICE_TYPE(GB_ROM_MBC3, device_gb_cart_interface) DECLARE_DEVICE_TYPE(GB_ROM_MBC5, device_gb_cart_interface) DECLARE_DEVICE_TYPE(GB_ROM_MMM01, device_gb_cart_interface) DECLARE_DEVICE_TYPE(GB_ROM_SINTAX, device_gb_cart_interface) diff --git a/src/devices/bus/gameboy/mbc3.cpp b/src/devices/bus/gameboy/mbc3.cpp new file mode 100644 index 00000000000..bfead355999 --- /dev/null +++ b/src/devices/bus/gameboy/mbc3.cpp @@ -0,0 +1,721 @@ +// license:BSD-3-Clause +// copyright-holders:Vas Crabb +/*************************************************************************** + + Nintendo Game Boy Memory Bank Controller 3 + + Includes a real-time clock in addition to the memory controller features. + The real-time clock can be used with or without a backup battery. Without + a backup battery, it just keeps time while the game is running. Several + games also used this memory controller without a real-time clock crystal. + + The MBC3 supports up to 2 MiB ROM (128 16 KiB pages) and 32 KiB static RAM + (4 8 KiB pages). The MBC30 supports up to 4 MiB ROM (256 16 KiB pages) and + 64 KiB static RAM (8 8 KiB pages). If RAM bank lines are used for coarse + ROM banking, up to 8 MiB ROM (512 16 KiB pages) can be supported by the + MBC3, and up to 32 MiB ROM (2048 16 KiB pages) can be supported by the + MBC30. + + The MBC30 was only used for a single game. In practice, 128K*8 static RAM + chips were used, but only half the space is accessible as the MBC30 chip + only has three RAM bank output lines. + + 0x0000-3FFF R - Fixed ROM bank, always first page of ROM. + 0x4000-7FFF R - Selectable ROM bank, page 0-127 (MBC) or 0-255 (MBC30) of + ROM. + 0xA000-BFFF RW - Static RAM or real-time clock registers. + + 0x0000-1FFF W - I/O enable - write 0x0A on low nybble to enable static RAM + or real-time clock registers, any other value to disable. + 0x2000-3FFF W - Select ROM page mapped at 0x4000. Bit 7 is ignored by + MBC3; all bits are significant for MBC30 Writing 0 selects + page 1. + 0x4000-5FFF W - Select RAM page or real-time clock register mapped at + 0xA000 (if enabled). If bit 3 is clear, static RAM is + selected; if bit 3 is set, real-time clock registers are + selected. Bits 2-0 select the RAM page or register. + 0x6000-7FFF W - Write 0x00 followed by 0x01 to latch real-time clock + registers. + + Real-time clock registers: + 0x0 - Seconds. + 0x1 - Minutes. + 0x2 - Hours. + 0x3 - Bits 7-0 of days. + 0x4 - X------- Day counter overflow (set on carry out of bit 8, cleared + manually). + -X------ Set to halt real-time clock. + -------X Bit 8 of days. + + TODO: + * How are the static RAM bank outputs set when real-time clock registers + are selected? + * What happens if invalid real-time clock registers 5-7 are selected? + * How do invalid seconds, minutes and hours values roll over? + * Does MBC30 really have eight ROM bank outputs? The one game using it + only uses seven. + + ***************************************************************************/ + +#include "emu.h" +#include "mbc3.h" + +#include "cartbase.ipp" +#include "cartheader.h" +#include "gbxfile.h" + +#include "dirtc.h" + +#include "corestr.h" + +#include + +//#define VERBOSE 1 +//#define LOG_OUTPUT_FUNC osd_printf_info +#include "logmacro.h" + + +namespace bus::gameboy { + +namespace { + +//************************************************************************** +// Class declarations +//************************************************************************** + +class mbc3_device_base : public mbc_ram_device_base, public device_rtc_interface, public device_nvram_interface +{ +protected: + mbc3_device_base(machine_config const &mconfig, device_type type, char const *tag, device_t *owner, u32 clock); + + virtual void device_start() override ATTR_COLD; + virtual void device_reset() override ATTR_COLD; + + virtual void rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second) override ATTR_COLD; + + virtual void nvram_default() override ATTR_COLD; + virtual bool nvram_read(util::read_stream &file) override ATTR_COLD; + virtual bool nvram_write(util::write_stream &file) override ATTR_COLD; + virtual bool nvram_can_write() const override ATTR_COLD; + + bool install_memory(std::string &message, unsigned highbits, unsigned lowbits) ATTR_COLD; + +private: + static inline constexpr u8 RTC_MASK[]{ 0x3f, 0x3f, 0x1f, 0xff, 0xc1 }; + static inline constexpr u8 RTC_ROLLOVER[]{ 0x3c, 0x3c, 0x18, 0x00, 0x00 }; + + TIMER_CALLBACK_MEMBER(rtc_advance_seconds); + + void enable_ram_rtc(u8 data); + void bank_switch_fine(u8 data); + void select_ram_rtc(u8 data); + void latch_rtc(u8 data); + u8 read_rtc(address_space &space); + void write_rtc(u8 data); + + u8 rtc_increment(unsigned index) + { + m_rtc_regs[0][index] = (m_rtc_regs[0][index] + 1) & RTC_MASK[index]; + if (RTC_ROLLOVER[index] == (m_rtc_regs[0][index] & RTC_ROLLOVER[index])) + m_rtc_regs[0][index] = 0U; + return m_rtc_regs[0][index]; + } + + memory_view m_view_ram; + + emu_timer *m_timer_rtc; + s64 m_machine_seconds; + bool m_has_rtc_xtal; + bool m_has_battery; + + u8 m_rtc_regs[2][5]; + u8 m_rtc_enable; + u8 m_rtc_select; + u8 m_rtc_latch; +}; + + +class mbc3_device : public mbc3_device_base +{ +public: + mbc3_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock); + + virtual image_init_result load(std::string &message) override ATTR_COLD; +}; + + +class mbc30_device : public mbc3_device_base +{ +public: + mbc30_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock); + + virtual image_init_result load(std::string &message) override ATTR_COLD; +}; + + + +//************************************************************************** +// mbc3_device_base +//************************************************************************** + +mbc3_device_base::mbc3_device_base( + machine_config const &mconfig, + device_type type, + char const *tag, + device_t *owner, + u32 clock) : + mbc_ram_device_base(mconfig, type, tag, owner, clock), + device_rtc_interface(mconfig, *this), + device_nvram_interface(mconfig, *this), + m_view_ram(*this, "ram"), + m_timer_rtc(nullptr), + m_machine_seconds(0), + m_has_rtc_xtal(false), + m_has_battery(false), + m_rtc_enable(0U), + m_rtc_select(0U), + m_rtc_latch(0U) +{ +} + + +bool mbc3_device_base::install_memory( + std::string &message, + unsigned highbits, + unsigned lowbits) +{ + // check for RTC oscillator and backup battery + if (loaded_through_softlist()) + { + // there's a feature tag indicating presence or absence of RTC crystal + char const *const rtcfeature(get_feature("rtc")); + if (rtcfeature) + { + // explicitly specified in software list + if (util::streqlower(rtcfeature, "yes") || util::streqlower(rtcfeature, "true")) + { + logerror("Real-time clock crystal present\n"); + m_has_rtc_xtal = true; + } + else if (util::streqlower(rtcfeature, "no") || util::streqlower(rtcfeature, "false")) + { + logerror("No real-time clock crystal present\n"); + m_has_rtc_xtal = false; + } + else + { + message = "Invalid 'rtc' feature value (must be yes or no)"; + return false; + } + } + else + { + logerror("No 'rtc' feature found, assuming no real-time clock crystal present\n"); + m_has_rtc_xtal = false; + } + + // if there's an NVRAM region, there must be a backup battery + if (cart_nvram_region()) + { + logerror("Found 'nvram' region, backup battery must be present\n"); + m_has_battery = true; + } + else + { + logerror("No 'nvram' region found, assuming no backup battery present\n"); + m_has_battery = true; + } + } + else + { + gbxfile::leader_1_0 leader; + u8 const *extra; + u32 extralen; + if (gbxfile::get_data(gbx_footer_region(), leader, extra, extralen)) + { + m_has_rtc_xtal = bool(leader.rtc); + m_has_battery = bool(leader.batt); + logerror( + "GBX format image specifies %sreal-time clock crystal present, %sbackup battery present\n", + m_has_rtc_xtal ? "" : "no ", + m_has_battery ? "" : "no "); + } + else + { + // try probing the header + memory_region *const romregion(cart_rom_region()); + if (romregion && (romregion->bytes() > cartheader::OFFSET_TYPE)) + { + u8 const carttype((&romregion->as_u8())[cartheader::OFFSET_TYPE]); + switch (carttype) + { + case cartheader::TYPE_MBC3_RTC_BATT: + case cartheader::TYPE_MBC3_RTC_RAM_BATT: + m_has_rtc_xtal = true; + m_has_battery = true; + break; + case cartheader::TYPE_MBC3: + m_has_rtc_xtal = false; + m_has_battery = false; + break; + case cartheader::TYPE_MBC3_RAM: + case cartheader::TYPE_MBC3_RAM_BATT: + m_has_rtc_xtal = false; + m_has_battery = true; + break; + default: + osd_printf_warning( + "[%s] Unrecognized cartridge type 0x%02X in header, assuming no real-time clock crystal or backup battery present\n", + tag(), + carttype); + m_has_rtc_xtal = false; + m_has_battery = false; + } + logerror( + "Cartridge type 0x%02X in header, %sreal-time clock crystal present, %sbackup battery present\n", + carttype, + m_has_rtc_xtal ? "" : "no ", + m_has_battery ? "" : "no "); + } + } + } + + // check for valid ROM/RAM regions + set_bank_bits_rom(highbits, lowbits); + set_bank_bits_ram(highbits); + if (!check_rom(message) || !check_ram(message)) + return false; + + // set up ROM and RAM + cart_space()->install_view(0xa000, 0xbfff, m_view_ram); + install_rom(); + install_ram(m_view_ram[0]); + + // install bank switching handlers + cart_space()->install_write_handler( + 0x0000, 0x1fff, + write8smo_delegate(*this, FUNC(mbc3_device_base::enable_ram_rtc))); + cart_space()->install_write_handler( + 0x2000, 0x3fff, + write8smo_delegate(*this, FUNC(mbc3_device_base::bank_switch_fine))); + cart_space()->install_write_handler( + 0x4000, 0x5fff, + write8smo_delegate(*this, FUNC(mbc3_device_base::select_ram_rtc))); + cart_space()->install_write_handler( + 0x6000, 0x7fff, + write8smo_delegate(*this, FUNC(mbc3_device_base::latch_rtc))); + + // install real-time clock handlers + m_view_ram[1].install_read_handler( + 0xa000, 0xbfff, + read8mo_delegate(*this, FUNC(mbc3_device_base::read_rtc))); + m_view_ram[1].install_write_handler( + 0xa000, 0xbfff, + write8smo_delegate(*this, FUNC(mbc3_device_base::write_rtc))); + + // if real-time clock crystal is present, start it ticking + if (m_has_rtc_xtal) + { + logerror("Real-time clock crystal present, starting timer\n"); + m_timer_rtc->adjust(attotime(1, 0), 0, attotime(1, 0)); + } + + // all good + return true; +} + + +void mbc3_device_base::device_start() +{ + mbc_ram_device_base::device_start(); + + m_timer_rtc = timer_alloc(FUNC(mbc3_device_base::rtc_advance_seconds), this); + + save_item(NAME(m_rtc_regs)); + save_item(NAME(m_rtc_enable)); + save_item(NAME(m_rtc_select)); + save_item(NAME(m_rtc_latch)); +} + + +void mbc3_device_base::device_reset() +{ + mbc_ram_device_base::device_reset(); + + m_rtc_enable = 0U; + m_rtc_select = 0U; + m_rtc_latch = 0U; + + set_bank_rom_coarse(0); + set_bank_rom_fine(1); + set_bank_ram(0); + m_view_ram.disable(); +} + + +void mbc3_device_base::rtc_clock_updated( + int year, + int month, + int day, + int day_of_week, + int hour, + int minute, + int second) +{ + if (!m_has_rtc_xtal && !m_has_battery) + { + logerror("No real-time clock crystal or no battery present, not updating for elapsed time\n"); + } + else if (std::numeric_limits::min() == m_machine_seconds) + { + logerror("Failed to load machine time from previous session, not updating for elapsed time\n"); + } + else if (BIT(m_rtc_regs[0][4], 6)) + { + logerror("Real-time clock halted, not updating for elapsed time\n"); + } + else + { + // do a simple seconds elapsed since last run calculation + system_time current; + machine().current_datetime(current); + s64 delta(std::make_signed_t(current.time) - m_machine_seconds); + logerror("Previous session time, %d current time %d, delta %d\n", current.time, m_machine_seconds, delta); + if (0 > delta) + { + // This happens if the user runs the emulation faster + // than real time, exits, and then starts again without + // waiting for the difference between emulated and real + // time to elapse. + logerror("Previous session ended in the future, not updating for elapsed time\n"); + } + else + { + logerror( + "Time before applying delta %u %02u:%02u:%02u%s\n", + (u16(BIT(m_rtc_regs[0][4], 0)) << 8) | m_rtc_regs[0][3], + m_rtc_regs[0][2], + m_rtc_regs[0][1], + m_rtc_regs[0][0], + BIT(m_rtc_regs[0][4], 7) ? " (overflow)" : ""); + + // annoyingly, we can get two rollovers if we started with an invalid value + unsigned seconds(delta % 60); + delta /= 60; + if (60 <= m_rtc_regs[0][0]) + { + m_rtc_regs[0][0] = 0U; + --seconds; + ++delta; + } + if (60 <= (m_rtc_regs[0][0] + seconds)) + ++delta; + m_rtc_regs[0][0] = (m_rtc_regs[0][0] + seconds) % 60; + + // minutes is the same + unsigned minutes(delta % 60); + delta /= 60; + if (60 <= m_rtc_regs[0][1]) + { + m_rtc_regs[0][1] = 0U; + --minutes; + ++delta; + } + if (60 <= (m_rtc_regs[0][1] + minutes)) + ++delta; + m_rtc_regs[0][1] = (m_rtc_regs[0][1] + minutes) % 60; + + // hours just has a different rollover point + unsigned hours(delta % 24); + delta /= 24; + if (24 <= m_rtc_regs[0][2]) + { + m_rtc_regs[0][2] = 0U; + --hours; + ++delta; + } + if (24 <= (m_rtc_regs[0][2] + hours)) + ++delta; + m_rtc_regs[0][2] = (m_rtc_regs[0][2] + hours) % 24; + + // days has simple binary rollover + unsigned days(delta % 256); + if (256 <= (m_rtc_regs[0][3] + days)) + ++delta; + m_rtc_regs[0][3] += days; + + // set overflow flag if appropriate + if ((1 < delta) || (BIT(m_rtc_regs[0][4], 0) && delta)) + m_rtc_regs[0][4] |= 0x80; + m_rtc_regs[0][4] ^= BIT(delta, 0); + + logerror( + "Time after applying delta %u %02u:%02u:%02u%s\n", + (u16(BIT(m_rtc_regs[0][4], 0)) << 8) | m_rtc_regs[0][3], + m_rtc_regs[0][2], + m_rtc_regs[0][1], + m_rtc_regs[0][0], + BIT(m_rtc_regs[0][4], 7) ? " (overflow)" : ""); + } + } +} + + +void mbc3_device_base::nvram_default() +{ + // TODO: proper cold RTC state + m_machine_seconds = std::numeric_limits::min(); + for (unsigned i = 0U; std::size(m_rtc_regs[0]) > i; ++i) + m_rtc_regs[0][i] = RTC_MASK[i]; +} + + +bool mbc3_device_base::nvram_read(util::read_stream &file) +{ + if (m_has_battery) + { + // read previous machine time (seconds since epoch) and RTC registers + u64 seconds; + std::size_t actual; + if (file.read(&seconds, sizeof(seconds), actual) || (sizeof(seconds) != actual)) + return false; + m_machine_seconds = big_endianize_int64(seconds); + + if (file.read(&m_rtc_regs[0][0], sizeof(m_rtc_regs[0]), actual) || (sizeof(m_rtc_regs[0]) != actual)) + return false; + } + else + { + logerror("No battery present, not loading real-time clock register contents\n"); + } + return true; +} + + +bool mbc3_device_base::nvram_write(util::write_stream &file) +{ + // save current machine time as seconds since epoch and RTC registers + system_time current; + machine().current_datetime(current); + u64 const seconds(big_endianize_int64(s64(std::make_signed_t(current.time)))); + std::size_t written; + if (file.write(&seconds, sizeof(seconds), written) || (sizeof(seconds) != written)) + return false; + if (file.write(&m_rtc_regs[0][0], sizeof(m_rtc_regs[0]), written) || (sizeof(m_rtc_regs[0]) != written)) + return false; + return true; +} + + +bool mbc3_device_base::nvram_can_write() const +{ + return m_has_battery; +} + + +TIMER_CALLBACK_MEMBER(mbc3_device_base::rtc_advance_seconds) +{ + if (BIT(m_rtc_regs[0][4], 6)) + return; + + if (rtc_increment(0)) + return; + if (rtc_increment(1)) + return; + if (rtc_increment(2)) + return; + if (++m_rtc_regs[0][3]) + return; + + if (BIT(m_rtc_regs[0][4], 0)) + { + LOG("Day counter overflow"); + m_rtc_regs[0][4] |= 0x80; + } + m_rtc_regs[0][4] ^= 0x01; +} + + +void mbc3_device_base::enable_ram_rtc(u8 data) +{ + m_rtc_enable = (0x0a == (data & 0x0f)) ? 1U : 0U; + if (!m_rtc_enable) + { + LOG( + "%s: Cartridge RAM and RTC registers disabled\n", + machine().describe_context()); + m_view_ram.disable(); + } + else if (BIT(m_rtc_select, 3)) + { + LOG( + "%s: RTC register %u enabled\n", + machine().describe_context(), + m_rtc_select & 0x07); + m_view_ram.select(1); + } + else + { + LOG("%s: Cartridge RAM enabled\n", machine().describe_context()); + m_view_ram.select(0); + } +} + + +void mbc3_device_base::bank_switch_fine(u8 data) +{ + data &= 0x7f; + set_bank_rom_fine(data ? data : 1); +} + + +void mbc3_device_base::select_ram_rtc(u8 data) +{ + // TODO: what happens with the RAM bank outputs when the RTC is selected? + // TODO: what happens if RTC register 5-7 is selected? + // TODO: is the high nybble ignored altogether? + set_bank_rom_coarse(data & 0x07); + set_bank_ram(data & 0x07); + m_rtc_select = data; + if (m_rtc_enable) + { + if (BIT(data, 3)) + { + LOG( + "%s: RTC register %u enabled\n", + machine().describe_context(), + data & 0x07); + m_view_ram.select(1); + } + else + { + LOG("%s: Cartridge RAM enabled\n", machine().describe_context()); + m_view_ram.select(0); + } + } +} + + +void mbc3_device_base::latch_rtc(u8 data) +{ + // FIXME: does it just check the least significant bit, or does it look for 0x00 and 0x01? + LOG("Latch RTC 0x%02X -> 0x%02X\n", m_rtc_latch, data); + if (!BIT(m_rtc_latch, 0) && BIT(data, 0)) + { + LOG("%s: Latching RTC registers\n", machine().describe_context()); + std::copy(std::begin(m_rtc_regs[0]), std::end(m_rtc_regs[0]), std::begin(m_rtc_regs[1])); + } + m_rtc_latch = data; +} + + +u8 mbc3_device_base::read_rtc(address_space &space) +{ + u8 const reg(m_rtc_select & 0x07); + if (std::size(m_rtc_regs[1]) > reg) + { + LOG( + "%s: Read RTC register %u = 0x%02X\n", + machine().describe_context(), + reg, + m_rtc_regs[1][reg]); + return m_rtc_regs[1][reg]; + } + else + { + LOG( + "%s: Read invalid RTC register %u\n", + machine().describe_context(), + reg); + return space.unmap(); + } +} + + +void mbc3_device_base::write_rtc(u8 data) +{ + u8 const reg(m_rtc_select & 0x07); + if (std::size(m_rtc_regs[0]) > reg) + { + LOG( + "%s: Write RTC register %u = 0x%02X\n", + machine().describe_context(), + reg, + data); + if (4U == reg) + { + // TODO: are bits 5-1 physically present, and if not, what do they read as? + // TODO: how does halting the RTC interact with the prescaler? + data &= 0xc1; + m_rtc_regs[0][reg] = data; + } + else + { + m_rtc_regs[0][reg] = data; + } + } + else + { + LOG( + "%s: Write invalid RTC register %u = 0x%02X\n", + machine().describe_context(), + reg, + data); + } +} + + + +//************************************************************************** +// mbc3_device +//************************************************************************** + +mbc3_device::mbc3_device( + machine_config const &mconfig, + char const *tag, + device_t *owner, + u32 clock) : + mbc3_device_base(mconfig, GB_ROM_MBC3, tag, owner, clock) +{ +} + + +image_init_result mbc3_device::load(std::string &message) +{ + if (!install_memory(message, 2, 7)) + return image_init_result::FAIL; + else + return image_init_result::PASS; +} + + + +//************************************************************************** +// mbc30_device +//************************************************************************** + +mbc30_device::mbc30_device( + machine_config const &mconfig, + char const *tag, + device_t *owner, + u32 clock) : + mbc3_device_base(mconfig, GB_ROM_MBC30, tag, owner, clock) +{ +} + + +image_init_result mbc30_device::load(std::string &message) +{ + if (!install_memory(message, 3, 8)) + return image_init_result::FAIL; + else + return image_init_result::PASS; +} + +} // anonymous namespace + +} // namespace bus::gameboy + + +DEFINE_DEVICE_TYPE_PRIVATE(GB_ROM_MBC3, device_gb_cart_interface, bus::gameboy::mbc3_device, "gb_rom_mbc3", "Game Boy MBC3 Cartridge") +DEFINE_DEVICE_TYPE_PRIVATE(GB_ROM_MBC30, device_gb_cart_interface, bus::gameboy::mbc30_device, "gb_rom_mbc30", "Game Boy MBC30 Cartridge") diff --git a/src/devices/bus/gameboy/mbc3.h b/src/devices/bus/gameboy/mbc3.h new file mode 100644 index 00000000000..e039262fc3d --- /dev/null +++ b/src/devices/bus/gameboy/mbc3.h @@ -0,0 +1,19 @@ +// license:BSD-3-Clause +// copyright-holders:Vas Crabb +/*************************************************************************** + + Nintendo Game Boy Memory Bank Controller 3 + + ***************************************************************************/ +#ifndef MAME_BUS_GAMEBOY_MBC3_H +#define MAME_BUS_GAMEBOY_MBC3_H + +#pragma once + +#include "slot.h" + + +DECLARE_DEVICE_TYPE(GB_ROM_MBC3, device_gb_cart_interface) +DECLARE_DEVICE_TYPE(GB_ROM_MBC30, device_gb_cart_interface) + +#endif // MAME_BUS_GAMEBOY_MBC3_H diff --git a/src/devices/cpu/mn1880/mn1880.cpp b/src/devices/cpu/mn1880/mn1880.cpp index 0a23b988918..0843947a480 100644 --- a/src/devices/cpu/mn1880/mn1880.cpp +++ b/src/devices/cpu/mn1880/mn1880.cpp @@ -66,7 +66,7 @@ incorrectly reported for writes. * Due to the pipelining of writes, an interrupt may be accepted during an instruction which attempts to disable interrupts by setting the - IEMASK bit, which may be cleared insted when control reaches the next + IEMASK bit, which may be cleared instead when control reaches the next sequential instruction from a RETI. This sequencing glitch is documented in the MN187XX23 user's manual, along with a failsafe way of setting IEMASK, and similar workarounds in extant program code diff --git a/src/mame/atari/atarigt.cpp b/src/mame/atari/atarigt.cpp index 7058f25cb05..44a72cdd6fe 100644 --- a/src/mame/atari/atarigt.cpp +++ b/src/mame/atari/atarigt.cpp @@ -1194,7 +1194,7 @@ ROM_START( tmek20 ) ROM_END -ROM_START( primrage ) // still shows 'version 2.3' on the title screen but build is newer than the primrage set +ROM_START( primrage ) // still shows 'version 2.3' on the title screen but build is newer than the primrageo set ROM_REGION( 0x200000, "maincpu", 0 ) /* 8*64k for 68000 code, differ from the primrageo set */ ROM_LOAD32_BYTE( "rage_136102-2044a_pgmuu.29l", 0x000000, 0x80000, CRC(85556b91) SHA1(5f4f5d0bf68bd17b7bff230b521a5dcfff414a50) ) ROM_LOAD32_BYTE( "rage_136102-2043a_pgmum.28l", 0x000001, 0x80000, CRC(4d3414d0) SHA1(b6465c0fbee4e67f74185e9ea048e40f4f443efa) ) diff --git a/src/mame/jaleco/armchamp.cpp b/src/mame/jaleco/armchamp.cpp index 08f4fc38550..961df09c929 100644 --- a/src/mame/jaleco/armchamp.cpp +++ b/src/mame/jaleco/armchamp.cpp @@ -54,6 +54,8 @@ protected: virtual void video_start() override; private: + static constexpr XTAL MASTER_CLOCK = 12_MHz_XTAL; + uint32_t screen_update_armchamp(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); void main_prg(address_map &map); @@ -87,8 +89,6 @@ private: uint8_t m_adpcm_byte = 0; uint8_t m_msm5205_vclk_toggle = 0; uint16_t m_paletteram[0x100] = { }; - - static constexpr XTAL MASTER_CLOCK = 12_MHz_XTAL; }; @@ -196,7 +196,7 @@ void armchamp_state::io1_w(uint8_t data) // .xxx x... - Tile ROM bank // x... .... - Speech ROM banking enable - m_rombank->set_entry(((data & 0x80) >> 5) | (data & 3)); + m_rombank->set_entry(bitswap<3>(data, 7, 1, 0)); if ((m_io1 ^ data) & 0x78) { -- cgit v1.2.3