diff --git a/scripts/src/bus.lua b/scripts/src/bus.lua index be1805ba9b8..b86f1073c08 100644 --- a/scripts/src/bus.lua +++ b/scripts/src/bus.lua @@ -4114,6 +4114,8 @@ if (BUSES["SPECTRUM"]~=null) then MAME_DIR .. "src/devices/bus/spectrum/mgt.h", MAME_DIR .. "src/devices/bus/spectrum/mikroplus.cpp", MAME_DIR .. "src/devices/bus/spectrum/mikroplus.h", + MAME_DIR .. "src/devices/bus/spectrum/mpoker.cpp", + MAME_DIR .. "src/devices/bus/spectrum/mpoker.h", MAME_DIR .. "src/devices/bus/spectrum/opus.cpp", MAME_DIR .. "src/devices/bus/spectrum/opus.h", MAME_DIR .. "src/devices/bus/spectrum/plus2test.cpp", @@ -4128,6 +4130,8 @@ if (BUSES["SPECTRUM"]~=null) then MAME_DIR .. "src/devices/bus/spectrum/speccydos.h", MAME_DIR .. "src/devices/bus/spectrum/specdrum.cpp", MAME_DIR .. "src/devices/bus/spectrum/specdrum.h", + MAME_DIR .. "src/devices/bus/spectrum/specmate.cpp", + MAME_DIR .. "src/devices/bus/spectrum/specmate.h", MAME_DIR .. "src/devices/bus/spectrum/uslot.cpp", MAME_DIR .. "src/devices/bus/spectrum/uslot.h", MAME_DIR .. "src/devices/bus/spectrum/usource.cpp", diff --git a/src/devices/bus/spectrum/beta.cpp b/src/devices/bus/spectrum/beta.cpp index 742f09e1922..6a2d75e9f2c 100644 --- a/src/devices/bus/spectrum/beta.cpp +++ b/src/devices/bus/spectrum/beta.cpp @@ -264,6 +264,7 @@ void spectrum_betav2_device::device_add_mconfig_base(machine_config& config) SPECTRUM_EXPANSION_SLOT(config, m_exp, spectrum_expansion_devices, nullptr); m_exp->irq_handler().set(DEVICE_SELF_OWNER, FUNC(spectrum_expansion_slot_device::irq_w)); m_exp->nmi_handler().set(DEVICE_SELF_OWNER, FUNC(spectrum_expansion_slot_device::nmi_w)); + m_exp->fb_r_handler().set(DEVICE_SELF_OWNER, FUNC(spectrum_expansion_slot_device::fb_r)); } void spectrum_betav2_device::device_add_mconfig(machine_config &config) diff --git a/src/devices/bus/spectrum/beta128.cpp b/src/devices/bus/spectrum/beta128.cpp index c0af1ef24c7..2aaea396504 100644 --- a/src/devices/bus/spectrum/beta128.cpp +++ b/src/devices/bus/spectrum/beta128.cpp @@ -114,6 +114,7 @@ void spectrum_beta128_device::device_add_mconfig(machine_config &config) SPECTRUM_EXPANSION_SLOT(config, m_exp, spectrum_expansion_devices, nullptr); m_exp->irq_handler().set(DEVICE_SELF_OWNER, FUNC(spectrum_expansion_slot_device::irq_w)); m_exp->nmi_handler().set(DEVICE_SELF_OWNER, FUNC(spectrum_expansion_slot_device::nmi_w)); + m_exp->fb_r_handler().set(DEVICE_SELF_OWNER, FUNC(spectrum_expansion_slot_device::fb_r)); } const tiny_rom_entry *spectrum_beta128_device::device_rom_region() const diff --git a/src/devices/bus/spectrum/d40.cpp b/src/devices/bus/spectrum/d40.cpp index e88f4607c54..9a7811b7936 100644 --- a/src/devices/bus/spectrum/d40.cpp +++ b/src/devices/bus/spectrum/d40.cpp @@ -246,7 +246,7 @@ void spectrum_d40base_device::pre_opcode_fetch(offs_t offset) uint8_t spectrum_d40base_device::iorq_r(offs_t offset) { - uint8_t data = 0xff; + uint8_t data = offset & 1 ? m_slot->fb_r() : 0xff; switch (offset & 0xf9) { diff --git a/src/devices/bus/spectrum/exp.cpp b/src/devices/bus/spectrum/exp.cpp index 51950eb7bb7..a0c79eeaec8 100644 --- a/src/devices/bus/spectrum/exp.cpp +++ b/src/devices/bus/spectrum/exp.cpp @@ -45,7 +45,8 @@ spectrum_expansion_slot_device::spectrum_expansion_slot_device(const machine_con device_single_card_slot_interface(mconfig, *this), m_card(nullptr), m_irq_handler(*this), - m_nmi_handler(*this) + m_nmi_handler(*this), + m_fb_r_handler(*this) { } @@ -61,6 +62,7 @@ void spectrum_expansion_slot_device::device_start() // resolve callbacks m_irq_handler.resolve_safe(); m_nmi_handler.resolve_safe(); + m_fb_r_handler.resolve_safe(0xff); } //------------------------------------------------- @@ -112,7 +114,7 @@ uint8_t spectrum_expansion_slot_device::iorq_r(offs_t offset) if (m_card) return m_card->iorq_r(offset); else - return 0xff; + return offset & 1 ? fb_r() : 0xff; } //------------------------------------------------- @@ -169,6 +171,7 @@ void spectrum_expansion_slot_device::mreq_w(offs_t offset, uint8_t data) #include "mface.h" #include "mgt.h" #include "mikroplus.h" +#include "mpoker.h" #include "opus.h" #include "plus2test.h" #include "protek.h" @@ -176,6 +179,7 @@ void spectrum_expansion_slot_device::mreq_w(offs_t offset, uint8_t data) #include "sixword.h" #include "specdrum.h" #include "speccydos.h" +#include "specmate.h" #include "uslot.h" #include "usource.h" #include "uspeech.h" @@ -206,9 +210,14 @@ void spectrum_expansion_devices(device_slot_interface &device) device.option_add("lprint", SPECTRUM_LPRINT); device.option_add("lprint3", SPECTRUM_LPRINT3); device.option_add("melodik", SPECTRUM_MELODIK); + device.option_add("mface1v1", SPECTRUM_MFACE1V1); + device.option_add("mface1v2", SPECTRUM_MFACE1V2); + device.option_add("mface1v3", SPECTRUM_MFACE1V3); device.option_add("mface1", SPECTRUM_MFACE1); + device.option_add("mface128v1", SPECTRUM_MFACE128V1); device.option_add("mface128", SPECTRUM_MFACE128); device.option_add("mikroplus", SPECTRUM_MIKROPLUS); + device.option_add("mpoker", SPECTRUM_MPOKER); device.option_add("mprint", SPECTRUM_MPRINT); device.option_add("opus", SPECTRUM_OPUS); device.option_add("plusd", SPECTRUM_PLUSD); @@ -218,6 +227,7 @@ void spectrum_expansion_devices(device_slot_interface &device) device.option_add("speccydos", SPECTRUM_SPECCYDOS); device.option_add("spdos", SPECTRUM_SPDOS); device.option_add("specdrum", SPECTRUM_SPECDRUM); + device.option_add("specmate", SPECTRUM_SPECMATE); device.option_add("swiftdisc", SPECTRUM_SWIFTDISC); device.option_add("swiftdisc2", SPECTRUM_SWIFTDISC2); device.option_add("uslot", SPECTRUM_USLOT); @@ -233,6 +243,7 @@ void spec128_expansion_devices(device_slot_interface &device) device.option_add("intf1", SPECTRUM_INTF1); device.option_add("intf2", SPECTRUM_INTF2); device.option_add("kempjoy", SPECTRUM_KEMPJOY); + device.option_add("mface128v1", SPECTRUM_MFACE128V1); device.option_add("mface128", SPECTRUM_MFACE128); device.option_add("mikroplus", SPECTRUM_MIKROPLUS); device.option_add("mprint", SPECTRUM_MPRINT); @@ -249,6 +260,7 @@ void spec128_expansion_devices(device_slot_interface &device) void specpls3_expansion_devices(device_slot_interface &device) { + device.option_add("kempjoy", SPECTRUM_KEMPJOY); device.option_add("mface3", SPECTRUM_MFACE3); } diff --git a/src/devices/bus/spectrum/exp.h b/src/devices/bus/spectrum/exp.h index 91d1922c577..5b6d3c8fecf 100644 --- a/src/devices/bus/spectrum/exp.h +++ b/src/devices/bus/spectrum/exp.h @@ -76,6 +76,7 @@ public: // callbacks auto irq_handler() { return m_irq_handler.bind(); } auto nmi_handler() { return m_nmi_handler.bind(); } + auto fb_r_handler() { return m_fb_r_handler.bind(); } void pre_opcode_fetch(offs_t offset); void post_opcode_fetch(offs_t offset); @@ -90,6 +91,7 @@ public: DECLARE_WRITE_LINE_MEMBER( irq_w ) { m_irq_handler(state); } DECLARE_WRITE_LINE_MEMBER( nmi_w ) { m_nmi_handler(state); } + uint8_t fb_r() { return m_fb_r_handler(); } protected: // device-level overrides @@ -100,6 +102,7 @@ protected: private: devcb_write_line m_irq_handler; devcb_write_line m_nmi_handler; + devcb_read8 m_fb_r_handler; }; @@ -115,7 +118,7 @@ public: virtual void post_data_fetch(offs_t offset) { }; virtual uint8_t mreq_r(offs_t offset) { return 0xff; } virtual void mreq_w(offs_t offset, uint8_t data) { } - virtual uint8_t iorq_r(offs_t offset) { return 0xff; } + virtual uint8_t iorq_r(offs_t offset) { return offset & 1 ? m_slot->fb_r() : 0xff; } virtual void iorq_w(offs_t offset, uint8_t data) { } virtual DECLARE_READ_LINE_MEMBER(romcs) { return 0; } diff --git a/src/devices/bus/spectrum/floppyone.cpp b/src/devices/bus/spectrum/floppyone.cpp index 00f7aeb72aa..026285dd854 100644 --- a/src/devices/bus/spectrum/floppyone.cpp +++ b/src/devices/bus/spectrum/floppyone.cpp @@ -131,6 +131,7 @@ void spectrum_flpone_device::device_add_mconfig(machine_config &config) SPECTRUM_EXPANSION_SLOT(config, m_exp, spectrum_expansion_devices, nullptr); m_exp->irq_handler().set(DEVICE_SELF_OWNER, FUNC(spectrum_expansion_slot_device::irq_w)); m_exp->nmi_handler().set(DEVICE_SELF_OWNER, FUNC(spectrum_expansion_slot_device::nmi_w)); + m_exp->fb_r_handler().set(DEVICE_SELF_OWNER, FUNC(spectrum_expansion_slot_device::fb_r)); } const tiny_rom_entry *spectrum_flpone_device::device_rom_region() const diff --git a/src/devices/bus/spectrum/fuller.cpp b/src/devices/bus/spectrum/fuller.cpp index 6d3371a44aa..0346a806171 100644 --- a/src/devices/bus/spectrum/fuller.cpp +++ b/src/devices/bus/spectrum/fuller.cpp @@ -55,6 +55,7 @@ void spectrum_fuller_device::device_add_mconfig(machine_config &config) SPECTRUM_EXPANSION_SLOT(config, m_exp, spectrum_expansion_devices, nullptr); m_exp->irq_handler().set(DEVICE_SELF_OWNER, FUNC(spectrum_expansion_slot_device::irq_w)); m_exp->nmi_handler().set(DEVICE_SELF_OWNER, FUNC(spectrum_expansion_slot_device::nmi_w)); + m_exp->fb_r_handler().set(DEVICE_SELF_OWNER, FUNC(spectrum_expansion_slot_device::fb_r)); } //************************************************************************** @@ -95,10 +96,10 @@ uint8_t spectrum_fuller_device::iorq_r(offs_t offset) switch (offset & 0xff) { case 0x5f: - data &= m_psg->data_r(); + data = m_psg->data_r(); break; case 0x7f: - data &= m_joy->read() | (0xff ^ 0x8f); + data = m_joy->read() | (0xff ^ 0x8f); break; } return data; diff --git a/src/devices/bus/spectrum/intf1.cpp b/src/devices/bus/spectrum/intf1.cpp index aaef5a53fbf..df40de1f9d6 100644 --- a/src/devices/bus/spectrum/intf1.cpp +++ b/src/devices/bus/spectrum/intf1.cpp @@ -54,6 +54,7 @@ void spectrum_intf1_device::device_add_mconfig(machine_config &config) SPECTRUM_EXPANSION_SLOT(config, m_exp, spectrum_expansion_devices, nullptr); m_exp->irq_handler().set(DEVICE_SELF_OWNER, FUNC(spectrum_expansion_slot_device::irq_w)); m_exp->nmi_handler().set(DEVICE_SELF_OWNER, FUNC(spectrum_expansion_slot_device::nmi_w)); + m_exp->fb_r_handler().set(DEVICE_SELF_OWNER, FUNC(spectrum_expansion_slot_device::fb_r)); SOFTWARE_LIST(config, "microdrive_list").set_original("spectrum_microdrive"); } diff --git a/src/devices/bus/spectrum/intf2.cpp b/src/devices/bus/spectrum/intf2.cpp index 8fbf1139f3f..5b407d88df3 100644 --- a/src/devices/bus/spectrum/intf2.cpp +++ b/src/devices/bus/spectrum/intf2.cpp @@ -128,7 +128,7 @@ uint8_t spectrum_intf2_device::mreq_r(offs_t offset) uint8_t spectrum_intf2_device::iorq_r(offs_t offset) { - uint8_t data = 0xff; + uint8_t data = offset & 1 ? m_slot->fb_r() : 0xff; switch (offset & 0xff) { diff --git a/src/devices/bus/spectrum/kempdisc.cpp b/src/devices/bus/spectrum/kempdisc.cpp index 3defea60d16..32573ebf969 100644 --- a/src/devices/bus/spectrum/kempdisc.cpp +++ b/src/devices/bus/spectrum/kempdisc.cpp @@ -96,6 +96,7 @@ void spectrum_kempdisc_device::device_add_mconfig(machine_config &config) SPECTRUM_EXPANSION_SLOT(config, m_exp, spectrum_expansion_devices, nullptr); m_exp->irq_handler().set(DEVICE_SELF_OWNER, FUNC(spectrum_expansion_slot_device::irq_w)); m_exp->nmi_handler().set(DEVICE_SELF_OWNER, FUNC(spectrum_expansion_slot_device::nmi_w)); + m_exp->fb_r_handler().set(DEVICE_SELF_OWNER, FUNC(spectrum_expansion_slot_device::fb_r)); } const tiny_rom_entry *spectrum_kempdisc_device::device_rom_region() const @@ -174,7 +175,7 @@ uint8_t spectrum_kempdisc_device::iorq_r(offs_t offset) switch (offset & 0xff) { case 0xe5: case 0xe7: case 0xed: case 0xef: - data &= m_fdc->read(BIT(offset, 1) | (BIT(offset, 3) << 1)); + data = m_fdc->read(BIT(offset, 1) | (BIT(offset, 3) << 1)); break; } diff --git a/src/devices/bus/spectrum/kempjoy.cpp b/src/devices/bus/spectrum/kempjoy.cpp index a09583d3a3e..4dee6eabba0 100644 --- a/src/devices/bus/spectrum/kempjoy.cpp +++ b/src/devices/bus/spectrum/kempjoy.cpp @@ -71,9 +71,9 @@ void spectrum_kempjoy_device::device_start() uint8_t spectrum_kempjoy_device::iorq_r(offs_t offset) { - uint8_t data = 0xff; + uint8_t data = offset & 1 ? m_slot->fb_r() : 0xff; - if ((offset & 0x00ff) == 0x1f) + if ((offset & 0xe0) == 0) // 000- ---- uses 0x1f { data = m_joy->read() & 0x1f; } diff --git a/src/devices/bus/spectrum/logitek.cpp b/src/devices/bus/spectrum/logitek.cpp index 3cb8105e655..6406231ce47 100644 --- a/src/devices/bus/spectrum/logitek.cpp +++ b/src/devices/bus/spectrum/logitek.cpp @@ -170,7 +170,7 @@ uint8_t spectrum_proceed_device::mreq_r(offs_t offset) uint8_t spectrum_proceed_device::iorq_r(offs_t offset) { - uint8_t data = 0xff; + uint8_t data = offset & 1 ? m_slot->fb_r() : 0xff; if (!BIT(offset, 5)) data = m_z80pio->read((offset >> 6) & 3); diff --git a/src/devices/bus/spectrum/lprint.cpp b/src/devices/bus/spectrum/lprint.cpp index 43bc0f60348..912c26d6c74 100644 --- a/src/devices/bus/spectrum/lprint.cpp +++ b/src/devices/bus/spectrum/lprint.cpp @@ -98,6 +98,7 @@ void spectrum_lprint3_device::device_add_mconfig(machine_config &config) SPECTRUM_EXPANSION_SLOT(config, m_exp, spectrum_expansion_devices, nullptr); m_exp->irq_handler().set(DEVICE_SELF_OWNER, FUNC(spectrum_expansion_slot_device::irq_w)); m_exp->nmi_handler().set(DEVICE_SELF_OWNER, FUNC(spectrum_expansion_slot_device::nmi_w)); + m_exp->fb_r_handler().set(DEVICE_SELF_OWNER, FUNC(spectrum_expansion_slot_device::fb_r)); } void spectrum_kempcentrs_device::device_add_mconfig(machine_config &config) @@ -279,7 +280,7 @@ uint8_t spectrum_lprint_device::mreq_r(offs_t offset) uint8_t spectrum_lprint_device::iorq_r(offs_t offset) { - uint8_t data = 0xff; + uint8_t data = offset & 1 ? m_slot->fb_r() : 0xff; if (!BIT(offset, 2)) { @@ -374,7 +375,7 @@ uint8_t spectrum_lprint3_device::mreq_r(offs_t offset) uint8_t spectrum_kempcentrs_device::iorq_r(offs_t offset) { - uint8_t data = 0xff; + uint8_t data = offset & 1 ? m_slot->fb_r() : 0xff; switch (offset) { @@ -432,7 +433,7 @@ void spectrum_kempcentre_device::pre_data_fetch(offs_t offset) uint8_t spectrum_kempcentre_device::iorq_r(offs_t offset) { - uint8_t data = 0xff; + uint8_t data = offset & 1 ? m_slot->fb_r() : 0xff; if (!BIT(offset, 2)) // earlier version ? uses same paging as Lprint III { @@ -506,7 +507,7 @@ void spectrum_kempcentreu_device::pre_opcode_fetch(offs_t offset) uint8_t spectrum_kempcentreu_device::iorq_r(offs_t offset) { - uint8_t data = 0xff; + uint8_t data = offset & 1 ? m_slot->fb_r() : 0xff; if ((offset & 0xf0) == 0xb0) // BB or BF, actual address decode is not known { diff --git a/src/devices/bus/spectrum/melodik.cpp b/src/devices/bus/spectrum/melodik.cpp index 95c426149a1..0b77635c051 100644 --- a/src/devices/bus/spectrum/melodik.cpp +++ b/src/devices/bus/spectrum/melodik.cpp @@ -32,6 +32,7 @@ void spectrum_melodik_device::device_add_mconfig(machine_config &config) SPECTRUM_EXPANSION_SLOT(config, m_exp, spectrum_expansion_devices, nullptr); m_exp->irq_handler().set(DEVICE_SELF_OWNER, FUNC(spectrum_expansion_slot_device::irq_w)); m_exp->nmi_handler().set(DEVICE_SELF_OWNER, FUNC(spectrum_expansion_slot_device::nmi_w)); + m_exp->fb_r_handler().set(DEVICE_SELF_OWNER, FUNC(spectrum_expansion_slot_device::fb_r)); } //************************************************************************** @@ -71,7 +72,7 @@ uint8_t spectrum_melodik_device::iorq_r(offs_t offset) switch (offset & 0xc002) { case 0xc000: - data &= m_psg->data_r(); + data = m_psg->data_r(); break; } return data; diff --git a/src/devices/bus/spectrum/mface.cpp b/src/devices/bus/spectrum/mface.cpp index 03579a26bb5..693b3eb4fcf 100644 --- a/src/devices/bus/spectrum/mface.cpp +++ b/src/devices/bus/spectrum/mface.cpp @@ -17,16 +17,26 @@ © Romantic Robot UK Ltd 1985 + Compatibility (real hardware) + ------------- + mface1 models work with 48K, 128K/+2 (only in 48K mode), don't work with +2A/+3 + mface128 models work with 48K/128K/+2, don't work with +2A/+3 + mface3 works only with +2A/+3 + mprint works with 48K/128K/+2, doesn't work with +2A/+3 + incompatibility is due mainly to expansion slot pinout changes on last Amstrad built models. + + 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). + Earliest version has 2KB of RAM, composite video output, and no pokes or toolkit. + Next version has 8KB of RAM, composite video output, and basic toolkit (just 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. + At some point the page out port changed from 0x5f to 0x1f (rev 2.0 pcb?) + Three pcb revs are known: 1.2, 2.0, 2.1. Various clone/hacked rom versions are known to exist as well. Roms: @@ -34,12 +44,16 @@ 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 "joystick disable" jumper is required for use with Beta disk which would otherwise not work due to port clash. + Real world mf1/beta combo only works spectrum->mf1->beta, with jumper open, the user manual suggests Beta users may like to fit a switch instead. + Some confusion exactly how this works, as an original-looking schematic shows the jumper simply setting data bits 6,7 hi-z, with the actual joystick still operational. + This isn't enough to stop the clash so perhaps schematic is for some non-Beta-supporting version or has an error. + Assume for now the entire joystick is disabled as that's the only way Beta can work. + Beta support seems limited to Beta v3/plus (TR-DOS 3/4.xx) models, beta128 (TR-DOS 5.xx) doesn't work. + Bios rom "mu21e7" has issues with Betaplus, doesn't work with betav3,beta128,betacbi, perhaps it's for some other interface entirely...? + 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 @@ -55,27 +69,51 @@ Multiface 128 ------------- 128K/+2 support (also works with 48K) - DISCiPLE/Plus D disc support + Software enable/disable (in menu, press 'o' to toggle on/off) + Some new 128k-exclusive menu features when running in 128k mode (mode is auto-detected) No joystick port - Software enable/disable - "Hypertape" recording (?) + No Beta support + Pass-through connector was optional + Original hardware version isn't compatible with DISCiPLE/+D (port clash), has "hypertape" high-speed tape recording + Second hardware version added DISCiPLE/+D compatibility and support as save device (uses different ports) but lost hypertape support - Todo ... + supported devices rom + -----+----------------------------------------+------------- + v1 Tape, Hypertape, Microdrive, Opus 87.1, 87.12 + v2 Tape, Microdrive, Opus, DISCiPLE/+D 87.2 + + I/O R/W v1 v2 + ---------+-----+-----------+----------- + page in R 0x9f 0xbf + page out R 0x1f 0x3f + nmi reset W 0x9f 0xbf + hide W 0x1f 0x3f Multiface 3 ----------- - +2A/+2B/+3/3B support (doesn't work with 48K/128K/+2) + +2A/+2B/+3/+3B support (doesn't work with 48K/128K/+2) +3 disk support - - Todo ... + Pass-through connector was optional + No support for older external disk interfaces (Beta, Opus, +D etc.) + Pcb/logic is quite different to other models, has a PAL16L8 and 74LS670 4x4 register file. + A schematic created from the Hard Mirco clone pcb is available, used for various modern "re-creation" projects, + official version assumed to be very similar if not identical. + Hard Mirco clone has double size ROM (16K), but contains two identical 8K halves of data. Pcb does have ability to select rom half via software, + so perhaps an unused multi-bios feature? (unknown if unique to clone pcb or present on official pcb also). Multiprint ---------- - Version ? multiface with Centronics printer interface + Printer interface with some mface features + No backup/snapshot feature + Has all other usual mface features: cheat/poke, 8KB RAM, magic button etc. + Centronics parallel printer port + Kempston E and ZX Lprint compatible (LPRINT, LLIST, COPY etc.) + Unique "REM" command set (commands "hidden" in rem comments) + Pass-through connector was optional - Todo ... + Todo: find other print command hooks, only magic button triggered menu works for now... *********************************************************************/ @@ -88,7 +126,11 @@ DEVICE DEFINITIONS ***************************************************************************/ +DEFINE_DEVICE_TYPE(SPECTRUM_MFACE1V1, spectrum_mface1v1_device, "spectrum_mface1v1", "Multiface One v1") +DEFINE_DEVICE_TYPE(SPECTRUM_MFACE1V2, spectrum_mface1v2_device, "spectrum_mface1v2", "Multiface One v2") +DEFINE_DEVICE_TYPE(SPECTRUM_MFACE1V3, spectrum_mface1v3_device, "spectrum_mface1v3", "Multiface One v3") DEFINE_DEVICE_TYPE(SPECTRUM_MFACE1, spectrum_mface1_device, "spectrum_mface1", "Multiface One") +DEFINE_DEVICE_TYPE(SPECTRUM_MFACE128V1, spectrum_mface128v1_device, "spectrum_mface128v1", "Multiface 128 v1") DEFINE_DEVICE_TYPE(SPECTRUM_MFACE128, spectrum_mface128_device, "spectrum_mface128", "Multiface 128") DEFINE_DEVICE_TYPE(SPECTRUM_MFACE3, spectrum_mface3_device, "spectrum_mface3", "Multiface 3") DEFINE_DEVICE_TYPE(SPECTRUM_MPRINT, spectrum_mprint_device, "spectrum_mprint", "MultiPrint") @@ -100,17 +142,17 @@ DEFINE_DEVICE_TYPE(SPECTRUM_MPRINT, spectrum_mprint_device, "spectrum_mprint", " INPUT_PORTS_START( mface ) PORT_START("BUTTON") - 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) + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_BUTTON1) PORT_NAME("Red Button") PORT_CODE(KEYCODE_PLUS_PAD) PORT_CHANGED_MEMBER(DEVICE_SELF, spectrum_mface_base_device, magic_button, 0) INPUT_PORTS_END -INPUT_PORTS_START( mface1 ) +INPUT_PORTS_START( mface1v2 ) PORT_INCLUDE( mface ) PORT_START("CONFIG") - PORT_CONFNAME(0x01, 0x00, "Joystick Enable Jumper") + PORT_CONFNAME(0x02, 0x00, "Joystick Enable Jumper") PORT_CONFSETTING(0x00, "Closed") - PORT_CONFSETTING(0x01, "Open") - PORT_BIT(0xfe, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_CONFSETTING(0x02, "Open") + PORT_BIT(0xfd, IP_ACTIVE_LOW, IPT_UNUSED) PORT_START("JOY") PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT) PORT_8WAY @@ -120,6 +162,16 @@ INPUT_PORTS_START( mface1 ) PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_BUTTON1) INPUT_PORTS_END +INPUT_PORTS_START( mface1 ) + PORT_INCLUDE( mface1v2 ) + + PORT_MODIFY("CONFIG") + PORT_CONFNAME(0x01, 0x00, "Interface Enable Switch") + PORT_CONFSETTING(0x00, "Enabled") + PORT_CONFSETTING(0x01, "Disabled") + PORT_BIT(0xfc, IP_ACTIVE_LOW, IPT_UNUSED) +INPUT_PORTS_END + //------------------------------------------------- // input_ports - device-specific input ports //------------------------------------------------- @@ -129,6 +181,11 @@ ioport_constructor spectrum_mface_base_device::device_input_ports() const return INPUT_PORTS_NAME(mface); } +ioport_constructor spectrum_mface1v2_device::device_input_ports() const +{ + return INPUT_PORTS_NAME(mface1v2); +} + ioport_constructor spectrum_mface1_device::device_input_ports() const { return INPUT_PORTS_NAME(mface1); @@ -138,57 +195,75 @@ ioport_constructor spectrum_mface1_device::device_input_ports() const // ROM( mface ) //------------------------------------------------- -ROM_START(mface1) +ROM_START(mface1v1) // pcb rev 1.2 ROM_REGION(0x2000, "rom", 0) - ROM_DEFAULT_BIOS("mu21e7") - ROM_SYSTEM_BIOS(0, "mu12cb", "MU12 CB") // Very early version, 2KB RAM, page out port 0x5F + ROM_DEFAULT_BIOS("mu12cb") + ROM_SYSTEM_BIOS(0, "mu12cb", "MU12 CB") // 2KB RAM, no pokes or toolkit, page out port 0x5f ROMX_LOAD("mf1_12_cb.rom", 0x0000, 0x2000, CRC(c88fbf9f) SHA1(c3018d1b495b8bc0a135038db0987de7091c9d4c), ROM_BIOS(0)) - ROM_SYSTEM_BIOS(1, "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(1)) - ROM_SYSTEM_BIOS(2, "mu20fe", "MU 2.0 FE") // pokes only (no toolkit) - ROMX_LOAD("mf1_20_fe.rom", 0x0000, 0x2000, CRC(fa1b8b0d) SHA1(20cd508b0143166558a7238c7a9ccfbe37b90b0d), ROM_BIOS(2)) - ROM_SYSTEM_BIOS(3, "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(3)) - ROM_SYSTEM_BIOS(4, "mu21e4", "MU 2.1 E4") // the most common version - ROMX_LOAD("mf1_21_e4.rom", 0x0000, 0x2000, CRC(4b31a971) SHA1(ba28754a3cc31a4ca579829ed4310c313409cf5d), ROM_BIOS(4)) - ROM_SYSTEM_BIOS(5, "mu21e7", "MU 2.1 E7") // last known version? - ROMX_LOAD("mf1_21_e7.rom", 0x0000, 0x2000, CRC(670f0ec2) SHA1(50fba2d628f3a2e9219f72980e4efd62fc9ec1f8), ROM_BIOS(5)) - ROM_SYSTEM_BIOS(6, "bc96", "Brazilian clone 96") // Brazilian clone, unknown pcb version - ROMX_LOAD("mf1_bc_96.rom", 0x0000, 0x2000, CRC(e6fe4507) SHA1(a7e03e7fee3aa05ce1501072aab4534ea7bae257), ROM_BIOS(6)) ROM_END -/* Todo ... - - 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(?, "bc93", "Brazilian clone 93") // NO DUMP? - ROMX_LOAD("mf1_bc_93.rom", 0x0000, 0x2000, CRC(8c17113b) SHA1(?), ROM_BIOS(?)) -*/ - -ROM_START(mface128) +ROM_START(mface1v2) // unknown pcb rev (probably <2.0) ROM_REGION(0x2000, "rom", 0) - ROM_DEFAULT_BIOS("v363c") + ROM_DEFAULT_BIOS("muxx23") + ROM_SYSTEM_BIOS(0, "muxx23", "MU x.x 23") // 8KB RAM, pokes only (no toolkit), page out port 0x5f + ROMX_LOAD("mf1_xx_23.rom", 0x0000, 0x2000, CRC(d4ae8953) SHA1(b442eb634a72fb63f1ccbbd0021a7a581152888d), ROM_BIOS(0)) +ROM_END + +ROM_START(mface1v3) // pcb rev 2.0 + ROM_REGION(0x2000, "rom", 0) + ROM_DEFAULT_BIOS("mu20fe") + 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, "mu2090", "MU 2.0, 90") // alt, unknown if earlier or later, no dump + // ROMX_LOAD("mf1_20_90.rom", 0x0000, 0x2000, CRC(2eaf8e41) SHA1(?), ROM_BIOS(1)) +ROM_END + +ROM_START(mface1) // pcb rev 2.1 + ROM_REGION(0x2000, "rom", 0) + ROM_DEFAULT_BIOS("mu21e4") + ROM_SYSTEM_BIOS(0, "mu21e4", "MU 2.1 E4") // most common version + ROMX_LOAD("mf1_21_e4.rom", 0x0000, 0x2000, CRC(4b31a971) SHA1(ba28754a3cc31a4ca579829ed4310c313409cf5d), ROM_BIOS(0)) + ROM_SYSTEM_BIOS(1, "mu21e7", "MU 2.1 E7") // alt, unknown if earlier or later, glitchy with Betaplus + ROMX_LOAD("mf1_21_e7.rom", 0x0000, 0x2000, CRC(670f0ec2) SHA1(50fba2d628f3a2e9219f72980e4efd62fc9ec1f8), ROM_BIOS(1)) + ROM_SYSTEM_BIOS(2, "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(2)) + ROM_SYSTEM_BIOS(3, "bc96", "Brazilian clone 96") // Brazilian clone, unknown pcb version + ROMX_LOAD("mf1_bc_96.rom", 0x0000, 0x2000, CRC(e6fe4507) SHA1(a7e03e7fee3aa05ce1501072aab4534ea7bae257), ROM_BIOS(3)) + // ROM_SYSTEM_BIOS(4, "bc93", "Brazilian clone 93") // another Brazilian clone, unknown pcb version, no dump + // ROMX_LOAD("mf1_bc_93.rom", 0x0000, 0x2000, CRC(8c17113b) SHA1(?), ROM_BIOS(4)) +ROM_END + +ROM_START(mface128v1) + ROM_REGION(0x2000, "rom", 0) + ROM_DEFAULT_BIOS("v350f") ROM_SYSTEM_BIOS(0, "v340d", "87.1 V34 0D") ROMX_LOAD("mf128_34_0d.rom", 0x0000, 0x2000, CRC(8d8cfd39) SHA1(2104962bb6097e58fcab63969bbaca424a872bb5), ROM_BIOS(0)) - ROM_SYSTEM_BIOS(1, "v350d", "87.12 V35 0F") + ROM_SYSTEM_BIOS(1, "v350f", "87.12 V35 0F") ROMX_LOAD("mf128_35_0f.rom", 0x0000, 0x2000, CRC(cfefd560) SHA1(6cd6fd2c0fbb40a989a568db9d08ba8eed49cbbd), ROM_BIOS(1)) - ROM_SYSTEM_BIOS(2, "vxx0f", "87.2 Vxx 1D") // unknown PCB version - ROMX_LOAD("mf128_xx_1d.rom", 0x0000, 0x2000, CRC(f473991e) SHA1(f03f4ecbcf4a654f4775d16bda0d4cc47f884379), ROM_BIOS(2)) - ROM_SYSTEM_BIOS(3, "v363c", "87.2 V36 3C") - ROMX_LOAD("mf128_36_3c.rom", 0x0000, 0x2000, CRC(78ec8cfd) SHA1(8df204ab490b87c389971ce0c7fb5f9cbd281f14), ROM_BIOS(3)) +ROM_END + +ROM_START(mface128) // DISCiPLE/+D compatible version + ROM_REGION(0x2000, "rom", 0) + ROM_DEFAULT_BIOS("v363c") + ROM_SYSTEM_BIOS(0, "vxx1d", "87.2 Vxx 1D") // unknown PCB version + ROMX_LOAD("mf128_xx_1d.rom", 0x0000, 0x2000, CRC(f473991e) SHA1(f03f4ecbcf4a654f4775d16bda0d4cc47f884379), ROM_BIOS(0)) + ROM_SYSTEM_BIOS(1, "v363c", "87.2 V36 3C") + ROMX_LOAD("mf128_36_3c.rom", 0x0000, 0x2000, CRC(78ec8cfd) SHA1(8df204ab490b87c389971ce0c7fb5f9cbd281f14), ROM_BIOS(1)) ROM_END ROM_START(mface3) ROM_REGION(0x2000, "rom", 0) - ROM_DEFAULT_BIOS("v50fe") - ROM_SYSTEM_BIOS(0, "v5013", "V50 13") - ROMX_LOAD("mf3_50_13.rom", 0x0000, 0x2000, CRC(2d594640) SHA1(5d74d2e2e5a537639da92ff120f8a6d86f474495), ROM_BIOS(0)) - ROM_SYSTEM_BIOS(1, "v50fe", "V50 FE") - ROMX_LOAD("mf3_50_fe.rom", 0x0000, 0x2000, CRC(b5c00f28) SHA1(983699a07665186f498f5827f9b35c442c2178ba), ROM_BIOS(1)) - ROM_SYSTEM_BIOS(2, "vxx9a", "Hard Micro Multiface 3 clone Vxx 9a") + ROM_DEFAULT_BIOS("v5013") + ROM_SYSTEM_BIOS(0, "v50fe", "3.9 V50 FE") // doesn't have "lock 48K" option in save menu + ROMX_LOAD("mf3_50_fe.rom", 0x0000, 0x2000, CRC(b5c00f28) SHA1(983699a07665186f498f5827f9b35c442c2178ba), ROM_BIOS(0)) + ROM_SYSTEM_BIOS(1, "v5013", "3.c V50 13") + ROMX_LOAD("mf3_50_13.rom", 0x0000, 0x2000, CRC(2d594640) SHA1(5d74d2e2e5a537639da92ff120f8a6d86f474495), ROM_BIOS(1)) + ROM_SYSTEM_BIOS(2, "vxx9a", "Hard Micro Multiface 3 clone Vxx 9A") ROMX_LOAD("mf3_hm_9a.rom", 0x0000, 0x2000, CRC(2ce53095) SHA1(5fa286f1552f26575a14ab32125d59c26ce95978), ROM_BIOS(2)) ROM_IGNORE(0x2000) // ROM is 16K, but contains two identical 8K halves + + ROM_REGION( 0x200, "plds", 0 ) // pal from Hard Micro clone, probably the same for all + ROM_LOAD( "mf3_pal16l8a.icx", 0x000, 0x104, CRC(710186a1) SHA1(6573c2b8f55f66ef71ce3992f654080141e09739) ) ROM_END ROM_START(mprint) @@ -210,6 +285,39 @@ void spectrum_mface_base_device::device_add_mconfig(machine_config &config) SPECTRUM_EXPANSION_SLOT(config, m_exp, spectrum_expansion_devices, nullptr); m_exp->irq_handler().set(DEVICE_SELF_OWNER, FUNC(spectrum_expansion_slot_device::irq_w)); m_exp->nmi_handler().set(DEVICE_SELF_OWNER, FUNC(spectrum_expansion_slot_device::nmi_w)); + m_exp->fb_r_handler().set(DEVICE_SELF_OWNER, FUNC(spectrum_expansion_slot_device::fb_r)); +} + +void spectrum_mface3_device::device_add_mconfig(machine_config &config) +{ + spectrum_mface_base_device::device_add_mconfig(config); + + /* passthru (+3 compatible devices only) */ + SPECTRUM_EXPANSION_SLOT(config.replace(), m_exp, specpls3_expansion_devices, nullptr); +} + +void spectrum_mprint_device::device_add_mconfig(machine_config &config) +{ + spectrum_mface_base_device::device_add_mconfig(config); + + /* printer port */ + CENTRONICS(config, m_centronics, centronics_devices, "printer"); + m_centronics->busy_handler().set(FUNC(spectrum_mprint_device::busy_w)); +} + +const tiny_rom_entry *spectrum_mface1v1_device::device_rom_region() const +{ + return ROM_NAME(mface1v1); +} + +const tiny_rom_entry *spectrum_mface1v2_device::device_rom_region() const +{ + return ROM_NAME(mface1v2); +} + +const tiny_rom_entry *spectrum_mface1v3_device::device_rom_region() const +{ + return ROM_NAME(mface1v3); } const tiny_rom_entry *spectrum_mface1_device::device_rom_region() const @@ -217,6 +325,11 @@ const tiny_rom_entry *spectrum_mface1_device::device_rom_region() const return ROM_NAME(mface1); } +const tiny_rom_entry *spectrum_mface128v1_device::device_rom_region() const +{ + return ROM_NAME(mface128v1); +} + const tiny_rom_entry *spectrum_mface128_device::device_rom_region() const { return ROM_NAME(mface128); @@ -249,25 +362,66 @@ spectrum_mface_base_device::spectrum_mface_base_device(const machine_config &mco { } -spectrum_mface1_device::spectrum_mface1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : spectrum_mface_base_device(mconfig, SPECTRUM_MFACE1, tag, owner, clock) +spectrum_mface1v2_device::spectrum_mface1v2_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) + : spectrum_mface_base_device(mconfig, type, tag, owner, clock) , m_joy(*this, "JOY") , m_hwconfig(*this, "CONFIG") { } +spectrum_mface1v2_device::spectrum_mface1v2_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : spectrum_mface1v2_device(mconfig, SPECTRUM_MFACE1V2, tag, owner, clock) +{ +} + +spectrum_mface1v1_device::spectrum_mface1v1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : spectrum_mface1v2_device(mconfig, SPECTRUM_MFACE1V1, tag, owner, clock) +{ +} + +spectrum_mface1v3_device::spectrum_mface1v3_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) + : spectrum_mface1v2_device(mconfig, type, tag, owner, clock) +{ +} + +spectrum_mface1v3_device::spectrum_mface1v3_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : spectrum_mface1v3_device(mconfig, SPECTRUM_MFACE1V3, tag, owner, clock) +{ +} + +spectrum_mface1_device::spectrum_mface1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : spectrum_mface1v3_device(mconfig, SPECTRUM_MFACE1, tag, owner, clock) +{ +} + +spectrum_mface128_base_device::spectrum_mface128_base_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) + : spectrum_mface_base_device(mconfig, type, tag, owner, clock) +{ +} + +spectrum_mface128v1_device::spectrum_mface128v1_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) + : spectrum_mface128_base_device(mconfig, type, tag, owner, clock) +{ +} + +spectrum_mface128v1_device::spectrum_mface128v1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : spectrum_mface128v1_device(mconfig, SPECTRUM_MFACE128V1, tag, owner, clock) +{ +} + spectrum_mface128_device::spectrum_mface128_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : spectrum_mface_base_device(mconfig, SPECTRUM_MFACE128, tag, owner, clock) + : spectrum_mface128v1_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_mface_base_device(mconfig, SPECTRUM_MFACE3, tag, owner, clock) + : spectrum_mface128_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_mface_base_device(mconfig, SPECTRUM_MPRINT, tag, owner, clock) + : spectrum_mface128_base_device(mconfig, SPECTRUM_MPRINT, tag, owner, clock) + , m_centronics(*this, "centronics") { } @@ -278,6 +432,48 @@ spectrum_mprint_device::spectrum_mprint_device(const machine_config &mconfig, co void spectrum_mface_base_device::device_start() { save_item(NAME(m_romcs)); + save_item(NAME(m_nmi_pending)); +} + +void spectrum_mface1v2_device::device_start() +{ + m_ram = std::make_unique(8 * 1024); + save_pointer(NAME(m_ram), 8 * 1024); + spectrum_mface_base_device::device_start(); +} + +void spectrum_mface1v1_device::device_start() +{ + m_ram = std::make_unique(2 * 1024); + save_pointer(NAME(m_ram), 2 * 1024); + spectrum_mface_base_device::device_start(); +} + +void spectrum_mface128_base_device::device_start() +{ + m_ram = std::make_unique(8 * 1024); + save_pointer(NAME(m_ram), 8 * 1024); + save_item(NAME(m_hidden)); + spectrum_mface_base_device::device_start(); +} + +void spectrum_mface128v1_device::device_start() +{ + spectrum_mface128_base_device::device_start(); + save_item(NAME(m_d3_ff)); +} + +void spectrum_mface3_device::device_start() +{ + spectrum_mface128_base_device::device_start(); + save_item(NAME(m_disable)); +} + +void spectrum_mprint_device::device_start() +{ + spectrum_mface128_base_device::device_start(); + m_busy = 0; + save_item(NAME(m_busy)); } //------------------------------------------------- @@ -287,6 +483,25 @@ void spectrum_mface_base_device::device_start() void spectrum_mface_base_device::device_reset() { m_romcs = 0; + m_nmi_pending = 0; +} + +void spectrum_mface128_base_device::device_reset() +{ + spectrum_mface_base_device::device_reset(); + m_hidden = 1; +} + +void spectrum_mface3_device::device_reset() +{ + spectrum_mface128_base_device::device_reset(); + m_disable = 0; +} + +void spectrum_mprint_device::device_reset() +{ + spectrum_mface128_base_device::device_reset(); + m_centronics->write_strobe(1); } @@ -305,25 +520,100 @@ void spectrum_mface_base_device::pre_opcode_fetch(offs_t offset) if (!machine().side_effects_disabled()) { - if (offset == 0x0066) + if (offset == 0x0066 && m_nmi_pending) m_romcs = 1; } } +void spectrum_mface128_device::pre_opcode_fetch(offs_t offset) +{ + // pass-thru pin a15 is controlled by some extra logic on v2 pcb + m_exp->pre_opcode_fetch((m_nmi_pending || m_romcs) ? offset | 0x8000 : offset); + + if (!machine().side_effects_disabled()) + { + if (offset == 0x0066 && m_nmi_pending) + m_romcs = 1; + } +} + +void spectrum_mprint_device::pre_opcode_fetch(offs_t offset) +{ + m_exp->pre_opcode_fetch(offset); + + if (!machine().side_effects_disabled()) + { + if (offset == 0x0066 && m_nmi_pending) + m_romcs = 1; + + // todo: must be some other hooks here... + // at least LPRINT, LLIST and COPY should be caught + // also unique REM xx commands + // menu should pop up for LPRINT and REM MP + } +} + +uint8_t spectrum_mface1v2_device::iorq_r(offs_t offset) +{ + uint8_t data = m_exp->iorq_r(offset); + + if (!machine().side_effects_disabled()) + { + switch (offset & 0xff) // real decodes tbc... + { + case 0x1f: + if (!(m_hwconfig->read() & 0x02)) + data = m_joy->read() & 0x1f; + break; + case 0x5f: + m_romcs = 0; + break; + case 0x9f: + m_romcs = 1; + break; + } + } + return data; +} + +uint8_t spectrum_mface1v3_device::iorq_r(offs_t offset) +{ + uint8_t data = m_exp->iorq_r(offset); + + if (!machine().side_effects_disabled()) + { + switch (offset & 0xff) // real decodes tbc... + { + case 0x1f: + m_romcs = 0; + if (!(m_hwconfig->read() & 0x02)) + data = m_joy->read() & 0x1f; + break; + case 0x9f: + m_romcs = 1; + break; + } + } + return data; +} + uint8_t spectrum_mface1_device::iorq_r(offs_t offset) { uint8_t data = m_exp->iorq_r(offset); + if (m_hwconfig->read() & 0x01) // disable switch + return data; + if (!machine().side_effects_disabled()) { - switch (offset & 0xff) + switch (offset & 0xf2) // -001 --1- { - case 0x1f: + case 0x12: // 0001 --1- uses 0x1f m_romcs = 0; - if (!(m_hwconfig->read() & 0x01)) // joystick disable jumper + if (!(m_hwconfig->read() & 0x02)) data = m_joy->read() & 0x1f; break; - case 0x9f: + case 0x92: // 1001 --1- uses 0x9f m_romcs = 1; break; } @@ -331,20 +621,47 @@ uint8_t spectrum_mface1_device::iorq_r(offs_t offset) return data; } +uint8_t spectrum_mface128v1_device::iorq_r(offs_t offset) +{ + uint8_t data = m_exp->iorq_r(offset); + + if (!machine().side_effects_disabled()) + { + switch (offset & 0xf0) // -001 ---- + { + case 0x10: // 0001 ---- uses 0x1f + m_romcs = 0; + break; + case 0x90: // 1001 ---- uses 0x9f + if (!m_hidden) + { + m_romcs = 1; + data = (data & 0x7f) | (m_d3_ff << 7); + } + break; + } + } + return data; +} + uint8_t spectrum_mface128_device::iorq_r(offs_t offset) { uint8_t data = m_exp->iorq_r(offset); if (!machine().side_effects_disabled()) { - switch (offset & 0xff) + switch (offset & 0xf4) // -011 -1-- { - case 0xbf: - m_romcs = 1; - break; - case 0x3f: + case 0x34: // 0011 -1-- uses 0x3f m_romcs = 0; break; + case 0xb4: // 1011 -1-- uses 0xbf + if (!m_hidden) + { + m_romcs = 1; + data = (data & 0x7f) | (m_d3_ff << 7); + } + break; } } return data; @@ -356,16 +673,26 @@ uint8_t spectrum_mface3_device::iorq_r(offs_t offset) if (!machine().side_effects_disabled()) { - switch (offset & 0xff) + switch (offset & 0xff) // fully decoded by PAL16L8 { case 0x3f: - m_romcs = 1; + if (!m_hidden) + m_romcs = 1; break; case 0xbf: m_romcs = 0; break; } } + + // mface3 monitors writes to the +3 memory ctrl registers (ports 1ffd, 7ffd) + // keeps copies of the low nibbles in a 74LS670 4x4 register file + if ((offset & 0x7f) == 0x3f && !m_hidden) + { + data = 0xf0; // get stored copy of 1ffd, 7ffd + data |= m_reg_file[(offset >> 13) & 3] & 0xf; + } + return data; } @@ -375,25 +702,141 @@ uint8_t spectrum_mprint_device::iorq_r(offs_t offset) if (!machine().side_effects_disabled()) { - switch (offset & 0xff) + switch (offset & 0xff) // real decodes tbc... { - case 0xbb: - m_romcs = 1; - break; case 0xbf: m_romcs = 0; break; + case 0xbb: + if (!m_hidden) + m_romcs = 1; + data &= ~0x40; + data |= m_busy << 6; + break; } } return data; } +void spectrum_mface1v2_device::iorq_w(offs_t offset, uint8_t data) +{ + if ((offset & 0xff) == 0x5f) // real decodes tbc... + nmi(CLEAR_LINE); + + m_exp->iorq_w(offset, data); +} + +void spectrum_mface1v3_device::iorq_w(offs_t offset, uint8_t data) +{ + if ((offset & 0xff) == 0x1f) // real decodes tbc... + nmi(CLEAR_LINE); + + m_exp->iorq_w(offset, data); +} + void spectrum_mface1_device::iorq_w(offs_t offset, uint8_t data) { - switch (offset & 0xff) + if ((offset & 0xf2) == 0x12) // 0001 --1- uses 0x1f + nmi(CLEAR_LINE); + + m_exp->iorq_w(offset, data); +} + +void spectrum_mface128v1_device::iorq_w(offs_t offset, uint8_t data) +{ + switch (offset & 0xf0) // -001 ---- { - case 0x1f: - m_slot->nmi_w(CLEAR_LINE); + case 0x10: // 0001 ---- uses 0x1f + m_hidden = 1; + [[fallthrough]]; + case 0x90: // 1001 ---- uses 0x9f + nmi(CLEAR_LINE); + break; + } + + // mface128 monitors writes to the 128K memory ctrl register (port 7ffd) + // keeps a copy of D3 (screen select bit) in a D flip-flop + if ((offset & 0x8002) == 0) // 0--- ---- ---- --0- uses 7ffd + m_d3_ff = (data >> 3) & 1; + + m_exp->iorq_w(offset, data); +} + +void spectrum_mface128_device::iorq_w(offs_t offset, uint8_t data) +{ + switch (offset & 0xf4) // -011 -1-- + { + case 0x34: // 0011 -1-- uses 0x3f + m_hidden = 1; + [[fallthrough]]; + case 0xb4: // 1011 -1-- uses 0xbf + nmi(CLEAR_LINE); + break; + } + + // mface128 monitors writes to the 128K memory ctrl register (port 7ffd) + // keeps a copy of D3 (screen select bit) in a D flip-flop + if ((offset & 0x8002) == 0) // 0--- ---- ---- --0- uses 7ffd + m_d3_ff = (data >> 3) & 1; + + m_exp->iorq_w(offset, data); +} + +void spectrum_mface3_device::iorq_w(offs_t offset, uint8_t data) +{ + switch (offset & 0xff) // fully decoded by PAL16L8 + { + case 0x3f: + m_hidden = 1; // also Hard Micro clone: D0 is 16KB rom msb (unused) + [[fallthrough]]; + case 0xbf: + nmi(CLEAR_LINE); + break; + } + + // mface3 monitors writes to the +3 memory ctrl registers (ports 1ffd, 7ffd) + // keeps copies of the low nibbles in a 74LS670 4x4 register file + if ((offset & 0x90fd) == 0x10fd) + m_reg_file[(offset >> 13) & 3] = data & 0x0f; + + // also disables itself if special paging mode bit is set (CP/M) + if ((offset & 0xf0fd) == 0x10fd) + m_disable = data & 1; + + m_exp->iorq_w(offset, data); +} + +void spectrum_mprint_device::iorq_w(offs_t offset, uint8_t data) +{ + // write_strobe is fired by wr seq: 0xbf, 0xbb, 0xbf + switch (offset & 0xff) // real decodes tbc... + { + case 0xbf: + m_centronics->write_data0(BIT(data, 0)); + m_centronics->write_data1(BIT(data, 1)); + m_centronics->write_data2(BIT(data, 2)); + m_centronics->write_data3(BIT(data, 3)); + m_centronics->write_data4(BIT(data, 4)); + m_centronics->write_data5(BIT(data, 5)); + m_centronics->write_data6(BIT(data, 6)); + m_centronics->write_data7(BIT(data, 7)); + m_centronics->write_strobe(1); + break; + case 0xbb: + m_centronics->write_strobe(0); + break; + } + + switch (offset & 0x5ff) + { + case 0x4bf: + nmi(CLEAR_LINE); + break; + case 0x4fb: // not essential yet, for other hooks? + m_hidden = 0; + break; + case 0x5fb: + m_hidden = 1; break; } @@ -423,6 +866,29 @@ uint8_t spectrum_mface_base_device::mreq_r(offs_t offset) return data; } +uint8_t spectrum_mface1v1_device::mreq_r(offs_t offset) +{ + uint8_t data = 0xff; + + if (m_romcs) + { + switch (offset & 0xe000) + { + case 0x0000: + data = m_rom->base()[offset & 0x1fff]; + break; + case 0x2000: + data = m_ram[offset & 0x7ff]; + break; + } + } + + if (m_exp->romcs()) + data &= m_exp->mreq_r(offset); + + return data; +} + void spectrum_mface_base_device::mreq_w(offs_t offset, uint8_t data) { if (m_romcs) @@ -439,26 +905,58 @@ void spectrum_mface_base_device::mreq_w(offs_t offset, uint8_t data) m_exp->mreq_w(offset, data); } -INPUT_CHANGED_MEMBER(spectrum_mface_base_device::magic_button) +void spectrum_mface1v1_device::mreq_w(offs_t offset, uint8_t data) { - if (newval && !oldval) + if (m_romcs) { - m_slot->nmi_w(ASSERT_LINE); + switch (offset & 0xe000) + { + case 0x2000: + m_ram[offset & 0x7ff] = data; + break; + } } - else + + if (m_exp->romcs()) + m_exp->mreq_w(offset, data); +} + +INPUT_CHANGED_MEMBER(spectrum_mface1v2_device::magic_button) +{ + if (!newval) { - m_slot->nmi_w(CLEAR_LINE); + nmi(ASSERT_LINE); } } INPUT_CHANGED_MEMBER(spectrum_mface1_device::magic_button) { - if (newval && !oldval) // key released + if (!newval) { - - } - else // key pressed - { - m_slot->nmi_w(ASSERT_LINE); + if (!(m_hwconfig->read() & 0x01)) + { + nmi(ASSERT_LINE); + } + } +} + +INPUT_CHANGED_MEMBER(spectrum_mface128_base_device::magic_button) +{ + if (!newval) + { + m_hidden = 0; + nmi(ASSERT_LINE); + } +} + +INPUT_CHANGED_MEMBER(spectrum_mface3_device::magic_button) +{ + if (!newval) + { + if (!m_disable) + { + m_hidden = 0; + nmi(ASSERT_LINE); + } } } diff --git a/src/devices/bus/spectrum/mface.h b/src/devices/bus/spectrum/mface.h index abf1202cc0d..781201295c8 100644 --- a/src/devices/bus/spectrum/mface.h +++ b/src/devices/bus/spectrum/mface.h @@ -9,7 +9,7 @@ #define MAME_BUS_SPECTRUM_MFACE_H #include "exp.h" - +#include "bus/centronics/ctronics.h" //************************************************************************** // TYPE DEFINITIONS @@ -18,13 +18,12 @@ class spectrum_mface_base_device : public device_t, public device_spectrum_expansion_interface - { public: // construction/destruction spectrum_mface_base_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); - virtual DECLARE_INPUT_CHANGED_MEMBER(magic_button); + virtual DECLARE_INPUT_CHANGED_MEMBER(magic_button) { m_slot->nmi_w(newval ? CLEAR_LINE : ASSERT_LINE); }; protected: spectrum_mface_base_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); @@ -49,14 +48,72 @@ protected: virtual uint8_t iorq_r(offs_t offset) override { return m_exp->iorq_r(offset); } virtual void iorq_w(offs_t offset, uint8_t data) override { m_exp->iorq_w(offset, data); } + void nmi(line_state state) { m_slot->nmi_w(state); m_nmi_pending = state; }; + required_memory_region m_rom; required_device m_exp; - uint8_t m_ram[8 * 1024]; int m_romcs; + int m_nmi_pending; + std::unique_ptr m_ram; }; -class spectrum_mface1_device : public spectrum_mface_base_device +class spectrum_mface1v2_device : public spectrum_mface_base_device +{ +public: + spectrum_mface1v2_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + DECLARE_INPUT_CHANGED_MEMBER(magic_button) override; + +protected: + spectrum_mface1v2_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; + + // 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; + + required_ioport m_joy; + required_ioport m_hwconfig; +}; + +class spectrum_mface1v1_device : public spectrum_mface1v2_device +{ +public: + spectrum_mface1v1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + +protected: + // device-level overrides + virtual void device_start() override; + + // optional information overrides + virtual const tiny_rom_entry *device_rom_region() const override; + + virtual uint8_t mreq_r(offs_t offset) override; + virtual void mreq_w(offs_t offset, uint8_t data) override; +}; + +class spectrum_mface1v3_device : public spectrum_mface1v2_device +{ +public: + spectrum_mface1v3_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + +protected: + spectrum_mface1v3_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); + + // optional information overrides + virtual const tiny_rom_entry *device_rom_region() const override; + + virtual uint8_t iorq_r(offs_t offset) override; + virtual void iorq_w(offs_t offset, uint8_t data) override; +}; + +class spectrum_mface1_device : public spectrum_mface1v3_device { public: spectrum_mface1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); @@ -70,13 +127,46 @@ protected: 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 +class spectrum_mface128_base_device : public spectrum_mface_base_device +{ +public: + spectrum_mface128_base_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + DECLARE_INPUT_CHANGED_MEMBER(magic_button) override; + +protected: + spectrum_mface128_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; + virtual void device_reset() override; + + int m_hidden; +}; + +class spectrum_mface128v1_device : public spectrum_mface128_base_device +{ +public: + spectrum_mface128v1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + +protected: + spectrum_mface128v1_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; + + // optional information overrides + virtual const tiny_rom_entry *device_rom_region() const override; + + virtual uint8_t iorq_r(offs_t offset) override; + virtual void iorq_w(offs_t offset, uint8_t data) override; + + int m_d3_ff; // no initial state +}; + +class spectrum_mface128_device : public spectrum_mface128v1_device { public: spectrum_mface128_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); @@ -85,36 +175,68 @@ protected: // optional information overrides virtual const tiny_rom_entry *device_rom_region() const override; + virtual void pre_opcode_fetch(offs_t offset) override; virtual uint8_t iorq_r(offs_t offset) override; + virtual void iorq_w(offs_t offset, uint8_t data) override; }; -class spectrum_mface3_device : public spectrum_mface_base_device +class spectrum_mface3_device : public spectrum_mface128_base_device { public: spectrum_mface3_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + DECLARE_INPUT_CHANGED_MEMBER(magic_button) override; + protected: + // device-level overrides + virtual void device_start() override; + virtual void device_reset() override; + // optional information overrides + virtual void device_add_mconfig(machine_config &config) override; virtual const tiny_rom_entry *device_rom_region() const override; virtual uint8_t iorq_r(offs_t offset) override; + virtual void iorq_w(offs_t offset, uint8_t data) override; + +private: + uint8_t m_reg_file[4]; // no initial state + int m_disable; }; -class spectrum_mprint_device : public spectrum_mface_base_device +class spectrum_mprint_device : public spectrum_mface128_base_device { public: spectrum_mprint_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); protected: + // device-level overrides + virtual void device_start() override; + virtual void device_reset() override; + // optional information overrides + virtual void device_add_mconfig(machine_config &config) override; virtual const tiny_rom_entry *device_rom_region() const override; + virtual void pre_opcode_fetch(offs_t offset) override; virtual uint8_t iorq_r(offs_t offset) override; + virtual void iorq_w(offs_t offset, uint8_t data) override; + +private: + DECLARE_WRITE_LINE_MEMBER(busy_w) { m_busy = state; }; + + required_device m_centronics; + + int m_busy; }; // device type definition +DECLARE_DEVICE_TYPE(SPECTRUM_MFACE1V1, spectrum_mface1v1_device) +DECLARE_DEVICE_TYPE(SPECTRUM_MFACE1V2, spectrum_mface1v2_device) +DECLARE_DEVICE_TYPE(SPECTRUM_MFACE1V3, spectrum_mface1v3_device) DECLARE_DEVICE_TYPE(SPECTRUM_MFACE1, spectrum_mface1_device) +DECLARE_DEVICE_TYPE(SPECTRUM_MFACE128V1, spectrum_mface128v1_device) DECLARE_DEVICE_TYPE(SPECTRUM_MFACE128, spectrum_mface128_device) DECLARE_DEVICE_TYPE(SPECTRUM_MFACE3, spectrum_mface3_device) DECLARE_DEVICE_TYPE(SPECTRUM_MPRINT, spectrum_mprint_device) diff --git a/src/devices/bus/spectrum/mgt.cpp b/src/devices/bus/spectrum/mgt.cpp index f1396cdeb7c..62f36c7a315 100644 --- a/src/devices/bus/spectrum/mgt.cpp +++ b/src/devices/bus/spectrum/mgt.cpp @@ -113,7 +113,7 @@ the PAL is a 16L6 rather than a 20L8 used in later version (only known dump is bruteforced and converted to gal20v8 target.) details here: https://web.archive.org/web/20171118171054/http://trastero.speccy.org/cosas/JL/PlusD/PlusD-v1-0.html - from "pick-poke-it" user manual (reguarding v1.0 unit): + from "pick-poke-it" user manual (regarding v1.0 unit): "A few PLUS D users are still using Version 1 of the ROM which was used in PLUS D's sold in December 1987-January 1988. ... check the serial number on the bottom of your PLUS D. If it's a 4-figure number commencing with 1, then you have a PLUS D with the Version 1 ROM." @@ -170,7 +170,7 @@ DEFINE_DEVICE_TYPE(SPECTRUM_DISCIPLE, spectrum_disciple_device, "spectrum_discip INPUT_PORTS_START(plusd) PORT_START("BUTTON") - PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_BUTTON1) PORT_NAME("Snapshot Button") PORT_CODE(KEYCODE_BACKSPACE) PORT_CHANGED_MEMBER(DEVICE_SELF, spectrum_plusd_device, snapshot_button, 0) + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_BUTTON1) PORT_NAME("Snapshot Button") PORT_CODE(KEYCODE_MINUS_PAD) PORT_CHANGED_MEMBER(DEVICE_SELF, spectrum_plusd_device, snapshot_button, 0) INPUT_PORTS_END //------------------------------------------------- @@ -308,6 +308,7 @@ void spectrum_disciple_device::device_add_mconfig(machine_config &config) SPECTRUM_EXPANSION_SLOT(config, m_exp, spectrum_expansion_devices, nullptr); m_exp->irq_handler().set(DEVICE_SELF_OWNER, FUNC(spectrum_expansion_slot_device::irq_w)); m_exp->nmi_handler().set(DEVICE_SELF_OWNER, FUNC(spectrum_expansion_slot_device::nmi_w)); + m_exp->fb_r_handler().set(DEVICE_SELF_OWNER, FUNC(spectrum_expansion_slot_device::fb_r)); } const tiny_rom_entry *spectrum_plusd_device::device_rom_region() const @@ -422,7 +423,7 @@ void spectrum_plusd_device::pre_opcode_fetch(offs_t offset) uint8_t spectrum_plusd_device::iorq_r(offs_t offset) { - uint8_t data = 0xff; + uint8_t data = offset & 1 ? m_slot->fb_r() : 0xff; switch (offset & 0x7e) // address lines 0 and 7-15 ignored { diff --git a/src/devices/bus/spectrum/mikroplus.cpp b/src/devices/bus/spectrum/mikroplus.cpp index 04ce942c632..9f46bc1b7db 100644 --- a/src/devices/bus/spectrum/mikroplus.cpp +++ b/src/devices/bus/spectrum/mikroplus.cpp @@ -91,7 +91,7 @@ void spectrum_mikroplus_device::device_start() uint8_t spectrum_mikroplus_device::iorq_r(offs_t offset) { - uint8_t data = 0xff; + uint8_t data = offset & 1 ? m_slot->fb_r() : 0xff; if ((offset & 0xff) == 0xdf) { diff --git a/src/devices/bus/spectrum/mpoker.cpp b/src/devices/bus/spectrum/mpoker.cpp new file mode 100644 index 00000000000..c2d84d13c1b --- /dev/null +++ b/src/devices/bus/spectrum/mpoker.cpp @@ -0,0 +1,168 @@ +// license:BSD-3-Clause +// copyright-holders:TwistedTom +/********************************************************************* + + MICRO-POKEer + + (Micro-Studio, Hungary 1988-1989) + + A back-up/snapshot type device similar to multiface. + Saves full ram or screen to tape (normal or high speed) + Cheat/poke and jump functions. + No pass-through slot. + + Operation: + Press freeze button... + H: on-screen help + space: exit help + enter: return + r: total ram save + R: turbo total ram save + s: screen save + S: turbo screen save + l: turbo screen load + L: turbo total ram load + w: warm reset + m: micro-monitor (poke or jump) + + micro-monitor: + black entry box appears... + move around with q/a/o/p, enter + input address (dec) + to jump: j, enter + to poke: p, input data (dec), enter (repeats) + to quit: q, enter + + normal saves are useable independant of the interface, + "turbo" saves need the interface present, must use l or L options to load. + + Lots of info including schematic and rom disassembly: + https://bitbandit.org/20141231/disassembling-the-micro-pokeer-rom-firmware/ + + +*********************************************************************/ + +#include "emu.h" +#include "mpoker.h" + + +/*************************************************************************** + DEVICE DEFINITIONS +***************************************************************************/ + +DEFINE_DEVICE_TYPE(SPECTRUM_MPOKER, spectrum_mpoker_device, "spectrum_mpoker", "MICRO-POKEer") + + +//------------------------------------------------- +// INPUT_PORTS( mpoker ) +//------------------------------------------------- + +INPUT_PORTS_START( mpoker ) + PORT_START("BUTTON") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_BUTTON1) PORT_NAME("Freeze Button") PORT_CODE(KEYCODE_PLUS_PAD) PORT_CHANGED_MEMBER(DEVICE_SELF, spectrum_mpoker_device, freeze_button, 0) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor spectrum_mpoker_device::device_input_ports() const +{ + return INPUT_PORTS_NAME(mpoker); +} + +//------------------------------------------------- +// ROM( mpoker ) +//------------------------------------------------- + +ROM_START(mpoker) + ROM_REGION(0x2000, "rom", 0) // v1.6 + ROM_LOAD("mpoker.rom", 0x0000, 0x2000, CRC(11927434) SHA1(fd918519e4bd0eb8220d157a1c3f314669764657)) +ROM_END + +//------------------------------------------------- +// device_add_mconfig - add device configuration +//------------------------------------------------- + +const tiny_rom_entry *spectrum_mpoker_device::device_rom_region() const +{ + return ROM_NAME(mpoker); +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// spectrum_mpoker_device - constructor +//------------------------------------------------- + +spectrum_mpoker_device::spectrum_mpoker_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, SPECTRUM_MPOKER, tag, owner, clock) + , device_spectrum_expansion_interface(mconfig, *this) + , m_rom(*this, "rom") +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void spectrum_mpoker_device::device_start() +{ + save_item(NAME(m_romcs)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void spectrum_mpoker_device::device_reset() +{ + m_romcs = 0; +} + + +//************************************************************************** +// IMPLEMENTATION +//************************************************************************** + +READ_LINE_MEMBER(spectrum_mpoker_device::romcs) +{ + return m_romcs; +} + +void spectrum_mpoker_device::iorq_w(offs_t offset, uint8_t data) +{ + if ((offset & 0x80) == 0) // 0--- ---- uses 7f + { + m_romcs = BIT(data, 0); + } +} + +uint8_t spectrum_mpoker_device::mreq_r(offs_t offset) +{ + uint8_t data = 0xff; + + if (m_romcs) + { + data = m_rom->base()[offset & 0x1fff]; + } + + return data; +} + +INPUT_CHANGED_MEMBER(spectrum_mpoker_device::freeze_button) +{ + if (newval) + { + m_slot->nmi_w(CLEAR_LINE); + } + else + { + m_romcs = 1; + m_slot->nmi_w(ASSERT_LINE); + } +} diff --git a/src/devices/bus/spectrum/mpoker.h b/src/devices/bus/spectrum/mpoker.h new file mode 100644 index 00000000000..27f7cef19b0 --- /dev/null +++ b/src/devices/bus/spectrum/mpoker.h @@ -0,0 +1,49 @@ +// license:BSD-3-Clause +// copyright-holders:TwistedTom +/********************************************************************* + + MICRO-POKEer + + (Micro-Studio, Hungary 1988-1989) + +*********************************************************************/ +#ifndef MAME_BUS_SPECTRUM_MPOKER_H +#define MAME_BUS_SPECTRUM_MPOKER_H + +#include "exp.h" + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class spectrum_mpoker_device : public device_t, public device_spectrum_expansion_interface +{ +public: + // construction/destruction + spectrum_mpoker_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + DECLARE_INPUT_CHANGED_MEMBER(freeze_button); + +protected: + // device-level overrides + virtual void device_start() override; + virtual void device_reset() override; + + // optional information overrides + virtual const tiny_rom_entry *device_rom_region() const override; + virtual ioport_constructor device_input_ports() const override; + + virtual uint8_t mreq_r(offs_t offset) override; + virtual void iorq_w(offs_t offset, uint8_t data) override; + virtual DECLARE_READ_LINE_MEMBER(romcs) override; + + required_memory_region m_rom; + + int m_romcs; +}; + +// device type definition +DECLARE_DEVICE_TYPE(SPECTRUM_MPOKER, spectrum_mpoker_device) + +#endif // MAME_BUS_SPECTRUM_MPOKER_H diff --git a/src/devices/bus/spectrum/opus.cpp b/src/devices/bus/spectrum/opus.cpp index 225783ebaf8..37eff23bce6 100644 --- a/src/devices/bus/spectrum/opus.cpp +++ b/src/devices/bus/spectrum/opus.cpp @@ -102,6 +102,7 @@ void spectrum_opus_device::device_add_mconfig(machine_config &config) /* passthru without NMI */ SPECTRUM_EXPANSION_SLOT(config, m_exp, spectrum_expansion_devices, nullptr); m_exp->irq_handler().set(DEVICE_SELF_OWNER, FUNC(spectrum_expansion_slot_device::irq_w)); + m_exp->fb_r_handler().set(DEVICE_SELF_OWNER, FUNC(spectrum_expansion_slot_device::fb_r)); } const tiny_rom_entry *spectrum_opus_device::device_rom_region() const @@ -188,7 +189,7 @@ uint8_t spectrum_opus_device::iorq_r(offs_t offset) // PIA bit 7 is enable joystick and selected on A5 only if (!BIT(m_pia->a_output(), 7) && (~offset & 0x20)) { - data &= m_joy->read() & 0x1f; + data = m_joy->read() & 0x1f; } return data; } diff --git a/src/devices/bus/spectrum/protek.cpp b/src/devices/bus/spectrum/protek.cpp index d1e122d8dbb..6e21268682e 100644 --- a/src/devices/bus/spectrum/protek.cpp +++ b/src/devices/bus/spectrum/protek.cpp @@ -74,7 +74,7 @@ void spectrum_protek_device::device_start() uint8_t spectrum_protek_device::iorq_r(offs_t offset) { - uint8_t data = 0xff; + uint8_t data = offset & 1 ? m_slot->fb_r() : 0xff; switch (offset & 0xff) { diff --git a/src/devices/bus/spectrum/sdi.cpp b/src/devices/bus/spectrum/sdi.cpp index 7137cbaceb3..ab8becb80f8 100644 --- a/src/devices/bus/spectrum/sdi.cpp +++ b/src/devices/bus/spectrum/sdi.cpp @@ -127,7 +127,7 @@ uint8_t spectrum_sdi_device::mreq_r(offs_t offset) uint8_t spectrum_sdi_device::iorq_r(offs_t offset) { - uint8_t data = 0xff; + uint8_t data = offset & 1 ? m_slot->fb_r() : 0xff; if ((offset & 0x9f) == 0x9f) data = m_ppi->read((offset >> 5) & 3); diff --git a/src/devices/bus/spectrum/sixword.cpp b/src/devices/bus/spectrum/sixword.cpp index 943f10a887e..e90ca86c88e 100644 --- a/src/devices/bus/spectrum/sixword.cpp +++ b/src/devices/bus/spectrum/sixword.cpp @@ -163,6 +163,7 @@ void spectrum_swiftdisc_device::device_add_mconfig(machine_config &config) SPECTRUM_EXPANSION_SLOT(config, m_exp, spectrum_expansion_devices, nullptr); m_exp->irq_handler().set(DEVICE_SELF_OWNER, FUNC(spectrum_expansion_slot_device::irq_w)); m_exp->nmi_handler().set(DEVICE_SELF_OWNER, FUNC(spectrum_expansion_slot_device::nmi_w)); + m_exp->fb_r_handler().set(DEVICE_SELF_OWNER, FUNC(spectrum_expansion_slot_device::fb_r)); } void spectrum_swiftdisc2_device::device_add_mconfig(machine_config &config) @@ -376,7 +377,7 @@ uint8_t spectrum_swiftdisc_device::iorq_r(offs_t offset) uint8_t data = m_exp->iorq_r(offset); if (!BIT(offset, 5)) - data &= m_joy->read(); + data = m_joy->read() & 0x1f; return data; } @@ -484,10 +485,10 @@ uint8_t spectrum_swiftdisc2_device::iorq_r(offs_t offset) uint8_t data = m_exp->iorq_r(offset); if (m_romcs && (offset & 0xf890) == 0x3000) - data &= control_r(); + data = control_r(); if (!BIT(offset, 5) && !BIT(m_control, 3)) - data &= m_joy->read(); + data = m_joy->read() & 0x1f; if (m_conf->read()) { @@ -496,14 +497,14 @@ uint8_t spectrum_swiftdisc2_device::iorq_r(offs_t offset) if (!BIT(offset, 3)) // port F7 { // D7 - RS232 /RX - data &= ~(m_rs232->rxd_r() << 7); + data &= ~0x80; + data |= !m_rs232->rxd_r() << 7; } if (!BIT(offset, 4)) // port EF { - data &= ~4; - data |= 0x0b; // D3 - RS232 /DSR - data &= ~(m_rs232->dsr_r() << 3); + data &= ~0x8; + data |= !m_rs232->dsr_r() << 3; } } } @@ -512,7 +513,8 @@ uint8_t spectrum_swiftdisc2_device::iorq_r(offs_t offset) if (!BIT(offset, 3)) // port F7 { // D7 - Centronics /BUSY - data &= ~(m_busy << 7); + data &= ~0x80; + data |= !m_busy << 7; } } diff --git a/src/devices/bus/spectrum/speccydos.cpp b/src/devices/bus/spectrum/speccydos.cpp index 5a8c7851c9a..9df39078ef9 100644 --- a/src/devices/bus/spectrum/speccydos.cpp +++ b/src/devices/bus/spectrum/speccydos.cpp @@ -114,6 +114,7 @@ void spectrum_speccydos_device::device_add_mconfig(machine_config &config) SPECTRUM_EXPANSION_SLOT(config, m_exp, spectrum_expansion_devices, nullptr); m_exp->irq_handler().set(DEVICE_SELF_OWNER, FUNC(spectrum_expansion_slot_device::irq_w)); m_exp->nmi_handler().set(DEVICE_SELF_OWNER, FUNC(spectrum_expansion_slot_device::nmi_w)); + m_exp->fb_r_handler().set(DEVICE_SELF_OWNER, FUNC(spectrum_expansion_slot_device::fb_r)); } const tiny_rom_entry *spectrum_speccydos_device::device_rom_region() const diff --git a/src/devices/bus/spectrum/specmate.cpp b/src/devices/bus/spectrum/specmate.cpp new file mode 100644 index 00000000000..4177a74f814 --- /dev/null +++ b/src/devices/bus/spectrum/specmate.cpp @@ -0,0 +1,190 @@ +// license:BSD-3-Clause +// copyright-holders:TwistedTom +/********************************************************************* + + Spec-Mate back-up interface + + (A, T & Y Computing Ltd.) + + A back-up/snapshot type device similar to multiface. + No on-screen UI, feedback is given by border colour changes. + Supports saving to Beta-disk, Microdrive, Wafadrive, tape (normal & double-speed modes) + + Only one rom is known, although magazine adverts stated: + "Opus users £2 extra, Opus & Sprint users contact us for details", suggesting other roms may exist. + (Sprint was a high-speed tape deck, x4 recording on a standard cassette) + + Operation: + + Press freeze button... + + Black border mode: (select device) + t = save to tape + m = save to microdrive + d = save to Beta disk + w = save to wafadrive + f = save to tape, double-speed mode + 0 = remove attributes *1 + + Red border mode: (save mode) + n = normal save + s = screenless save (game starts with blank screen!) + a = normal save with a 2nd screen (1st part of 2-part operation) *2 + b = normal save with a 2nd screen (2nd part of 2-part operation) *2 + + Blue border mode: (select which part of vram is used as specmate working ram) + 1 = use top 3rd of screen + 2 = use middle 3rd of screen + 3 = use bottom 3rd of screen + + Magenta border mode: (enter filename) + Type a filename, press Enter to save + + System should auto-unfreeze after successful save... + + + Notes: + *1 Removes colour from the frozen screen so that essential data "hidden" in vram can be seen (some games do this as a copy protection), + user can then avoid disturbing this data with choice made in blue-border mode. + *2 Saves a 2nd screen (eg. a nice loading screen) just for fun. 2-part operation, so load game, freeze, save 1st screen, + reset system, re-load game, freeze, save main game and 2nd screen. + * Saves are created with stand-alone loader code so are not dependant on the interface for reuse. + * Pokes can be added to the save loader: press BREAK as soon as the screen goes black, INK 9, POKE aaaaa,ddd + + +*********************************************************************/ + +#include "emu.h" +#include "specmate.h" + + +/*************************************************************************** + DEVICE DEFINITIONS +***************************************************************************/ + +DEFINE_DEVICE_TYPE(SPECTRUM_SPECMATE, spectrum_specmate_device, "spectrum_specmate", "AT&Y Spec-Mate") + + +//------------------------------------------------- +// INPUT_PORTS( specmate ) +//------------------------------------------------- + +INPUT_PORTS_START( specmate ) + PORT_START("BUTTON") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_BUTTON1) PORT_NAME("Freeze Button") PORT_CODE(KEYCODE_PLUS_PAD) PORT_CHANGED_MEMBER(DEVICE_SELF, spectrum_specmate_device, freeze_button, 0) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor spectrum_specmate_device::device_input_ports() const +{ + return INPUT_PORTS_NAME(specmate); +} + +//------------------------------------------------- +// ROM( specmate ) +//------------------------------------------------- + +ROM_START(specmate) + ROM_REGION(0x2000, "rom", 0) // unknown ver + ROM_LOAD("specmate.rom", 0x0000, 0x2000, CRC(8d74b19c) SHA1(c8f128610eeb5142d4d80f28e5dd07b7a5ab6b84)) +ROM_END + +//------------------------------------------------- +// device_add_mconfig - add device configuration +//------------------------------------------------- + +void spectrum_specmate_device::device_add_mconfig(machine_config &config) +{ + /* passthru */ + SPECTRUM_EXPANSION_SLOT(config, m_exp, spectrum_expansion_devices, nullptr); + m_exp->irq_handler().set(DEVICE_SELF_OWNER, FUNC(spectrum_expansion_slot_device::irq_w)); + m_exp->nmi_handler().set(DEVICE_SELF_OWNER, FUNC(spectrum_expansion_slot_device::nmi_w)); + m_exp->fb_r_handler().set(DEVICE_SELF_OWNER, FUNC(spectrum_expansion_slot_device::fb_r)); +} + +const tiny_rom_entry *spectrum_specmate_device::device_rom_region() const +{ + return ROM_NAME(specmate); +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// spectrum_specmate_device - constructor +//------------------------------------------------- + +spectrum_specmate_device::spectrum_specmate_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, SPECTRUM_SPECMATE, tag, owner, clock) + , device_spectrum_expansion_interface(mconfig, *this) + , m_rom(*this, "rom") + , m_exp(*this, "exp") +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void spectrum_specmate_device::device_start() +{ + save_item(NAME(m_romcs)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void spectrum_specmate_device::device_reset() +{ + m_romcs = 0; +} + + +//************************************************************************** +// IMPLEMENTATION +//************************************************************************** + +READ_LINE_MEMBER(spectrum_specmate_device::romcs) +{ + return m_romcs | m_exp->romcs(); +} + +void spectrum_specmate_device::pre_opcode_fetch(offs_t offset) +{ + m_exp->pre_opcode_fetch(offset); + + if (!machine().side_effects_disabled()) + { + switch (offset & 0xdfff) // a13 isn't used in the decoding + { + case 0x0066: + m_romcs = 1; + break; + case 0x0071: + m_romcs = 0; + break; + } + } +} + +uint8_t spectrum_specmate_device::mreq_r(offs_t offset) +{ + uint8_t data = 0xff; + + if (m_romcs) + { + data = m_rom->base()[offset & 0x1fff]; + } + + if (m_exp->romcs()) + data &= m_exp->mreq_r(offset); + + return data; +} diff --git a/src/devices/bus/spectrum/specmate.h b/src/devices/bus/spectrum/specmate.h new file mode 100644 index 00000000000..2bb43f925b3 --- /dev/null +++ b/src/devices/bus/spectrum/specmate.h @@ -0,0 +1,59 @@ +// license:BSD-3-Clause +// copyright-holders:TwistedTom +/********************************************************************* + + Spec-Mate back-up interface + + (A, T & Y Computing Ltd.) + +*********************************************************************/ +#ifndef MAME_BUS_SPECTRUM_SPECMATE_H +#define MAME_BUS_SPECTRUM_SPECMATE_H + +#include "exp.h" + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class spectrum_specmate_device : public device_t, public device_spectrum_expansion_interface +{ +public: + // construction/destruction + spectrum_specmate_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + DECLARE_INPUT_CHANGED_MEMBER(freeze_button) { m_slot->nmi_w(newval ? CLEAR_LINE : ASSERT_LINE); }; + +protected: + // device-level overrides + virtual void device_start() override; + virtual void device_reset() override; + + // 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 DECLARE_READ_LINE_MEMBER(romcs) override; + + // passthru + virtual void post_opcode_fetch(offs_t offset) override { m_exp->post_opcode_fetch(offset); }; + virtual void pre_data_fetch(offs_t offset) override { m_exp->pre_data_fetch(offset); }; + virtual void post_data_fetch(offs_t offset) override { m_exp->post_data_fetch(offset); }; + virtual void mreq_w(offs_t offset, uint8_t data) override { if (m_exp->romcs()) m_exp->mreq_w(offset, data); } + virtual uint8_t iorq_r(offs_t offset) override { return m_exp->iorq_r(offset); } + virtual void iorq_w(offs_t offset, uint8_t data) override { m_exp->iorq_w(offset, data); } + + required_memory_region m_rom; + required_device m_exp; + + int m_romcs; +}; + +// device type definition +DECLARE_DEVICE_TYPE(SPECTRUM_SPECMATE, spectrum_specmate_device) + +#endif // MAME_BUS_SPECTRUM_SPECMATE_H diff --git a/src/devices/bus/spectrum/uspeech.cpp b/src/devices/bus/spectrum/uspeech.cpp index a3a6db8cb30..06e48dca0fd 100644 --- a/src/devices/bus/spectrum/uspeech.cpp +++ b/src/devices/bus/spectrum/uspeech.cpp @@ -114,7 +114,7 @@ uint8_t spectrum_uspeech_device::iorq_r(offs_t offset) m_romcs = !m_romcs; } - return 0xff; + return offset & 1 ? m_slot->fb_r() : 0xff; } uint8_t spectrum_uspeech_device::mreq_r(offs_t offset) diff --git a/src/devices/bus/spectrum/wafa.cpp b/src/devices/bus/spectrum/wafa.cpp index 2e25b2500ce..c5af195289c 100644 --- a/src/devices/bus/spectrum/wafa.cpp +++ b/src/devices/bus/spectrum/wafa.cpp @@ -53,6 +53,7 @@ void spectrum_wafa_device::device_add_mconfig(machine_config &config) SPECTRUM_EXPANSION_SLOT(config, m_exp, spectrum_expansion_devices, nullptr); m_exp->irq_handler().set(DEVICE_SELF_OWNER, FUNC(spectrum_expansion_slot_device::irq_w)); m_exp->nmi_handler().set(DEVICE_SELF_OWNER, FUNC(spectrum_expansion_slot_device::nmi_w)); + m_exp->fb_r_handler().set(DEVICE_SELF_OWNER, FUNC(spectrum_expansion_slot_device::fb_r)); SOFTWARE_LIST(config, "wafadrive_list").set_original("spectrum_wafadrive"); } diff --git a/src/mame/drivers/atm.cpp b/src/mame/drivers/atm.cpp index 1bf5e85ffb0..10ac8b00297 100644 --- a/src/mame/drivers/atm.cpp +++ b/src/mame/drivers/atm.cpp @@ -131,7 +131,7 @@ void atm_state::atm_io(address_map &map) map(0x003f, 0x003f).mirror(0xff00).rw(m_beta, FUNC(beta_disk_device::track_r), FUNC(beta_disk_device::track_w)); map(0x005f, 0x005f).mirror(0xff00).rw(m_beta, FUNC(beta_disk_device::sector_r), FUNC(beta_disk_device::sector_w)); map(0x007f, 0x007f).mirror(0xff00).rw(m_beta, FUNC(beta_disk_device::data_r), FUNC(beta_disk_device::data_w)); - map(0x00fe, 0x00fe).select(0xff00).rw(FUNC(atm_state::spectrum_port_fe_r), FUNC(atm_state::spectrum_port_fe_w)); + map(0x00fe, 0x00fe).select(0xff00).rw(FUNC(atm_state::spectrum_ula_r), FUNC(atm_state::spectrum_ula_w)); map(0x00ff, 0x00ff).mirror(0xff00).rw(m_beta, FUNC(beta_disk_device::state_r), FUNC(beta_disk_device::param_w)); map(0x4000, 0x4000).mirror(0x3ffd).w(FUNC(atm_state::atm_port_7ffd_w)); map(0x8000, 0x8000).mirror(0x3ffd).w("ay8912", FUNC(ay8910_device::data_w)); diff --git a/src/mame/drivers/elwro800.cpp b/src/mame/drivers/elwro800.cpp index d27d46da27c..6a1476e0333 100644 --- a/src/mame/drivers/elwro800.cpp +++ b/src/mame/drivers/elwro800.cpp @@ -325,7 +325,7 @@ void elwro800_state::elwro800jr_io_w(offs_t offset, uint8_t data) if (!BIT(cs,0)) { // CFE - spectrum_port_fe_w(offset, data); + spectrum_ula_w(offset, data); } else if (!BIT(cs,1)) { diff --git a/src/mame/drivers/pentagon.cpp b/src/mame/drivers/pentagon.cpp index 9f34427ed2c..20cc5666c12 100644 --- a/src/mame/drivers/pentagon.cpp +++ b/src/mame/drivers/pentagon.cpp @@ -210,7 +210,7 @@ void pentagon_state::pentagon_io(address_map &map) map(0x003f, 0x003f).mirror(0xff00).rw(m_beta, FUNC(beta_disk_device::track_r), FUNC(beta_disk_device::track_w)); map(0x005f, 0x005f).mirror(0xff00).rw(m_beta, FUNC(beta_disk_device::sector_r), FUNC(beta_disk_device::sector_w)); map(0x007f, 0x007f).mirror(0xff00).rw(m_beta, FUNC(beta_disk_device::data_r), FUNC(beta_disk_device::data_w)); - map(0x00fe, 0x00fe).select(0xff00).rw(FUNC(pentagon_state::spectrum_port_fe_r), FUNC(pentagon_state::spectrum_port_fe_w)); + map(0x00fe, 0x00fe).select(0xff00).rw(FUNC(pentagon_state::spectrum_ula_r), FUNC(pentagon_state::spectrum_ula_w)); map(0x00ff, 0x00ff).mirror(0xff00).rw(m_beta, FUNC(beta_disk_device::state_r), FUNC(beta_disk_device::param_w)); map(0x8000, 0x8000).mirror(0x3ffd).w("ay8912", FUNC(ay8910_device::data_w)); map(0xc000, 0xc000).mirror(0x3ffd).rw("ay8912", FUNC(ay8910_device::data_r), FUNC(ay8910_device::address_w)); diff --git a/src/mame/drivers/scorpion.cpp b/src/mame/drivers/scorpion.cpp index 95174090351..e96dee69a10 100644 --- a/src/mame/drivers/scorpion.cpp +++ b/src/mame/drivers/scorpion.cpp @@ -197,7 +197,7 @@ void scorpion_state::scorpion_io(address_map &map) map(0x003f, 0x003f).mirror(0xff00).rw(m_beta, FUNC(beta_disk_device::track_r), FUNC(beta_disk_device::track_w)); map(0x005f, 0x005f).mirror(0xff00).rw(m_beta, FUNC(beta_disk_device::sector_r), FUNC(beta_disk_device::sector_w)); map(0x007f, 0x007f).mirror(0xff00).rw(m_beta, FUNC(beta_disk_device::data_r), FUNC(beta_disk_device::data_w)); - map(0x00fe, 0x00fe).select(0xff00).rw(FUNC(scorpion_state::spectrum_port_fe_r), FUNC(scorpion_state::spectrum_port_fe_w)); + map(0x00fe, 0x00fe).select(0xff00).rw(FUNC(scorpion_state::spectrum_ula_r), FUNC(scorpion_state::spectrum_ula_w)); map(0x00ff, 0x00ff).mirror(0xff00).rw(m_beta, FUNC(beta_disk_device::state_r), FUNC(beta_disk_device::param_w)); map(0x4021, 0x4021).mirror(0x3fdc).w(FUNC(scorpion_state::scorpion_port_7ffd_w)); map(0x8021, 0x8021).mirror(0x3fdc).w("ay8912", FUNC(ay8910_device::data_w)); diff --git a/src/mame/drivers/spec128.cpp b/src/mame/drivers/spec128.cpp index 8a12f04b145..39a864e76b0 100644 --- a/src/mame/drivers/spec128.cpp +++ b/src/mame/drivers/spec128.cpp @@ -239,21 +239,35 @@ void spectrum_128_state::spectrum_128_update_memory() m_screen_location = messram + (5<<14); } -uint8_t spectrum_128_state::spectrum_128_ula_r() +uint8_t spectrum_128_state::spectrum_port_r(offs_t offset) { + // Pass through to expansion device if present + if (m_exp->get_card_device()) + return m_exp->iorq_r(offset | 1); + + return floating_bus_r(); +} + +uint8_t spectrum_128_state::floating_bus_r() +{ + // very basic "floating bus" implementation, see notes in spectrum.cpp + uint8_t data = 0xff; + int hpos = m_screen->hpos(); int vpos = m_screen->vpos(); - return vpos<193 ? m_screen_location[0x1800|(vpos&0xf8)<<2]:0xff; + if ((hpos >= 48 && hpos < 304) && (vpos >= 48 && vpos < 240)) + data = m_screen_location[0x1800 + (((vpos-48)/8)*32) + ((hpos-48)/8)]; + + return data; } void spectrum_128_state::spectrum_128_io(address_map &map) { - map(0x0000, 0xffff).rw(m_exp, FUNC(spectrum_expansion_slot_device::iorq_r), FUNC(spectrum_expansion_slot_device::iorq_w)); - map(0x0000, 0x0000).select(0xfffe).rw(FUNC(spectrum_128_state::spectrum_port_fe_r), FUNC(spectrum_128_state::spectrum_port_fe_w)); + map(0x0000, 0x0000).select(0xfffe).rw(FUNC(spectrum_128_state::spectrum_ula_r), FUNC(spectrum_128_state::spectrum_ula_w)); + map(0x0001, 0x0001).select(0xfffe).rw(FUNC(spectrum_128_state::spectrum_port_r), FUNC(spectrum_128_state::spectrum_port_w)); map(0x0001, 0x0001).select(0x7ffc).w(FUNC(spectrum_128_state::spectrum_128_port_7ffd_w)); // (A15 | A1) == 0, note: reading from this port does write to it by value from data bus map(0x8000, 0x8000).mirror(0x3ffd).w("ay8912", FUNC(ay8910_device::data_w)); map(0xc000, 0xc000).mirror(0x3ffd).rw("ay8912", FUNC(ay8910_device::data_r), FUNC(ay8910_device::address_w)); - map(0x0001, 0x0001).r(FUNC(spectrum_128_state::spectrum_128_ula_r)); // .mirror(0xfffe); } void spectrum_128_state::spectrum_128_mem(address_map &map) @@ -332,6 +346,7 @@ void spectrum_128_state::spectrum_128(machine_config &config) SPECTRUM_EXPANSION_SLOT(config.replace(), m_exp, spec128_expansion_devices, nullptr); m_exp->irq_handler().set_inputline(m_maincpu, INPUT_LINE_IRQ0); m_exp->nmi_handler().set_inputline(m_maincpu, INPUT_LINE_NMI); + m_exp->fb_r_handler().set(FUNC(spectrum_128_state::floating_bus_r)); /* internal ram */ m_ram->set_default_size("128K"); @@ -375,24 +390,14 @@ ROM_START(specpls2) ROMX_LOAD("pl2namco.rom",0x10000,0x8000, CRC(72a54e75) SHA1(311400157df689450dadc3620f4c4afa960b05ad), ROM_BIOS(4)) ROM_END -ROM_START(hc128) +ROM_START(hc128) // Romanian clone, "ICE Felix HC91+" (aka HC-128), AY-8910 was optional ROM_REGION(0x18000,"maincpu",0) ROM_LOAD("zx128_0.rom",0x10000,0x4000, CRC(e76799d2) SHA1(4f4b11ec22326280bdb96e3baf9db4b4cb1d02c5)) ROM_LOAD("hc128.rom", 0x14000,0x4000, CRC(0241e960) SHA1(cea0d14391b9e571460a816088a1c00ecb24afa3)) ROM_END -ROM_START(hc2000) - ROM_REGION(0x18000,"maincpu",0) - ROM_SYSTEM_BIOS( 0, "v1", "Version 1" ) - ROMX_LOAD("zx128_0.rom",0x10000,0x4000, CRC(e76799d2) SHA1(4f4b11ec22326280bdb96e3baf9db4b4cb1d02c5), ROM_BIOS(0)) - ROMX_LOAD("hc2000.v1", 0x14000,0x4000, CRC(453c1a5a) SHA1(f8139fc38478691cf44944dc83fd6e70b0f002fb), ROM_BIOS(0)) - ROM_SYSTEM_BIOS( 1, "v2", "Version 2" ) - ROMX_LOAD("zx128_0.rom",0x10000,0x4000, CRC(e76799d2) SHA1(4f4b11ec22326280bdb96e3baf9db4b4cb1d02c5), ROM_BIOS(1)) - ROMX_LOAD("hc2000.v2", 0x14000,0x4000, CRC(65d90464) SHA1(5e2096e6460ff2120c8ada97579fdf82c1199c09), ROM_BIOS(1)) -ROM_END -// YEAR NAME PARENT COMPAT MACHINE CLASS STATE INIT COMPANY FULLNAME FLAGS +// YEAR NAME PARENT COMPAT MACHINE INPUT STATE INIT COMPANY FULLNAME FLAGS COMP( 1986, spec128, 0, 0, spectrum_128, spec128, spectrum_128_state, empty_init, "Sinclair Research Ltd", "ZX Spectrum 128", 0 ) COMP( 1986, specpls2, spec128, 0, spectrum_128, spec_plus, spectrum_128_state, empty_init, "Amstrad plc", "ZX Spectrum +2", 0 ) -COMP( 1991, hc128, spec128, 0, spectrum_128, spec_plus, spectrum_128_state, empty_init, "ICE-Felix", "HC-128", 0 ) -COMP( 1992, hc2000, spec128, 0, spectrum_128, spec_plus, spectrum_128_state, empty_init, "ICE-Felix", "HC-2000", MACHINE_NOT_WORKING ) +COMP( 1991, hc128, spec128, 0, spectrum_128, spec_plus, spectrum_128_state, empty_init, "ICE-Felix", "HC-91+ (HC-128)", 0 ) diff --git a/src/mame/drivers/specpls3.cpp b/src/mame/drivers/specpls3.cpp index 747853e603c..412f6a0647e 100644 --- a/src/mame/drivers/specpls3.cpp +++ b/src/mame/drivers/specpls3.cpp @@ -173,10 +173,14 @@ static const int spectrum_plus3_memory_selections[]= 4,7,6,3 }; -void specpls3_state::port_3ffd_w(uint8_t data) +void specpls3_state::port_3ffd_w(offs_t offset, uint8_t data) { if (m_upd765.found()) m_upd765->fifo_w(data); + + /* mface3 needs to see this port */ + if (m_exp) + m_exp->iorq_w(offset | 0x3000, data); } uint8_t specpls3_state::port_3ffd_r() @@ -291,14 +295,18 @@ uint8_t specpls3_state::bank1_r(offs_t offset) return data; } -void specpls3_state::port_7ffd_w(uint8_t data) +void specpls3_state::port_7ffd_w(offs_t offset, uint8_t data) { - /* D0-D2: RAM page located at 0x0c000-0x0ffff */ - /* D3 - Screen select (screen 0 in ram page 5, screen 1 in ram page 7 */ - /* D4 - ROM select - which rom paged into 0x0000-0x03fff */ - /* D5 - Disable paging */ + /* D0-D2 - RAM page located at 0x0c000-0x0ffff */ + /* D3 - Screen select (screen 0 in ram page 5, screen 1 in ram page 7 */ + /* D4 - ROM select low bit - which rom paged into 0x0000-0x03fff */ + /* D5 - Disable paging (permanent until reset) */ - /* disable paging? */ + /* mface3 needs to see this port */ + if (m_exp) + m_exp->iorq_w(offset | 0x4000, data); + + /* paging disabled? */ if (m_port_7ffd_data & 0x20) return; @@ -309,12 +317,15 @@ void specpls3_state::port_7ffd_w(uint8_t data) plus3_update_memory(); } -void specpls3_state::port_1ffd_w(uint8_t data) +void specpls3_state::port_1ffd_w(offs_t offset, uint8_t data) { - /* D0-D1: ROM/RAM paging */ - /* D2: Affects if d0-d1 work on ram/rom */ - /* D3 - Disk motor on/off */ - /* D4 - parallel port strobe */ + /* D0=0 - Normal ROM/RAM paging mode */ + /* D1 - Not used */ + /* D2 - Rom select high bit */ + /* D0=1 - Special RAM paging mode (all-RAM CP/M modes) */ + /* D1-D2 - Special paging mode 0-3 */ + /* D3 - Disk motor on/off */ + /* D4 - Parallel port strobe */ if (m_upd765.found()) { @@ -323,14 +334,23 @@ void specpls3_state::port_1ffd_w(uint8_t data) flop->get_device()->mon_w(!BIT(data, 3)); } - m_port_1ffd_data = data; + /* mface3 needs to see this port */ + if (m_exp) + m_exp->iorq_w(offset | 0x1000, data); - /* disable paging? */ + /* paging disabled? */ if ((m_port_7ffd_data & 0x20)==0) { /* no */ + m_port_1ffd_data = data; plus3_update_memory(); } + else + { + /* yes, update only non-memory related */ + m_port_1ffd_data &= 0x7; + m_port_1ffd_data |= data & 0xf8; + } } /* ports are not decoded full. @@ -338,13 +358,13 @@ The function decodes the ports appropriately */ void specpls3_state::plus3_io(address_map &map) { map(0x0000, 0xffff).rw(m_exp, FUNC(spectrum_expansion_slot_device::iorq_r), FUNC(spectrum_expansion_slot_device::iorq_w)); - map(0x0000, 0x0000).rw(FUNC(specpls3_state::spectrum_port_fe_r), FUNC(specpls3_state::spectrum_port_fe_w)).select(0xfffe); - map(0x4000, 0x4000).w(FUNC(specpls3_state::port_7ffd_w)).mirror(0x3ffd); + map(0x0000, 0x0000).rw(FUNC(specpls3_state::spectrum_ula_r), FUNC(specpls3_state::spectrum_ula_w)).select(0xfffe); + map(0x4000, 0x4000).w(FUNC(specpls3_state::port_7ffd_w)).select(0x3ffd); map(0x8000, 0x8000).w("ay8912", FUNC(ay8910_device::data_w)).mirror(0x3ffd); map(0xc000, 0xc000).rw("ay8912", FUNC(ay8910_device::data_r), FUNC(ay8910_device::address_w)).mirror(0x3ffd); - map(0x1000, 0x1000).w(FUNC(specpls3_state::port_1ffd_w)).mirror(0x0ffd); + map(0x1000, 0x1000).w(FUNC(specpls3_state::port_1ffd_w)).select(0x0ffd); map(0x2000, 0x2000).r(FUNC(specpls3_state::port_2ffd_r)).mirror(0x0ffd); - map(0x3000, 0x3000).rw(FUNC(specpls3_state::port_3ffd_r), FUNC(specpls3_state::port_3ffd_w)).mirror(0x0ffd); + map(0x3000, 0x3000).rw(FUNC(specpls3_state::port_3ffd_r), FUNC(specpls3_state::port_3ffd_w)).select(0x0ffd); } void specpls3_state::plus3_mem(address_map &map) @@ -415,6 +435,8 @@ void specpls3_state::spectrum_plus2(machine_config &config) SPECTRUM_EXPANSION_SLOT(config.replace(), m_exp, specpls3_expansion_devices, nullptr); m_exp->irq_handler().set_inputline(m_maincpu, INPUT_LINE_IRQ0); m_exp->nmi_handler().set_inputline(m_maincpu, INPUT_LINE_NMI); + // these models don't have floating bus + m_exp->fb_r_handler().set([]() { return 0xff; }); } void specpls3_state::spectrum_plus3(machine_config &config) @@ -435,34 +457,50 @@ void specpls3_state::spectrum_plus3(machine_config &config) ***************************************************************************/ +/* Amstrad built +2A/+2B/+3/+3B models: + + +2A/B has built-in tape "datacorder", +3/B has built-in 3" fdd + +2A/+3 use common z70830 pcb with v4.0 rom (fdc etc. unpopulated on +2A) + +2B/+3B use unique z70833/z70835 pcbs but use same v4.1 rom + + Note, +2 (non-A/B, aka "grey case") although Amstrad built is essentially a re-cased Sinclair 128K, see spec128.cpp +*/ ROM_START(specpl2a) ROM_REGION(0x20000,"maincpu",0) - ROM_LOAD("p2a41_0.rom",0x10000,0x4000, CRC(30c9f490) SHA1(62ec15a4af56cd1d206d0bd7011eac7c889a595d)) - ROM_LOAD("p2a41_1.rom",0x14000,0x4000, CRC(a7916b3f) SHA1(1a7812c383a3701e90e88d1da086efb0c033ac72)) - ROM_LOAD("p2a41_2.rom",0x18000,0x4000, CRC(c9a0b748) SHA1(8df145d10ff78f98138682ea15ebccb2874bf759)) - ROM_LOAD("p2a41_3.rom",0x1c000,0x4000, CRC(b88fd6e3) SHA1(be365f331942ec7ec35456b641dac56a0dbfe1f0)) + ROM_SYSTEM_BIOS( 0, "en", "English v4.0" ) // +2A + ROMX_LOAD("40092.ic7",0x10000,0x8000, CRC(9bc85686) SHA1(5992daf925f6e225fc0d01f7640282954d092ef4), ROM_BIOS(0)) + ROMX_LOAD("40093.ic8",0x18000,0x8000, CRC(db551783) SHA1(a0432adcca03f849fb39b6dce6414740cf4aecd2), ROM_BIOS(0)) + ROM_SYSTEM_BIOS( 1, "sp", "Spanish v4.0" ) + ROMX_LOAD("40094.ic7",0x10000,0x8000, CRC(392242fb) SHA1(976ae88951f8d1beb5d107f048950118a7133823), ROM_BIOS(1)) + ROMX_LOAD("40101.ic8",0x18000,0x8000, CRC(5daaae01) SHA1(09ca25b4dbec064a4964ab7a41d48404199afd77), ROM_BIOS(1)) + ROM_SYSTEM_BIOS( 2, "enb", "English v4.1" ) // +2B + ROMX_LOAD("40092u.ic7",0x10000,0x8000, CRC(80808d82) SHA1(b9e88ec18f844ce42ecb7802d82c2bda65f9c4f2), ROM_BIOS(2)) + ROMX_LOAD("40093u.ic8",0x18000,0x8000, CRC(61f2b50c) SHA1(d062765ceb1f3cd2c94ea51cb737cac7ad6151b4), ROM_BIOS(2)) + ROM_SYSTEM_BIOS( 3, "spb", "Spanish v4.1" ) + ROMX_LOAD("40094s.ic7",0x10000,0x8000, CRC(9d102acf) SHA1(c525bd23f79ca968d34a0efdcc47b2eb342007f5), ROM_BIOS(3)) + ROMX_LOAD("40101s.ic8",0x18000,0x8000, CRC(1408ddce) SHA1(56eb124d44ee8c8daef130be4d7e735ec412c4ba), ROM_BIOS(3)) ROM_END ROM_START(specpls3) ROM_REGION(0x20000,"maincpu",0) - ROM_SYSTEM_BIOS( 0, "en", "English v4.0" ) - ROMX_LOAD("pl3-0.rom",0x10000,0x4000, CRC(17373da2) SHA1(e319ed08b4d53a5e421a75ea00ea02039ba6555b), ROM_BIOS(0)) - ROMX_LOAD("pl3-1.rom",0x14000,0x4000, CRC(f1d1d99e) SHA1(c9969fc36095a59787554026a9adc3b87678c794), ROM_BIOS(0)) - ROMX_LOAD("pl3-2.rom",0x18000,0x4000, CRC(3dbf351d) SHA1(22e50c6ba4157a3f6a821bd9937cd26e292775c6), ROM_BIOS(0)) - ROMX_LOAD("pl3-3.rom",0x1c000,0x4000, CRC(04448eaa) SHA1(65f031caa8148a5493afe42c41f4929deab26b4e), ROM_BIOS(0)) - ROM_SYSTEM_BIOS( 1, "sp", "Spanish v.40" ) - ROMX_LOAD("plus3sp0.rom",0x10000,0x4000, CRC(1f86147a) SHA1(e9b0a60a1a8def511d59090b945d175bdc646346), ROM_BIOS(1)) - ROMX_LOAD("plus3sp1.rom",0x14000,0x4000, CRC(a8ac4966) SHA1(4e48f196427596c7990c175d135c15a039c274a4), ROM_BIOS(1)) - ROMX_LOAD("plus3sp2.rom",0x18000,0x4000, CRC(f6bb0296) SHA1(09fc005625589ef5992515957ce7a3167dec24b2), ROM_BIOS(1)) - ROMX_LOAD("plus3sp3.rom",0x1c000,0x4000, CRC(f6d25389) SHA1(ec8f644a81e2e9bcb58ace974103ea960361bad2), ROM_BIOS(1)) - ROM_SYSTEM_BIOS( 2, "en41", "English v4.1" ) - ROMX_LOAD("plus341.rom",0x10000,0x10000, CRC(be0d9ec4) SHA1(500c0945760abeefcbd08bc22c0d07b14b336cf0), ROM_BIOS(2)) - ROM_SYSTEM_BIOS( 3, "4ms", "Customize 3.5\" 4ms" ) - ROMX_LOAD("p3_01_4m.rom",0x10000,0x8000, CRC(ad99380a) SHA1(4e5d114b72d464cefdde0566457f52a3c0c1cae2), ROM_BIOS(3)) - ROMX_LOAD("p3_23_4m.rom",0x18000,0x8000, CRC(07727895) SHA1(752cdd6a083ab9910348995e483541d60bb6372b), ROM_BIOS(3)) - ROM_SYSTEM_BIOS( 4, "12ms", "Customize 3.5\" 12ms" ) - ROMX_LOAD("p3_01_cm.rom",0x10000,0x8000, CRC(ad99380a) SHA1(4e5d114b72d464cefdde0566457f52a3c0c1cae2), ROM_BIOS(4)) - ROMX_LOAD("p3_23_cm.rom",0x18000,0x8000, CRC(61f2b50c) SHA1(d062765ceb1f3cd2c94ea51cb737cac7ad6151b4), ROM_BIOS(4)) + ROM_SYSTEM_BIOS( 0, "en", "English v4.0" ) // +3 + ROMX_LOAD("40092.ic7",0x10000,0x8000, CRC(9bc85686) SHA1(5992daf925f6e225fc0d01f7640282954d092ef4), ROM_BIOS(0)) + ROMX_LOAD("40093.ic8",0x18000,0x8000, CRC(db551783) SHA1(a0432adcca03f849fb39b6dce6414740cf4aecd2), ROM_BIOS(0)) + ROM_SYSTEM_BIOS( 1, "sp", "Spanish v4.0" ) + ROMX_LOAD("40094.ic7",0x10000,0x8000, CRC(392242fb) SHA1(976ae88951f8d1beb5d107f048950118a7133823), ROM_BIOS(1)) + ROMX_LOAD("40101.ic8",0x18000,0x8000, CRC(5daaae01) SHA1(09ca25b4dbec064a4964ab7a41d48404199afd77), ROM_BIOS(1)) + ROM_SYSTEM_BIOS( 2, "enb", "English v4.1" ) // +3B + ROMX_LOAD("40092u.ic7",0x10000,0x8000, CRC(80808d82) SHA1(b9e88ec18f844ce42ecb7802d82c2bda65f9c4f2), ROM_BIOS(2)) + ROMX_LOAD("40093u.ic8",0x18000,0x8000, CRC(61f2b50c) SHA1(d062765ceb1f3cd2c94ea51cb737cac7ad6151b4), ROM_BIOS(2)) + ROM_SYSTEM_BIOS( 3, "spb", "Spanish v4.1" ) + ROMX_LOAD("40094s.ic7",0x10000,0x8000, CRC(9d102acf) SHA1(c525bd23f79ca968d34a0efdcc47b2eb342007f5), ROM_BIOS(3)) + ROMX_LOAD("40101s.ic8",0x18000,0x8000, CRC(1408ddce) SHA1(56eb124d44ee8c8daef130be4d7e735ec412c4ba), ROM_BIOS(3)) + ROM_SYSTEM_BIOS( 4, "4ms", "Customize 3.5\" 4ms" ) // unofficial 3.5" fdd hacks by Cristian Secară (v4.1 english) + ROMX_LOAD("p3_01_4m.rom",0x10000,0x8000, CRC(ad99380a) SHA1(4e5d114b72d464cefdde0566457f52a3c0c1cae2), ROM_BIOS(4)) + ROMX_LOAD("p3_23_4m.rom",0x18000,0x8000, CRC(07727895) SHA1(752cdd6a083ab9910348995e483541d60bb6372b), ROM_BIOS(4)) + ROM_SYSTEM_BIOS( 5, "12ms", "Customize 3.5\" 12ms" ) + ROMX_LOAD("p3_01_cm.rom",0x10000,0x8000, CRC(ad99380a) SHA1(4e5d114b72d464cefdde0566457f52a3c0c1cae2), ROM_BIOS(5)) + ROMX_LOAD("p3_23_cm.rom",0x18000,0x8000, CRC(61f2b50c) SHA1(d062765ceb1f3cd2c94ea51cb737cac7ad6151b4), ROM_BIOS(5)) ROM_END ROM_START(specpl3e) @@ -499,10 +537,10 @@ ROM_START(sp3eata) ROMX_LOAD("3ezxaes.rom",0x10000,0x10000, CRC(8f0ae91a) SHA1(71693e18b30c90914be58cba26682ca025c924ea), ROM_BIOS(1)) ROM_END -/* YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS */ -COMP( 1987, specpl2a, spec128, 0, spectrum_plus2, spec_plus, specpls3_state, empty_init, "Amstrad plc", "ZX Spectrum +2a", 0 ) -COMP( 1987, specpls3, spec128, 0, spectrum_plus3, spec_plus, specpls3_state, empty_init, "Amstrad plc", "ZX Spectrum +3", 0 ) -COMP( 2000, specpl3e, spec128, 0, spectrum_plus3, spec_plus, specpls3_state, empty_init, "Amstrad plc", "ZX Spectrum +3e", MACHINE_UNOFFICIAL ) -COMP( 2002, sp3e8bit, spec128, 0, spectrum_plus3, spec_plus, specpls3_state, empty_init, "Amstrad plc", "ZX Spectrum +3e 8bit IDE", MACHINE_UNOFFICIAL ) -COMP( 2002, sp3eata, spec128, 0, spectrum_plus3, spec_plus, specpls3_state, empty_init, "Amstrad plc", "ZX Spectrum +3e 8bit ZXATASP" , MACHINE_UNOFFICIAL ) -COMP( 2002, sp3ezcf, spec128, 0, spectrum_plus3, spec_plus, specpls3_state, empty_init, "Amstrad plc", "ZX Spectrum +3e 8bit ZXCF", MACHINE_UNOFFICIAL ) +/* YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS */ +COMP( 1987, specpl2a, 0, 0, spectrum_plus2, spec_plus, specpls3_state, empty_init, "Amstrad plc", "ZX Spectrum +2a", 0 ) +COMP( 1987, specpls3, specpl2a, 0, spectrum_plus3, spec_plus, specpls3_state, empty_init, "Amstrad plc", "ZX Spectrum +3", 0 ) +COMP( 2000, specpl3e, 0, 0, spectrum_plus3, spec_plus, specpls3_state, empty_init, "Amstrad plc", "ZX Spectrum +3e", MACHINE_UNOFFICIAL ) +COMP( 2002, sp3e8bit, 0, 0, spectrum_plus3, spec_plus, specpls3_state, empty_init, "Amstrad plc", "ZX Spectrum +3e 8bit IDE", MACHINE_UNOFFICIAL ) +COMP( 2002, sp3eata, 0, 0, spectrum_plus3, spec_plus, specpls3_state, empty_init, "Amstrad plc", "ZX Spectrum +3e 8bit ZXATASP", MACHINE_UNOFFICIAL ) +COMP( 2002, sp3ezcf, 0, 0, spectrum_plus3, spec_plus, specpls3_state, empty_init, "Amstrad plc", "ZX Spectrum +3e 8bit ZXCF", MACHINE_UNOFFICIAL ) diff --git a/src/mame/drivers/spectrum.cpp b/src/mame/drivers/spectrum.cpp index 9bf83d33703..f3a6dde65a3 100644 --- a/src/mame/drivers/spectrum.cpp +++ b/src/mame/drivers/spectrum.cpp @@ -340,7 +340,7 @@ uint8_t spectrum_state::spectrum_rom_r(offs_t offset) bit 2-0: border colour */ -void spectrum_state::spectrum_port_fe_w(offs_t offset, uint8_t data) +void spectrum_state::spectrum_ula_w(offs_t offset, uint8_t data) { unsigned char Changed; @@ -364,6 +364,8 @@ void spectrum_state::spectrum_port_fe_w(offs_t offset, uint8_t data) m_cassette->output((data & (1<<3)) ? -1.0 : +1.0); } + // Some exp devices use ula port unused bits 5-7: + // Beta v2/3/plus use bit 7, Beta clones use bits 6 and 7 if (m_exp) m_exp->iorq_w(offset, data); @@ -373,7 +375,7 @@ void spectrum_state::spectrum_port_fe_w(offs_t offset, uint8_t data) /* KT: more accurate keyboard reading */ /* DJR: Spectrum+ keys added */ -uint8_t spectrum_state::spectrum_port_fe_r(offs_t offset) +uint8_t spectrum_state::spectrum_ula_r(offs_t offset) { int lines = offset >> 8; int data = 0xff; @@ -448,76 +450,30 @@ uint8_t spectrum_state::spectrum_port_fe_r(offs_t offset) return data; } -uint8_t spectrum_state::spectrum_port_ula_r(offs_t offset) +void spectrum_state::spectrum_port_w(offs_t offset, uint8_t data) { - // known ports used for reading floating bus are: - // 0x28ff Arkanoid, Cobra, Renegade, Short Circuit, Terra Cresta - // 0x40ff Sidewize - - // note, these games clash with Beta disk (status reg is R:xxff) - - offset |= 1; - //logerror("fb: %04x\n", offset); - -#if 0 // TODO make this expansion devices friendly - // Arkanoid, Cobra, Renegade, Short Circuit, Terra Cresta - if (offset == 0x28ff) - return floating_bus_r(); - - // Sidewize - if (offset == 0x40ff) - return floating_bus_r(); -#endif - // Pass through to expansion device if present if (m_exp->get_card_device()) - return m_exp->iorq_r(offset); + m_exp->iorq_w(offset | 1, data); +} + +uint8_t spectrum_state::spectrum_port_r(offs_t offset) +{ + // Pass through to expansion device if present + if (m_exp->get_card_device()) + return m_exp->iorq_r(offset | 1); return floating_bus_r(); } -uint8_t spectrum_state::spectrum_clone_port_ula_r() +uint8_t spectrum_state::spectrum_clone_port_r(offs_t offset) { - int vpos = m_screen->vpos(); + // Pass through to expansion device if present + if (m_exp->get_card_device()) + return m_exp->iorq_r(offset | 1); - return vpos<193 ? m_video_ram[(vpos&0xf8)<<2]:0xff; -} - -/* Memory Maps */ - -void spectrum_state::spectrum_map(address_map &map) -{ - map(0x0000, 0x3fff).rw(FUNC(spectrum_state::spectrum_rom_r), FUNC(spectrum_state::spectrum_rom_w)); - map(0x4000, 0x5aff).ram().share("video_ram"); - // installed later depending on ramsize - //map(0x5b00, 0x7fff).ram(); - //map(0x8000, 0xffff).ram(); -} - -void spectrum_state::spectrum_opcodes(address_map &map) -{ - map(0x0000, 0xffff).rw(FUNC(spectrum_state::spectrum_data_r), FUNC(spectrum_state::spectrum_data_w)); -} - -void spectrum_state::spectrum_data(address_map &map) -{ - map(0x0000, 0xffff).r(FUNC(spectrum_state::pre_opcode_fetch_r)); -} - -/* ports are not decoded full. -The function decodes the ports appropriately */ -void spectrum_state::spectrum_io(address_map &map) -{ - map(0x0000, 0xffff).w(m_exp, FUNC(spectrum_expansion_slot_device::iorq_w)); - map(0x00, 0x00).select(0xfffe).rw(FUNC(spectrum_state::spectrum_port_fe_r), FUNC(spectrum_state::spectrum_port_fe_w)); - map(0x01, 0x01).select(0xfffe).r(FUNC(spectrum_state::spectrum_port_ula_r)); -} - -void spectrum_state::spectrum_clone_io(address_map &map) -{ - map(0x0000, 0xffff).rw(m_exp, FUNC(spectrum_expansion_slot_device::iorq_r), FUNC(spectrum_expansion_slot_device::iorq_w)); - map(0x00, 0x00).select(0xfffe).rw(FUNC(spectrum_state::spectrum_port_fe_r), FUNC(spectrum_state::spectrum_port_fe_w)); - map(0x01, 0x01).r(FUNC(spectrum_state::spectrum_clone_port_ula_r)); // .mirror(0xfffe); + // no floating bus for clones + return 0xff; } uint8_t spectrum_state::floating_bus_r() @@ -540,6 +496,8 @@ uint8_t spectrum_state::floating_bus_r() * * ...others? * + * (Sidewize uses port 0x40ff, others use 0x28ff) + * * Note, some were later re-released as "fixed" +2A compatible versions with the floating bus code removed (Arkanoid, Cobra, others?). */ @@ -557,6 +515,46 @@ uint8_t spectrum_state::floating_bus_r() } +/* Memory Maps */ + +void spectrum_state::spectrum_map(address_map &map) +{ + map(0x0000, 0x3fff).rw(FUNC(spectrum_state::spectrum_rom_r), FUNC(spectrum_state::spectrum_rom_w)); + map(0x4000, 0x5aff).ram().share("video_ram"); + // installed later depending on ramsize + //map(0x5b00, 0x7fff).ram(); + //map(0x8000, 0xffff).ram(); +} + +void spectrum_state::spectrum_opcodes(address_map &map) +{ + map(0x0000, 0xffff).rw(FUNC(spectrum_state::spectrum_data_r), FUNC(spectrum_state::spectrum_data_w)); +} + +void spectrum_state::spectrum_data(address_map &map) +{ + map(0x0000, 0xffff).r(FUNC(spectrum_state::pre_opcode_fetch_r)); +} + +// The ula is usually accessed with port 0xfe but is only partially decoded with a single address line (A0), +// so actually responds to any even numbered port. +// Exp devices therefore shouldn't use any even numbered ports, but in fact some do: +// for write, some devices use bits 5-7 as they are not used by the ula (eg. Beta) +// for read, some devices (eg. Interface II and some other joystick interfaces) simply override the data lines to simulate key presses +// (series resistors between the ula and cpu/exp slot allow this) +void spectrum_state::spectrum_io(address_map &map) +{ + map(0x00, 0x00).rw(FUNC(spectrum_state::spectrum_ula_r), FUNC(spectrum_state::spectrum_ula_w)).select(0xfffe); + map(0x01, 0x01).rw(FUNC(spectrum_state::spectrum_port_r), FUNC(spectrum_state::spectrum_port_w)).select(0xfffe); +} + +void spectrum_state::spectrum_clone_io(address_map &map) +{ + map(0x00, 0x00).rw(FUNC(spectrum_state::spectrum_ula_r), FUNC(spectrum_state::spectrum_ula_w)).select(0xfffe); + map(0x01, 0x01).rw(FUNC(spectrum_state::spectrum_clone_port_r), FUNC(spectrum_state::spectrum_port_w)).select(0xfffe); +} + + /* Input ports */ /****************************************************************************************************/ @@ -802,6 +800,7 @@ void spectrum_state::spectrum_common(machine_config &config) SPECTRUM_EXPANSION_SLOT(config, m_exp, spectrum_expansion_devices, "kempjoy"); m_exp->irq_handler().set_inputline(m_maincpu, INPUT_LINE_IRQ0); m_exp->nmi_handler().set_inputline(m_maincpu, INPUT_LINE_NMI); + m_exp->fb_r_handler().set(FUNC(spectrum_state::floating_bus_r)); /* devices */ SNAPSHOT(config, "snapshot", "ach,frz,plusd,prg,sem,sit,sna,snp,snx,sp,z80,zx").set_load_callback(FUNC(spectrum_state::snapshot_cb)); @@ -831,7 +830,10 @@ void spectrum_state::spectrum(machine_config &config) void spectrum_state::spectrum_clone(machine_config &config) { spectrum(config); + + // no floating bus m_maincpu->set_addrmap(AS_IO, &spectrum_state::spectrum_clone_io); + m_exp->fb_r_handler().set([]() { return 0xff; }); } /*************************************************************************** @@ -913,6 +915,15 @@ ROM_START(spec80k) ROM_LOAD("80-lec.rom", 0x0000, 0x4000, CRC(5b5c92b1) SHA1(bb7a77d66e95d2e28ebb610e543c065e0d428619)) ROM_END +/* Official Sinclair licensed Spanish clone */ + +ROM_START(inves) + ROM_REGION(0x10000,"maincpu",0) + ROM_LOAD("inves.rom",0x0000,0x4000, CRC(8ff7a4d1) SHA1(d020440638aff4d39467128413ef795677be9c23)) +ROM_END + +/* Brazilian clones */ + ROM_START(tk90x) ROM_REGION(0x10000,"maincpu",0) ROM_LOAD("tk90x.rom",0x0000,0x4000, CRC(3e785f6f) SHA1(9a943a008be13194fb006bddffa7d22d2277813f)) @@ -923,18 +934,14 @@ ROM_START(tk95) ROM_LOAD("tk95.rom",0x0000,0x4000, CRC(17368e07) SHA1(94edc401d43b0e9a9cdc1d35de4b6462dc414ab3)) ROM_END -ROM_START(inves) - ROM_REGION(0x10000,"maincpu",0) - ROM_LOAD("inves.rom",0x0000,0x4000, CRC(8ff7a4d1) SHA1(d020440638aff4d39467128413ef795677be9c23)) -ROM_END - /* Romanian clones */ + ROM_START(hc85) ROM_REGION(0x10000,"maincpu",0) ROM_LOAD("hc85.rom",0x0000,0x4000, CRC(3ab60fb5) SHA1(a4189db0bcdf8b39ed782b398828efb408fc4817)) ROM_END -ROM_START( hc88 ) +ROM_START(hc88) ROM_REGION( 0x10000, "maincpu", ROMREGION_ERASEFF ) ROM_LOAD( "hc88.bin", 0x0000, 0x0800, CRC(33be5134) SHA1(b15a6e7085710de8b818e42d329707cb737627e3)) ROM_END @@ -949,6 +956,27 @@ ROM_START(hc91) ROM_LOAD("hc91.rom",0x0000,0x4000, CRC(8bf53761) SHA1(967d5179ba2823e9c8dd9ddfb0430465aaddb554)) ROM_END +ROM_START(hc2000) + // HC-91 with internal fdd, 64KB ram, dual-os (BASIC, CP/M), built-in Interface I + // user manual states "16KB BASIC rom, 16KB CP/M rom, 10KB Interface I rom" + // some pcb have 2x 27256 eproms, some have single 28-pin socket (27512?) + // for 2 eprom model, seems #1 is combined BASIC+CP/M, #2 is intf1 + // BASIC should boot first, then optionally CP/M can be booted with RANDOMIZE USR 14446 + // CP/M can use 56KB ram, fdc is UM8272A, disks are 3.5" 720KB + ROM_REGION(0x10000,"maincpu",0) + ROM_SYSTEM_BIOS( 0, "basicv1", "BASIC v1" ) + ROMX_LOAD("hc2000.v1", 0x0000,0x4000, CRC(453c1a5a) SHA1(f8139fc38478691cf44944dc83fd6e70b0f002fb), ROM_BIOS(0)) + ROM_SYSTEM_BIOS( 1, "basicv2", "BASIC v2" ) + ROMX_LOAD("hc2000.v2", 0x0000,0x4000, CRC(65d90464) SHA1(5e2096e6460ff2120c8ada97579fdf82c1199c09), ROM_BIOS(1)) + ROM_SYSTEM_BIOS( 2, "cpmv1", "CP/M v1" ) // not working + ROMX_LOAD("hc2000c.v1", 0x0000,0x4000, CRC(aaa373fe) SHA1(55a30d99c37c86c55ce6c8ecbe593b81d9819e90), ROM_BIOS(2)) + ROM_SYSTEM_BIOS( 3, "cpmv2", "CP/M v2" ) // not working, data arranged differently to v1 + ROMX_LOAD("hc2000c.v2", 0x0000,0x2000, CRC(69c757fe) SHA1(c2bcab2398fb493a31cf6c18ff1e4e9f55690d41), ROM_BIOS(3)) + ROM_REGION(0x8000,"opt",0) // Interface 1 roms + ROM_LOAD_OPTIONAL("hc2000i.v12", 0x4000, 0x4000, CRC(182d5c0c) SHA1(b76d2bebcd938238f790e395859d0d237637d33e)) // 190892 v1, v2 pcb + ROM_LOAD_OPTIONAL("hc2000i.vx", 0x0000, 0x4000, CRC(39967a21) SHA1(e190001ae318982ed31f6c02b4201ca9126a739a)) // 221191 unknown pcb ver +ROM_END + ROM_START(cip03) ROM_REGION(0x10000,"maincpu",0) ROM_LOAD("cip03.rom",0x0000,0x4000, CRC(c7d0cd3c) SHA1(811055b44fc74076137e2bf8db206b2a70287cc2)) @@ -964,7 +992,7 @@ ROM_START(jet) ROM_LOAD("jet.rom",0x0000,0x4000, CRC(e56a7d11) SHA1(e76be9ee71bae6aa1c2ff969276fb599ed68cb50)) ROM_END -ROM_START( cobrasp ) +ROM_START(cobrasp) ROM_REGION( 0x10000, "maincpu", ROMREGION_ERASEFF ) ROM_SYSTEM_BIOS(0, "v1", "V1") ROMX_LOAD( "boot64k_v1.bin", 0x0000, 0x0800, CRC(a54aae6d) SHA1(8f5134ce24aea59065ed166ad79e864e17ce812f), ROM_BIOS(0)) @@ -972,7 +1000,7 @@ ROM_START( cobrasp ) ROMX_LOAD( "boot64k_v2.bin", 0x0000, 0x0800, CRC(ee91cc89) SHA1(37dea7fe0734068adf99b91fdcbf3119095c350d), ROM_BIOS(1)) ROM_END -ROM_START( cobra80 ) +ROM_START(cobra80) ROM_REGION( 0x10000, "maincpu", ROMREGION_ERASEFF ) ROM_SYSTEM_BIOS(0, "v1", "V1") ROMX_LOAD( "boot80k_v1.bin", 0x0000, 0x0800, CRC(f42d2342) SHA1(8aa1b3b056e311674a051ffc6a49af60cae409f3), ROM_BIOS(0)) @@ -1040,7 +1068,7 @@ ROM_END /* Russian clones */ -ROM_START( bk08 ) +ROM_START(bk08) ROM_REGION(0x10000,"maincpu",0) ROM_LOAD( "right.bin", 0x0000, 0x2000, CRC(fb253544) SHA1(6b79487e3013d0acdea8d224b21c937e88105a2f) ) ROM_LOAD( "left.bin", 0x2000, 0x2000, CRC(a092b5f3) SHA1(06b8d98a398f61daf6604c68bcee4596c283c2cd) ) @@ -1106,6 +1134,7 @@ COMP( 1985, hc85, spectrum, 0, spectrum_clone, spectrum, spectrum_stat COMP( 1988, hc88, spectrum, 0, spectrum_clone, spectrum, spectrum_state, init_spectrum, "ICE-Felix", "HC-88", MACHINE_NOT_WORKING ) COMP( 1990, hc90, spectrum, 0, spectrum_clone, spectrum, spectrum_state, init_spectrum, "ICE-Felix", "HC-90", 0 ) COMP( 1991, hc91, spectrum, 0, spectrum_clone, spec_plus, spectrum_state, init_spectrum, "ICE-Felix", "HC-91", 0 ) +COMP( 1992, hc2000, spectrum, 0, spectrum_clone, spec_plus, spectrum_state, init_spectrum, "ICE-Felix", "HC-2000", MACHINE_NOT_WORKING ) // dual-os, only BASIC roms working COMP( 1988, cobrasp, spectrum, 0, spectrum_clone, spectrum, spectrum_state, init_spectrum, "ITCI", "Cobra (ITCI)", MACHINE_NOT_WORKING ) COMP( 1988, cobra80, spectrum, 0, spectrum_clone, spectrum, spectrum_state, init_spectrum, "ITCI", "Cobra 80K (ITCI)", MACHINE_NOT_WORKING ) COMP( 1987, cip01, spectrum, 0, spectrum_clone, spectrum, spectrum_state, init_spectrum, "Electronica", "CIP-01", 0 ) // keyboard should be spectrum, but image was not clear diff --git a/src/mame/drivers/timex.cpp b/src/mame/drivers/timex.cpp index 6709d06a5e9..220963536fd 100644 --- a/src/mame/drivers/timex.cpp +++ b/src/mame/drivers/timex.cpp @@ -530,7 +530,7 @@ void ts2068_state::ts2068_io(address_map &map) map(0xf4, 0xf4).rw(FUNC(ts2068_state::port_f4_r), FUNC(ts2068_state::port_f4_w)).mirror(0xff00); map(0xf5, 0xf5).w("ay8912", FUNC(ay8910_device::address_w)).mirror(0xff00); map(0xf6, 0xf6).rw("ay8912", FUNC(ay8910_device::data_r), FUNC(ay8910_device::data_w)).mirror(0xff00); - map(0xfe, 0xfe).rw(FUNC(ts2068_state::spectrum_port_fe_r), FUNC(ts2068_state::spectrum_port_fe_w)).select(0xff00); + map(0xfe, 0xfe).rw(FUNC(ts2068_state::spectrum_ula_r), FUNC(ts2068_state::spectrum_ula_w)).select(0xff00); map(0xff, 0xff).rw(FUNC(ts2068_state::port_ff_r), FUNC(ts2068_state::port_ff_w)).mirror(0xff00); } @@ -573,7 +573,7 @@ void tc2048_state::port_ff_w(offs_t offset, uint8_t data) void tc2048_state::tc2048_io(address_map &map) { - map(0x00, 0x00).rw(FUNC(tc2048_state::spectrum_port_fe_r), FUNC(tc2048_state::spectrum_port_fe_w)).select(0xfffe); + map(0x00, 0x00).rw(FUNC(tc2048_state::spectrum_ula_r), FUNC(tc2048_state::spectrum_ula_w)).select(0xfffe); map(0xff, 0xff).rw(FUNC(tc2048_state::port_ff_r), FUNC(tc2048_state::port_ff_w)).mirror(0xff00); } diff --git a/src/mame/drivers/tsconf.cpp b/src/mame/drivers/tsconf.cpp index 2819b467bbb..926fb4fc9b8 100644 --- a/src/mame/drivers/tsconf.cpp +++ b/src/mame/drivers/tsconf.cpp @@ -122,7 +122,7 @@ void tsconf_state::tsconf_io(address_map &map) map(0x0077, 0x0077).mirror(0xff00).rw(FUNC(tsconf_state::tsconf_port_77_zctr_r), FUNC(tsconf_state::tsconf_port_77_zctr_w)); // spi data map(0x005f, 0x005f).mirror(0xff00).rw(m_beta, FUNC(beta_disk_device::sector_r), FUNC(beta_disk_device::sector_w)); map(0x007f, 0x007f).mirror(0xff00).rw(m_beta, FUNC(beta_disk_device::data_r), FUNC(beta_disk_device::data_w)); - map(0x00fe, 0x00fe).select(0xff00).rw(FUNC(tsconf_state::spectrum_port_fe_r), FUNC(tsconf_state::tsconf_port_fe_w)); + map(0x00fe, 0x00fe).select(0xff00).rw(FUNC(tsconf_state::spectrum_ula_r), FUNC(tsconf_state::tsconf_port_fe_w)); map(0x00ff, 0x00ff).mirror(0xff00).rw(m_beta, FUNC(beta_disk_device::state_r), FUNC(beta_disk_device::param_w)); map(0x00af, 0x00af).select(0xff00).rw(FUNC(tsconf_state::tsconf_port_xxaf_r), FUNC(tsconf_state::tsconf_port_xxaf_w)); map(0x8ff7, 0x8ff7).select(0x7000).w(FUNC(tsconf_state::tsconf_port_f7_w)); // 3:bff7 5:dff7 6:eff7 diff --git a/src/mame/includes/specpls3.h b/src/mame/includes/specpls3.h index 1464e4d6505..848d6342212 100644 --- a/src/mame/includes/specpls3.h +++ b/src/mame/includes/specpls3.h @@ -36,11 +36,11 @@ protected: private: void bank1_w(offs_t offset, uint8_t data); uint8_t bank1_r(offs_t offset); - void port_3ffd_w(uint8_t data); + void port_3ffd_w(offs_t offset, uint8_t data); uint8_t port_3ffd_r(); uint8_t port_2ffd_r(); - void port_7ffd_w(uint8_t data); - void port_1ffd_w(uint8_t data); + void port_7ffd_w(offs_t offset, uint8_t data); + void port_1ffd_w(offs_t offset, uint8_t data); void plus3_us_w(uint8_t data); void plus3_io(address_map &map); diff --git a/src/mame/includes/spectrum.h b/src/mame/includes/spectrum.h index e25dfc5c5b5..6248a21653a 100644 --- a/src/mame/includes/spectrum.h +++ b/src/mame/includes/spectrum.h @@ -153,10 +153,12 @@ protected: uint8_t spectrum_data_r(offs_t offset); void spectrum_data_w(offs_t offset, uint8_t data); - void spectrum_port_fe_w(offs_t offset, uint8_t data); - uint8_t spectrum_port_fe_r(offs_t offset); - uint8_t spectrum_port_ula_r(offs_t offset); - uint8_t spectrum_clone_port_ula_r(); + void spectrum_ula_w(offs_t offset, uint8_t data); + uint8_t spectrum_ula_r(offs_t offset); + void spectrum_port_w(offs_t offset, uint8_t data); + virtual uint8_t spectrum_port_r(offs_t offset); + virtual uint8_t floating_bus_r(); + uint8_t spectrum_clone_port_r(offs_t offset); void spectrum_palette(palette_device &palette) const; virtual uint32_t screen_update_spectrum(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); @@ -238,8 +240,6 @@ protected: void log_quickload(const char *type, uint32_t start, uint32_t length, uint32_t exec, const char *exec_format); void setup_scr(uint8_t *quickdata, uint32_t quicksize); void setup_raw(uint8_t *quickdata, uint32_t quicksize); - - uint8_t floating_bus_r(); }; class spectrum_128_state : public spectrum_state @@ -262,7 +262,9 @@ private: void spectrum_128_bank1_w(offs_t offset, uint8_t data); uint8_t spectrum_128_bank1_r(offs_t offset); void spectrum_128_port_7ffd_w(offs_t offset, uint8_t data); - uint8_t spectrum_128_ula_r(); + virtual uint8_t spectrum_port_r(offs_t offset) override; + virtual uint8_t floating_bus_r() override; + //uint8_t spectrum_128_ula_r(); void spectrum_128_io(address_map &map); void spectrum_128_mem(address_map &map); diff --git a/src/mame/machine/tsconf.cpp b/src/mame/machine/tsconf.cpp index 98cf851d4aa..1b35f167878 100644 --- a/src/mame/machine/tsconf.cpp +++ b/src/mame/machine/tsconf.cpp @@ -336,7 +336,7 @@ void tsconf_state::tsconf_port_7ffd_w(u8 data) void tsconf_state::tsconf_port_fe_w(offs_t offset, u8 data) { m_regs[BORDER] = (data & 0x07) | 0xf0; - spectrum_port_fe_w(offset, data); + spectrum_ula_w(offset, data); } u8 tsconf_state::tsconf_port_xxaf_r(offs_t port) diff --git a/src/mame/mame.lst b/src/mame/mame.lst index 28f8dfc9afe..59550995d87 100644 --- a/src/mame/mame.lst +++ b/src/mame/mame.lst @@ -39196,7 +39196,6 @@ spdodgeb // TA-0022 (c) 1987 @source:spec128.cpp hc128 // 1991 HC-128 -hc2000 // 1992 HC-2000 spec128 // 1986 ZX Spectrum 128 specpls2 // 1986 ZX Spectrum +2 @@ -39243,6 +39242,7 @@ didakm92 // 1992 Didaktik M 92 didakm93 // 1993 Didaktik M 93 didakt90 // 1990 Didaktik Skalica 90 didaktk // 1992 Didaktik Kompakt +hc2000 // 1992 HC-2000 hc85 // 1985 HC-85 hc88 // 1988 HC-88 hc90 // 1990 HC-90