From 8f49d7d62e06d4b35915374a910e81829377b44e Mon Sep 17 00:00:00 2001 From: hap Date: Tue, 4 May 2021 16:23:12 +0200 Subject: [PATCH] slot: add preliminary support for hotswapping rom cartridge --- src/devices/bus/generic/slot.cpp | 16 +++++++++++ src/devices/bus/generic/slot.h | 10 ++++--- src/frontend/mame/ui/swlist.cpp | 6 +++++ src/mame/drivers/aci_ggm.cpp | 31 ++++++++++++++------- src/mame/drivers/chessmst.cpp | 5 ++-- src/mame/drivers/chessmstdm.cpp | 46 ++++++++++++++++++++++++-------- 6 files changed, 89 insertions(+), 25 deletions(-) diff --git a/src/devices/bus/generic/slot.cpp b/src/devices/bus/generic/slot.cpp index c892d07f3fe..af83f35dca7 100644 --- a/src/devices/bus/generic/slot.cpp +++ b/src/devices/bus/generic/slot.cpp @@ -95,6 +95,19 @@ void device_generic_cart_interface::rom_alloc(u32 size, int width, endianness_t m_rom_size = size; } +void device_generic_cart_interface::rom_free(char const *tag) +{ + if (m_rom) + { + std::string fulltag(tag); + fulltag.append(GENERIC_ROM_REGION_TAG); + device().logerror("Deallocating ROM region with tag '%s'\n", fulltag); + device().machine().memory().region_free(fulltag.c_str()); + m_rom = nullptr; + m_rom_size = 0; + } +} + void device_generic_cart_interface::ram_alloc(u32 size) { if (!m_ram.empty()) @@ -123,6 +136,7 @@ generic_slot_device::generic_slot_device(machine_config const &mconfig, device_t m_default_card("rom"), m_extensions("bin"), m_must_be_loaded(false), + m_reset_on_load(true), m_width(GENERIC_ROM8_WIDTH), m_endianness(ENDIANNESS_LITTLE), m_cart(nullptr), @@ -186,6 +200,8 @@ void generic_slot_device::call_unload() { if (!m_device_image_unload.isnull()) return m_device_image_unload(*this); + else if (m_cart) + rom_free(); } diff --git a/src/devices/bus/generic/slot.h b/src/devices/bus/generic/slot.h index 837da36bdca..a203eb2a7ff 100644 --- a/src/devices/bus/generic/slot.h +++ b/src/devices/bus/generic/slot.h @@ -64,6 +64,7 @@ public: virtual void write_ram(offs_t offset, u8 data); virtual void rom_alloc(u32 size, int width, endianness_t end, char const *tag); + virtual void rom_free(char const *tag); virtual void ram_alloc(u32 size); u8 *get_rom_base() { return m_rom; } @@ -114,7 +115,8 @@ public: void set_interface(char const *interface) { m_interface = interface; } void set_default_card(char const *def) { m_default_card = def; } void set_extensions(char const *exts) { m_extensions = exts; } - void set_must_be_loaded(bool mandatory) { m_must_be_loaded = mandatory; } + void set_must_be_loaded(bool mandatory) { m_must_be_loaded = mandatory; } // default false + void set_reset_on_load(bool reset) { m_reset_on_load = reset; } // default true void set_width(int width) { m_width = width; } void set_endian(endianness_t end) { m_endianness = end; } @@ -126,7 +128,7 @@ public: virtual bool is_writeable() const noexcept override { return false; } virtual bool is_creatable() const noexcept override { return false; } virtual bool must_be_loaded() const noexcept override { return m_must_be_loaded; } - virtual bool is_reset_on_load() const noexcept override { return true; } + virtual bool is_reset_on_load() const noexcept override { return m_reset_on_load; } virtual char const *image_interface() const noexcept override { return m_interface; } virtual char const *file_extensions() const noexcept override { return m_extensions; } @@ -145,7 +147,8 @@ public: virtual void write_ram(offs_t offset, u8 data); virtual void rom_alloc(u32 size, int width, endianness_t end) { if (m_cart) m_cart->rom_alloc(size, width, end, tag()); } - virtual void ram_alloc(u32 size) { if (m_cart) m_cart->ram_alloc(size); } + virtual void rom_free() { if (m_cart) m_cart->rom_free(tag()); } + virtual void ram_alloc(u32 size) { if (m_cart) m_cart->ram_alloc(size); } u8* get_rom_base() { @@ -182,6 +185,7 @@ protected: char const *m_default_card; char const *m_extensions; bool m_must_be_loaded; + bool m_reset_on_load; int m_width; endianness_t m_endianness; device_generic_cart_interface *m_cart; diff --git a/src/frontend/mame/ui/swlist.cpp b/src/frontend/mame/ui/swlist.cpp index c373f9ff73b..11d2c7e00db 100644 --- a/src/frontend/mame/ui/swlist.cpp +++ b/src/frontend/mame/ui/swlist.cpp @@ -113,6 +113,8 @@ void menu_software_parts::populate(float &customtop, float &custombottom) item_append(m_info->shortname(), menu_part_name, 0, &entry); } } + + item_append(menu_item_type::SEPARATOR); } @@ -234,6 +236,8 @@ void menu_software_list::populate(float &customtop, float &custombottom) // append all of the menu entries for (auto &entry : m_entrylist) item_append(entry.short_name, entry.long_name, 0, &entry); + + item_append(menu_item_type::SEPARATOR); } @@ -395,6 +399,8 @@ void menu_software::populate(float &customtop, float &custombottom) } have_compatible = true; } + + item_append(menu_item_type::SEPARATOR); } diff --git a/src/mame/drivers/aci_ggm.cpp b/src/mame/drivers/aci_ggm.cpp index a9ec9967503..07449ad53eb 100644 --- a/src/mame/drivers/aci_ggm.cpp +++ b/src/mame/drivers/aci_ggm.cpp @@ -25,8 +25,9 @@ Known chess cartridges (*denotes not dumped): - Steinitz Edition-4 - Master Chess - *Monitor Edition - Master Kriegspiel -The opening/endgame cartridges are meant to be ejected/inserted while -playing (put the power switch in "MEM" first). +The opening/endgame cartridges are meant to be ejected/inserted while playing: +switch power switch to MEM, swap cartridge, switch power switch back to ON. +In other words, don't power cycle the machine (or MAME). Other games: - *Borchek Edition - Master Checkers @@ -50,7 +51,6 @@ TODO: #include "bus/generic/carts.h" #include "cpu/m6502/m6502.h" #include "machine/6522via.h" -#include "machine/nvram.h" #include "machine/timer.h" #include "sound/dac.h" #include "video/pwm.h" @@ -105,7 +105,8 @@ private: void update_display(); TIMER_DEVICE_CALLBACK_MEMBER(ca1_off) { m_via->write_ca1(0); } - DECLARE_DEVICE_IMAGE_LOAD_MEMBER(cartridge); + DECLARE_DEVICE_IMAGE_LOAD_MEMBER(load_cart); + DECLARE_DEVICE_IMAGE_UNLOAD_MEMBER(unload_cart); u8 cartridge_r(offs_t offset); void select_w(u8 data); @@ -165,7 +166,7 @@ void ggm_state::update_reset(ioport_value state) // cartridge -DEVICE_IMAGE_LOAD_MEMBER(ggm_state::cartridge) +DEVICE_IMAGE_LOAD_MEMBER(ggm_state::load_cart) { u32 size = m_cart->common_get_size("rom"); m_cart_mask = ((1 << (31 - count_leading_zeros(size))) - 1) & 0xffff; @@ -184,6 +185,18 @@ DEVICE_IMAGE_LOAD_MEMBER(ggm_state::cartridge) return image_init_result::PASS; } +DEVICE_IMAGE_UNLOAD_MEMBER(ggm_state::unload_cart) +{ + m_cart->rom_free(); + + // unmap extra ram + if (image.get_feature("ram")) + { + m_maincpu->space(AS_PROGRAM).nop_readwrite(0x0800, 0x0fff); + memset(m_extram, 0, m_extram.bytes()); + } +} + u8 ggm_state::cartridge_r(offs_t offset) { return m_cart->read_rom(offset & m_cart_mask); @@ -255,7 +268,7 @@ void ggm_state::main_map(address_map &map) { // external slot has potential bus conflict with RAM/VIA map(0x0000, 0xffff).r(FUNC(ggm_state::cartridge_r)); - map(0x0000, 0x07ff).ram().share("nvram"); + map(0x0000, 0x07ff).ram(); map(0x8000, 0x800f).m(m_via, FUNC(via6522_device::map)); } @@ -430,8 +443,6 @@ void ggm_state::ggm(machine_config &config) m_via->cb2_handler().set(FUNC(ggm_state::shift_data_w)); TIMER(config, m_ca1_off).configure_generic(FUNC(ggm_state::ca1_off)); - NVRAM(config, "nvram", nvram_device::DEFAULT_ALL_0); - /* video hardware */ PWM_DISPLAY(config, m_display).set_size(8, 16); m_display->set_segmask(0xff, 0x3fff); @@ -444,8 +455,10 @@ void ggm_state::ggm(machine_config &config) /* cartridge */ GENERIC_CARTSLOT(config, m_cart, generic_plain_slot, "ggm"); - m_cart->set_device_load(FUNC(ggm_state::cartridge)); + m_cart->set_device_load(FUNC(ggm_state::load_cart)); + m_cart->set_device_unload(FUNC(ggm_state::unload_cart)); m_cart->set_must_be_loaded(true); + m_cart->set_reset_on_load(false); SOFTWARE_LIST(config, "cart_list").set_original("ggm"); } diff --git a/src/mame/drivers/chessmst.cpp b/src/mame/drivers/chessmst.cpp index 8bbbe84c9b8..89519c17df8 100644 --- a/src/mame/drivers/chessmst.cpp +++ b/src/mame/drivers/chessmst.cpp @@ -180,6 +180,7 @@ void chessmst_state::chessmst_io(address_map &map) INPUT_CHANGED_MEMBER(chessmst_state::halt_button) { + // halt button goes to PIO(0) ASTB pin m_pio[0]->strobe_a(newval); reset_button(field, param, oldval, newval); } @@ -203,8 +204,8 @@ static INPUT_PORTS_START( chessmst ) PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("New Game / 0 / Pawn") PORT_CODE(KEYCODE_0) PORT_CODE(KEYCODE_0_PAD) PORT_CODE(KEYCODE_N) PORT_START("IN.1") - PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("Halt") PORT_CODE(KEYCODE_F2) PORT_CHANGED_MEMBER(DEVICE_SELF, chessmst_state, halt_button, 0) // -> PIO(0) ASTB pin - PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("Reset") PORT_CODE(KEYCODE_F1) PORT_CHANGED_MEMBER(DEVICE_SELF, chessmst_state, reset_button, 0) // -> Z80 RESET pin if HALT is pressed too + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("Halt") PORT_CODE(KEYCODE_F2) PORT_CHANGED_MEMBER(DEVICE_SELF, chessmst_state, halt_button, 0) + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("Reset") PORT_CODE(KEYCODE_F1) PORT_CHANGED_MEMBER(DEVICE_SELF, chessmst_state, reset_button, 0) INPUT_PORTS_END diff --git a/src/mame/drivers/chessmstdm.cpp b/src/mame/drivers/chessmstdm.cpp index 55fac94cc85..77520c91ebb 100644 --- a/src/mame/drivers/chessmstdm.cpp +++ b/src/mame/drivers/chessmstdm.cpp @@ -7,6 +7,9 @@ Chess-Master Diamond (G-5004-500), by VEB Mikroelektronik "Karl Marx" Erfurt The chess engine is a continuation of the older Chess-Master model. So it plays quite weak when compared with other chess computers from 1987. +PM10 and PM11 modules were included (not separate purchases). No other modules +were released. The player is supposed to hotswap them with the [CH M] option. + Hardware notes: - UA880 Z80 @ 4MHz - 2*Z80 PIO @@ -54,7 +57,8 @@ public: m_digits(*this, "digit%u", 0U) { } - DECLARE_INPUT_CHANGED_MEMBER(reset_button); + DECLARE_INPUT_CHANGED_MEMBER(monitor_button); + DECLARE_INPUT_CHANGED_MEMBER(view_button); void chessmstdm(machine_config &config); @@ -75,6 +79,7 @@ private: void chessmstdm_mem(address_map &map); void chessmstdm_io(address_map &map); + u8 reset_r(); void digits_w(u8 data); void pio1_port_a_w(u8 data); void pio1_port_b_w(u8 data); @@ -118,6 +123,18 @@ void chessmstdm_state::machine_reset() I/O ******************************************************************************/ +u8 chessmstdm_state::reset_r() +{ + // reading from 9cxx asserts a reset + if (!machine().side_effects_disabled()) + { + m_maincpu->set_input_line(INPUT_LINE_RESET, ASSERT_LINE); + machine_reset(); + } + + return 0xff; +} + void chessmstdm_state::update_digits() { u16 digit_data = bitswap<16>(m_digit_data, 3,5,12,10,14,1,2,13,8,6,11,15,7,9,4,0); @@ -200,6 +217,7 @@ void chessmstdm_state::chessmstdm_mem(address_map &map) map(0x0000, 0x3fff).rom(); map(0x4000, 0x7fff).r("cartslot", FUNC(generic_slot_device::read_rom)); map(0x8000, 0x8bff).ram(); + map(0x9c00, 0x9c00).mirror(0x0300).r(FUNC(chessmstdm_state::reset_r)); } void chessmstdm_state::chessmstdm_io(address_map &map) @@ -209,7 +227,7 @@ void chessmstdm_state::chessmstdm_io(address_map &map) //map(0x00, 0x03).mirror(0x70) read/write to both PIOs, but not used by software map(0x04, 0x07).mirror(0x70).rw(m_pio[0], FUNC(z80pio_device::read), FUNC(z80pio_device::write)); map(0x08, 0x0b).mirror(0x70).rw(m_pio[1], FUNC(z80pio_device::read), FUNC(z80pio_device::write)); - map(0x4c, 0x4c).mirror(0x03).w(FUNC(chessmstdm_state::digits_w)); + map(0x4c, 0x4c).mirror(0x33).w(FUNC(chessmstdm_state::digits_w)); } @@ -218,14 +236,20 @@ void chessmstdm_state::chessmstdm_io(address_map &map) Input Ports ******************************************************************************/ -INPUT_CHANGED_MEMBER(chessmstdm_state::reset_button) +INPUT_CHANGED_MEMBER(chessmstdm_state::monitor_button) +{ + // releasing monitor button clears reset + if (!newval && oldval) + m_maincpu->set_input_line(INPUT_LINE_RESET, CLEAR_LINE); + + view_button(field, param, oldval, newval); +} + +INPUT_CHANGED_MEMBER(chessmstdm_state::view_button) { // pressing both monitor+view buttons buttons causes a reset - const bool reset = (m_inputs[1]->read() & 0x03) == 0x03; - m_maincpu->set_input_line(INPUT_LINE_RESET, reset ? ASSERT_LINE : CLEAR_LINE); - - if (reset) - machine_reset(); + if ((m_inputs[1]->read() & 0x03) == 0x03) + reset_r(); } static INPUT_PORTS_START( chessmstdm ) @@ -240,8 +264,8 @@ static INPUT_PORTS_START( chessmstdm ) PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("Enter") PORT_CODE(KEYCODE_ENTER) PORT_CODE(KEYCODE_ENTER_PAD) PORT_START("IN.1") - PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("Monitor") PORT_CODE(KEYCODE_F1) PORT_CHANGED_MEMBER(DEVICE_SELF, chessmstdm_state, reset_button, 0) - PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("View") PORT_CODE(KEYCODE_F2) PORT_CHANGED_MEMBER(DEVICE_SELF, chessmstdm_state, reset_button, 0) + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("Monitor") PORT_CODE(KEYCODE_F1) PORT_CHANGED_MEMBER(DEVICE_SELF, chessmstdm_state, monitor_button, 0) + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("View") PORT_CODE(KEYCODE_F2) PORT_CHANGED_MEMBER(DEVICE_SELF, chessmstdm_state, view_button, 0) INPUT_PORTS_END @@ -296,7 +320,7 @@ void chessmstdm_state::chessmstdm(machine_config &config) BEEP(config, m_beeper, 1000).add_route(ALL_OUTPUTS, "speaker", 0.25); // cartridge - GENERIC_CARTSLOT(config, "cartslot", generic_plain_slot, "chessmstdm_cart"); + GENERIC_CARTSLOT(config, "cartslot", generic_plain_slot, "chessmstdm_cart").set_reset_on_load(false); SOFTWARE_LIST(config, "cart_list").set_original("chessmstdm"); }