From 4f0dd32003888ab2a70f40ed79a85e74f23f1369 Mon Sep 17 00:00:00 2001 From: Tom <37988779+TwistedTom@users.noreply.github.com> Date: Mon, 11 Nov 2019 11:44:03 +0000 Subject: ZX Spectrum Multiface One improvements (#5885) * mface * mface improvements * use required_ioport, remove disable switch --- src/devices/bus/spectrum/mface.cpp | 187 ++++++++++++++++++++++++++++++++----- src/devices/bus/spectrum/mface.h | 36 +++++-- 2 files changed, 190 insertions(+), 33 deletions(-) diff --git a/src/devices/bus/spectrum/mface.cpp b/src/devices/bus/spectrum/mface.cpp index 807787126b2..1417c5db58c 100644 --- a/src/devices/bus/spectrum/mface.cpp +++ b/src/devices/bus/spectrum/mface.cpp @@ -2,7 +2,81 @@ // copyright-holders:Nigel Barnes /********************************************************************* - Romantic Robot Multiface One/128/3 + Romantic Robot Multiface One/128/3 + ---------------------------------- + + " MULTI-PURPOSE INTERFACE FOR THE ZX SPECTRUM " + + MULTIFACE ONE comprises three interfaces in one box: + 1) Fully universal and 100% automatic SAVE facility for tape, microdrive, wafadrive, Beta, + Discovery and indirectly (via tape) for other disc systems + 2) Joystick interface – Kempston compatible (IN 31) + 3) 8K RAM extension – fully accessible, usable as a RAM disk, buffer etc. Also used by + MULTIFACE for MULTI TOOLKIT routines, buffer & other purposes. + + © Romantic Robot UK Ltd 1985 + + + Multiface One + ------------- + Many versions exist, a very good source of info is: https://x128.speccy.cz/multiface/multiface.htm + + Summary: + Earliest version has 2KB of RAM, composite video output, and no toolkit (pokes only). + Next version has 8KB of RAM, composite video output, and basic toolkit (including pokes). + Latest and most common version dropped the composite video output, added an enable/disable switch, and full-featured toolkit. + A special (and rare) version supports the Kempston Disc interface but drops Beta support. (not sold in stores, available only on request). + At some point during "early" revisions, the page out port changed from 0x5f to 0x1f. + Various clone/hacked rom versions are known to exist as well. + + Roms: + The MUxx in the rom name is pcb revision (silkscreen marking). + The two hex digits are the rom checksum. + With the MF menu on-screen, press Symbol Shift + A (STOP) to see checksum, space to return. + + The enable/disable switch became necessary on later versions as games had started including checks to detect presence of the interface. + eg. Renegade ("The Hit Squad" re-release) whilst loading, reads from 0x9f specifically to cause the MF (if present) to page in and crash the machine. + Todo: confirm exact operation of disable switch. + + As mentioned in the user instructions, there is a "joystick disable" jumper inside the unit which must be cut to allow Beta disk compatibility. + The joystick is not actually disabled but rather just data bus bits D6 + D7 are held hi-z for any reads of kempston range 0b000xxxxx. + + rom maps to 0x0000 + ram maps to 0x2000 + + I/O R/W early ver late ver + ---------+-----+-----------+----------- + page in R 0x9f 0x9f + page out R 0x5f 0x1f + nmi reset W 0x5f 0x1f + joystick R 0x1f 0x1f + + + Multiface 128 + ------------- + 128K/+2 support (also works with 48K) + DISCiPLE/Plus D disc support + No joystick port + Software enable/disable + "Hypertape" recording (?) + + Todo ... + + + Multiface 3 + ----------- + +2A/+2B/+3/3B support (doesn't work with 48K/128K/+2) + +3 disk support + + Todo ... + + + Multiprint + ---------- + Version ? multiface with Centronics printer interface + + Todo ... + *********************************************************************/ @@ -24,37 +98,74 @@ DEFINE_DEVICE_TYPE(SPECTRUM_MPRINT, spectrum_mprint_device, "spectrum_mprint", " // INPUT_PORTS( mface ) //------------------------------------------------- -INPUT_PORTS_START(mface) +INPUT_PORTS_START( mface ) PORT_START("BUTTON") - PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_BUTTON1) PORT_NAME("Multiface") PORT_CODE(KEYCODE_F12) PORT_CHANGED_MEMBER(DEVICE_SELF, spectrum_mface1_device, magic_button, 0) + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_BUTTON1) PORT_NAME("Red Button") PORT_CODE(KEYCODE_BACKSPACE) PORT_CHANGED_MEMBER(DEVICE_SELF, spectrum_mface_base_device, magic_button, 0) +INPUT_PORTS_END + +INPUT_PORTS_START( mface1 ) + PORT_INCLUDE( mface ) + + PORT_START("CONFIG") + PORT_CONFNAME(0x01, 0x00, "Joystick Enable Jumper") + PORT_CONFSETTING(0x00, "Closed") + PORT_CONFSETTING(0x01, "Open") + PORT_BIT(0xfe, IP_ACTIVE_LOW, IPT_UNUSED) + + PORT_START("JOY") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT) PORT_8WAY + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT) PORT_8WAY + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN) PORT_8WAY + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP) PORT_8WAY + PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_BUTTON1) INPUT_PORTS_END //------------------------------------------------- // input_ports - device-specific input ports //------------------------------------------------- -ioport_constructor spectrum_mface1_device::device_input_ports() const +ioport_constructor spectrum_mface_base_device::device_input_ports() const { return INPUT_PORTS_NAME(mface); } +ioport_constructor spectrum_mface1_device::device_input_ports() const +{ + return INPUT_PORTS_NAME(mface1); +} + //------------------------------------------------- -// ROM( mface1 ) +// ROM( mface ) //------------------------------------------------- ROM_START(mface1) ROM_REGION(0x2000, "rom", 0) ROM_DEFAULT_BIOS("mu21e7") - ROM_SYSTEM_BIOS(0, "mu20fe", "MU 2.0 FE") + ROM_SYSTEM_BIOS(0, "mu20fe", "MU 2.0 FE") // pokes only (no toolkit) ROMX_LOAD("mf1_20_fe.rom", 0x0000, 0x2000, CRC(fa1b8b0d) SHA1(20cd508b0143166558a7238c7a9ccfbe37b90b0d), ROM_BIOS(0)) - ROM_SYSTEM_BIOS(1, "mu2167", "MU 2.1 67") + ROM_SYSTEM_BIOS(1, "mu2167", "MU 2.1 67") // Kempston Disc support, no Beta support ROMX_LOAD("mf1_21_67.rom", 0x0000, 0x2000, CRC(d720ec1b) SHA1(91a40d8f503ef825df3e2ed712897dbf4ca3671d), ROM_BIOS(1)) - ROM_SYSTEM_BIOS(2, "mu21e4", "MU 2.1 E4") + ROM_SYSTEM_BIOS(2, "mu21e4", "MU 2.1 E4") // the most common version ROMX_LOAD("mf1_21_e4.rom", 0x0000, 0x2000, CRC(4b31a971) SHA1(ba28754a3cc31a4ca579829ed4310c313409cf5d), ROM_BIOS(2)) - ROM_SYSTEM_BIOS(3, "mu21e7", "MU 2.1 E7") + ROM_SYSTEM_BIOS(3, "mu21e7", "MU 2.1 E7") // last known version? ROMX_LOAD("mf1_21_e7.rom", 0x0000, 0x2000, CRC(670f0ec2) SHA1(50fba2d628f3a2e9219f72980e4efd62fc9ec1f8), ROM_BIOS(3)) ROM_END +/* Todo ... + + ROM_SYSTEM_BIOS(?, "mu12cb", "MU12 CB") // Very early version, 2KB RAM, page out port 0x5F + ROMX_LOAD("mf1_12_cb.rom", 0x0000, 0x2000, CRC(c88fbf9f) SHA1(c3018d1b495b8bc0a135038db0987de7091c9d4c), ROM_BIOS(?)) + + ROM_SYSTEM_BIOS(?, "mu2023", "MU 2.0 23") // pokes only (no toolkit), page out port 0x5F + ROMX_LOAD("mf1_20_23.rom", 0x0000, 0x2000, CRC(d4ae8953) SHA1(b442eb634a72fb63f1ccbbd0021a7a581152888d), ROM_BIOS(?)) + + ROM_SYSTEM_BIOS(?, "mu2090", "MU 2.0, 90") // pokes only or full toolkit? NO DUMP? + ROMX_LOAD("mf1_20_90.rom", 0x0000, 0x2000, CRC(2eaf8e41) SHA1(?), ROM_BIOS(?)) + + ROM_SYSTEM_BIOS(?, "v24", "MU ?? 93 (Brazilian clone)") // NO DUMP? + ROMX_LOAD("mf1_bc_fe.rom", 0x0000, 0x2000, CRC(8c17113b) SHA1(?), ROM_BIOS(?)) +*/ + ROM_START(mface128) ROM_REGION(0x2000, "rom", 0) ROM_DEFAULT_BIOS("v363c") @@ -84,7 +195,7 @@ ROM_END // device_add_mconfig - add device configuration //------------------------------------------------- -void spectrum_mface1_device::device_add_mconfig(machine_config &config) +void spectrum_mface_base_device::device_add_mconfig(machine_config &config) { /* passthru */ SPECTRUM_EXPANSION_SLOT(config, m_exp, spectrum_expansion_devices, nullptr); @@ -118,10 +229,10 @@ const tiny_rom_entry *spectrum_mprint_device::device_rom_region() const //************************************************************************** //------------------------------------------------- -// spectrum_opus_device - constructor +// spectrum_mface_base_device - constructor //------------------------------------------------- -spectrum_mface1_device::spectrum_mface1_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) +spectrum_mface_base_device::spectrum_mface_base_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_spectrum_expansion_interface(mconfig, *this) , m_rom(*this, "rom") @@ -130,22 +241,24 @@ spectrum_mface1_device::spectrum_mface1_device(const machine_config &mconfig, de } spectrum_mface1_device::spectrum_mface1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : spectrum_mface1_device(mconfig, SPECTRUM_MFACE1, tag, owner, clock) + : spectrum_mface_base_device(mconfig, SPECTRUM_MFACE1, tag, owner, clock) + , m_joy(*this, "JOY") + , m_hwconfig(*this, "CONFIG") { } spectrum_mface128_device::spectrum_mface128_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : spectrum_mface1_device(mconfig, SPECTRUM_MFACE128, tag, owner, clock) + : spectrum_mface_base_device(mconfig, SPECTRUM_MFACE128, tag, owner, clock) { } spectrum_mface3_device::spectrum_mface3_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : spectrum_mface1_device(mconfig, SPECTRUM_MFACE3, tag, owner, clock) + : spectrum_mface_base_device(mconfig, SPECTRUM_MFACE3, tag, owner, clock) { } spectrum_mprint_device::spectrum_mprint_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : spectrum_mface1_device(mconfig, SPECTRUM_MPRINT, tag, owner, clock) + : spectrum_mface_base_device(mconfig, SPECTRUM_MPRINT, tag, owner, clock) { } @@ -153,7 +266,7 @@ spectrum_mprint_device::spectrum_mprint_device(const machine_config &mconfig, co // device_start - device-specific startup //------------------------------------------------- -void spectrum_mface1_device::device_start() +void spectrum_mface_base_device::device_start() { save_item(NAME(m_romcs)); } @@ -162,7 +275,7 @@ void spectrum_mface1_device::device_start() // device_reset - device-specific reset //------------------------------------------------- -void spectrum_mface1_device::device_reset() +void spectrum_mface_base_device::device_reset() { m_romcs = 0; } @@ -172,12 +285,12 @@ void spectrum_mface1_device::device_reset() // IMPLEMENTATION //************************************************************************** -READ_LINE_MEMBER(spectrum_mface1_device::romcs) +READ_LINE_MEMBER(spectrum_mface_base_device::romcs) { return m_romcs | m_exp->romcs(); } -void spectrum_mface1_device::pre_opcode_fetch(offs_t offset) +void spectrum_mface_base_device::pre_opcode_fetch(offs_t offset) { m_exp->pre_opcode_fetch(offset); @@ -191,13 +304,15 @@ void spectrum_mface1_device::pre_opcode_fetch(offs_t offset) uint8_t spectrum_mface1_device::iorq_r(offs_t offset) { uint8_t data = m_exp->iorq_r(offset); - + if (!machine().side_effects_disabled()) { switch (offset & 0xff) { case 0x1f: m_romcs = 0; + if (!(m_hwconfig->read() & 0x01)) // joystick disable jumper + data = m_joy->read() & 0x1f; break; case 0x9f: m_romcs = 1; @@ -264,12 +379,24 @@ uint8_t spectrum_mprint_device::iorq_r(offs_t offset) return data; } +void spectrum_mface_base_device::iorq_w(offs_t offset, uint8_t data) +{ + m_exp->iorq_w(offset, data); +} + void spectrum_mface1_device::iorq_w(offs_t offset, uint8_t data) { + switch (offset & 0xff) + { + case 0x1f: + m_slot->nmi_w(CLEAR_LINE); + break; + } + m_exp->iorq_w(offset, data); } -uint8_t spectrum_mface1_device::mreq_r(offs_t offset) +uint8_t spectrum_mface_base_device::mreq_r(offs_t offset) { uint8_t data = 0xff; @@ -292,7 +419,7 @@ uint8_t spectrum_mface1_device::mreq_r(offs_t offset) return data; } -void spectrum_mface1_device::mreq_w(offs_t offset, uint8_t data) +void spectrum_mface_base_device::mreq_w(offs_t offset, uint8_t data) { if (m_romcs) { @@ -308,7 +435,7 @@ void spectrum_mface1_device::mreq_w(offs_t offset, uint8_t data) m_exp->mreq_w(offset, data); } -INPUT_CHANGED_MEMBER(spectrum_mface1_device::magic_button) +INPUT_CHANGED_MEMBER(spectrum_mface_base_device::magic_button) { if (newval && !oldval) { @@ -319,3 +446,15 @@ INPUT_CHANGED_MEMBER(spectrum_mface1_device::magic_button) m_slot->nmi_w(CLEAR_LINE); } } + +INPUT_CHANGED_MEMBER(spectrum_mface1_device::magic_button) +{ + if (newval && !oldval) // key released + { + + } + else // key pressed + { + m_slot->nmi_w(ASSERT_LINE); + } +} diff --git a/src/devices/bus/spectrum/mface.h b/src/devices/bus/spectrum/mface.h index bf286cf9823..9f3d89ae6dc 100644 --- a/src/devices/bus/spectrum/mface.h +++ b/src/devices/bus/spectrum/mface.h @@ -15,19 +15,19 @@ // TYPE DEFINITIONS //************************************************************************** -class spectrum_mface1_device : +class spectrum_mface_base_device : public device_t, public device_spectrum_expansion_interface { public: // construction/destruction - spectrum_mface1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + spectrum_mface_base_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); - DECLARE_INPUT_CHANGED_MEMBER(magic_button); + virtual DECLARE_INPUT_CHANGED_MEMBER(magic_button); protected: - spectrum_mface1_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); + spectrum_mface_base_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); // device-level overrides virtual void device_start() override; @@ -35,13 +35,11 @@ protected: // optional information overrides virtual void device_add_mconfig(machine_config &config) override; - virtual const tiny_rom_entry *device_rom_region() const override; virtual ioport_constructor device_input_ports() const override; virtual void pre_opcode_fetch(offs_t offset) override; virtual uint8_t mreq_r(offs_t offset) override; virtual void mreq_w(offs_t offset, uint8_t data) override; - virtual uint8_t iorq_r(offs_t offset) override; virtual void iorq_w(offs_t offset, uint8_t data) override; virtual DECLARE_READ_LINE_MEMBER(romcs) override; @@ -52,7 +50,27 @@ protected: int m_romcs; }; -class spectrum_mface128_device : public spectrum_mface1_device +class spectrum_mface1_device : public spectrum_mface_base_device +{ +public: + spectrum_mface1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + DECLARE_INPUT_CHANGED_MEMBER(magic_button) override; + +protected: + // optional information overrides + virtual const tiny_rom_entry *device_rom_region() const override; + virtual ioport_constructor device_input_ports() const override; + + virtual uint8_t iorq_r(offs_t offset) override; + virtual void iorq_w(offs_t offset, uint8_t data) override; + +private: + required_ioport m_joy; + required_ioport m_hwconfig; +}; + +class spectrum_mface128_device : public spectrum_mface_base_device { public: spectrum_mface128_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); @@ -64,7 +82,7 @@ protected: virtual uint8_t iorq_r(offs_t offset) override; }; -class spectrum_mface3_device : public spectrum_mface1_device +class spectrum_mface3_device : public spectrum_mface_base_device { public: spectrum_mface3_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); @@ -76,7 +94,7 @@ protected: virtual uint8_t iorq_r(offs_t offset) override; }; -class spectrum_mprint_device : public spectrum_mface1_device +class spectrum_mprint_device : public spectrum_mface_base_device { public: spectrum_mprint_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); -- cgit v1.2.3