slot: add preliminary support for hotswapping rom cartridge

This commit is contained in:
hap 2021-05-04 16:23:12 +02:00
parent 9de981104f
commit 8f49d7d62e
6 changed files with 89 additions and 25 deletions

View File

@ -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();
}

View File

@ -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;

View File

@ -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);
}

View File

@ -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");
}

View File

@ -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

View File

@ -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");
}