summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/bus
diff options
context:
space:
mode:
author Tom <37988779+TwistedTom@users.noreply.github.com>2022-01-25 12:45:31 +0000
committer GitHub <noreply@github.com>2022-01-25 07:45:31 -0500
commiteb3c4e67da37ad807718987671ee1460c583df28 (patch)
tree3028a104178bd702ac97fba2754d752897ad4627 /src/devices/bus
parentaafda14fb1cff3f06ade1166aa5353e74f84bed0 (diff)
zx spectrum: new slot devices, floating bus restore, big mface tidy-up (#7913)
Diffstat (limited to 'src/devices/bus')
-rw-r--r--src/devices/bus/spectrum/beta.cpp1
-rw-r--r--src/devices/bus/spectrum/beta128.cpp1
-rw-r--r--src/devices/bus/spectrum/d40.cpp2
-rw-r--r--src/devices/bus/spectrum/exp.cpp16
-rw-r--r--src/devices/bus/spectrum/exp.h5
-rw-r--r--src/devices/bus/spectrum/floppyone.cpp1
-rw-r--r--src/devices/bus/spectrum/fuller.cpp5
-rw-r--r--src/devices/bus/spectrum/intf1.cpp1
-rw-r--r--src/devices/bus/spectrum/intf2.cpp2
-rw-r--r--src/devices/bus/spectrum/kempdisc.cpp3
-rw-r--r--src/devices/bus/spectrum/kempjoy.cpp4
-rw-r--r--src/devices/bus/spectrum/logitek.cpp2
-rw-r--r--src/devices/bus/spectrum/lprint.cpp9
-rw-r--r--src/devices/bus/spectrum/melodik.cpp3
-rw-r--r--src/devices/bus/spectrum/mface.cpp668
-rw-r--r--src/devices/bus/spectrum/mface.h142
-rw-r--r--src/devices/bus/spectrum/mgt.cpp7
-rw-r--r--src/devices/bus/spectrum/mikroplus.cpp2
-rw-r--r--src/devices/bus/spectrum/mpoker.cpp168
-rw-r--r--src/devices/bus/spectrum/mpoker.h49
-rw-r--r--src/devices/bus/spectrum/opus.cpp3
-rw-r--r--src/devices/bus/spectrum/protek.cpp2
-rw-r--r--src/devices/bus/spectrum/sdi.cpp2
-rw-r--r--src/devices/bus/spectrum/sixword.cpp18
-rw-r--r--src/devices/bus/spectrum/speccydos.cpp1
-rw-r--r--src/devices/bus/spectrum/specmate.cpp190
-rw-r--r--src/devices/bus/spectrum/specmate.h59
-rw-r--r--src/devices/bus/spectrum/uspeech.cpp2
-rw-r--r--src/devices/bus/spectrum/wafa.cpp1
29 files changed, 1242 insertions, 127 deletions
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<device_spectrum_expansion_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_START(mface1v2) // unknown pcb rev (probably <2.0)
+ ROM_REGION(0x2000, "rom", 0)
+ 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_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_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_SYSTEM_BIOS(?, "bc93", "Brazilian clone 93") // NO DUMP?
- ROMX_LOAD("mf1_bc_93.rom", 0x0000, 0x2000, CRC(8c17113b) SHA1(?), ROM_BIOS(?))
-*/
+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(mface128)
+ROM_START(mface128v1)
ROM_REGION(0x2000, "rom", 0)
- ROM_DEFAULT_BIOS("v363c")
+ 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<uint8_t[]>(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<uint8_t[]>(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<uint8_t[]>(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,22 +520,73 @@ 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;
}
}
-uint8_t spectrum_mface1_device::iorq_r(offs_t offset)
+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)
+ switch (offset & 0xff) // real decodes tbc...
{
case 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:
@@ -331,20 +597,71 @@ uint8_t spectrum_mface1_device::iorq_r(offs_t offset)
return data;
}
-uint8_t spectrum_mface128_device::iorq_r(offs_t offset)
+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 0xbf:
+ case 0x12: // 0001 --1- uses 0x1f
+ m_romcs = 0;
+ if (!(m_hwconfig->read() & 0x02))
+ data = m_joy->read() & 0x1f;
+ break;
+ case 0x92: // 1001 --1- uses 0x9f
m_romcs = 1;
break;
- case 0x3f:
+ }
+ }
+ 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 & 0xf4) // -011 -1--
+ {
+ 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)
{
+ 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);
}
- else // key pressed
+}
+
+INPUT_CHANGED_MEMBER(spectrum_mface3_device::magic_button)
+{
+ if (!newval)
{
- m_slot->nmi_w(ASSERT_LINE);
+ 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,21 +48,29 @@ 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<spectrum_expansion_slot_device> m_exp;
- uint8_t m_ram[8 * 1024];
int m_romcs;
+ int m_nmi_pending;
+ std::unique_ptr<uint8_t[]> m_ram;
};
-class spectrum_mface1_device : public spectrum_mface_base_device
+class spectrum_mface1v2_device : public spectrum_mface_base_device
{
public:
- spectrum_mface1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+ 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;
@@ -71,12 +78,95 @@ 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_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);
+
+ DECLARE_INPUT_CHANGED_MEMBER(magic_button) override;
+
+protected:
+ // optional information overrides
+ virtual const tiny_rom_entry *device_rom_region() const override;
+ virtual ioport_constructor device_input_ports() const override;
+
+ virtual uint8_t iorq_r(offs_t offset) override;
+ virtual void iorq_w(offs_t offset, uint8_t data) override;
+};
+
+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<centronics_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<spectrum_expansion_slot_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");
}