diff options
author | Tom <37988779+TwistedTom@users.noreply.github.com> | 2019-11-21 15:52:10 +0000 |
---|---|---|
committer | Vas Crabb <cuavas@users.noreply.github.com> | 2019-11-22 02:52:10 +1100 |
commit | b4003648241f11e79808dba23e9c2db2c782d3f7 (patch) | |
tree | 4aa4b956be3bc7785ab43e703bee7afd0f71a793 /src | |
parent | c38f63c10afec9cd90ba48514a180344cb005762 (diff) |
new working ZX Spectrum slot devices: DISCiPLE and +D disk interfaces (#5931)
* plusd working (rom patch)
* plusd done
* added disciple, not working
* disciple working
* wd_fdc fix
* final tidy-up
* ready for pr
* Pernod70 changes
* cuavas changes #1
* combine devices + files
* sort out side_effects
Diffstat (limited to 'src')
-rw-r--r-- | src/devices/bus/spectrum/exp.cpp | 8 | ||||
-rw-r--r-- | src/devices/bus/spectrum/mgt.cpp | 677 | ||||
-rw-r--r-- | src/devices/bus/spectrum/mgt.h | 103 | ||||
-rw-r--r-- | src/devices/machine/wd_fdc.cpp | 8 | ||||
-rw-r--r-- | src/devices/machine/wd_fdc.h | 1 | ||||
-rw-r--r-- | src/lib/formats/coupedsk.cpp | 2 |
6 files changed, 794 insertions, 5 deletions
diff --git a/src/devices/bus/spectrum/exp.cpp b/src/devices/bus/spectrum/exp.cpp index e8890d824b9..160b4500eaf 100644 --- a/src/devices/bus/spectrum/exp.cpp +++ b/src/devices/bus/spectrum/exp.cpp @@ -156,17 +156,16 @@ void spectrum_expansion_slot_device::mreq_w(offs_t offset, uint8_t data) // slot devices #include "beta.h" #include "beta128.h" -//#include "disciple.h" #include "intf1.h" #include "intf2.h" #include "fuller.h" #include "kempjoy.h" #include "melodik.h" #include "mface.h" +#include "mgt.h" #include "mikroplus.h" #include "opus.h" #include "plus2test.h" -//#include "plusd.h" #include "protek.h" #include "specdrum.h" #include "uslot.h" @@ -180,7 +179,7 @@ void spectrum_expansion_devices(device_slot_interface &device) device.option_add("betav3", SPECTRUM_BETAV3); device.option_add("betaplus", SPECTRUM_BETAPLUS); device.option_add("beta128", SPECTRUM_BETA128); - //device.option_add("disciple", SPECTRUM_DISCIPLE); + device.option_add("disciple", SPECTRUM_DISCIPLE); device.option_add("intf1", SPECTRUM_INTF1); device.option_add("intf2", SPECTRUM_INTF2); device.option_add("fuller", SPECTRUM_FULLER); @@ -191,7 +190,7 @@ void spectrum_expansion_devices(device_slot_interface &device) device.option_add("mikroplus", SPECTRUM_MIKROPLUS); device.option_add("mprint", SPECTRUM_MPRINT); device.option_add("opus", SPECTRUM_OPUS); - //device.option_add("plusd", SPECTRUM_PLUSD); + device.option_add("plusd", SPECTRUM_PLUSD); device.option_add("protek", SPECTRUM_PROTEK); device.option_add("specdrum", SPECTRUM_SPECDRUM); device.option_add("uslot", SPECTRUM_USLOT); @@ -211,6 +210,7 @@ void spec128_expansion_devices(device_slot_interface &device) device.option_add("mikroplus", SPECTRUM_MIKROPLUS); device.option_add("mprint", SPECTRUM_MPRINT); device.option_add("opus", SPECTRUM_OPUS); + //device.option_add("plusd", SPECTRUM_PLUSD); device.option_add("plus2test", SPECTRUM_PLUS2TEST); device.option_add("protek", SPECTRUM_PROTEK); device.option_add("specdrum", SPECTRUM_SPECDRUM); diff --git a/src/devices/bus/spectrum/mgt.cpp b/src/devices/bus/spectrum/mgt.cpp new file mode 100644 index 00000000000..6d3abff690e --- /dev/null +++ b/src/devices/bus/spectrum/mgt.cpp @@ -0,0 +1,677 @@ +// license:BSD-3-Clause +// copyright-holders:TwistedTom +/********************************************************************** + + DISCiPLE Multi-purpose Interface + +D Disk and Printer Interface + + Miles Gordon Technology, UK, 1986-1990 (also produced the Sam Coupé home computer.) + + DISCiPLE was MGT's first disk interface, a large plastic base that sat under the Spectrum, similar to Sinclair's official Interface 1. + +D was MGT's second (and last) disk interface, a cost and feature reduced version of the Disciple, a small metal-cased, + stand-alone unit which connects to ZX Spectrum's expansion slot via a ribbon cable. + A second Datel version of the +D exists (following the closure of MGT, it was licensed and produced by Datel.) + Many unofficial versions of +D exist and modern versions are still seen today as DIY-style projects/kits. + It's said the device's design and roms were officially released into the public domain at some point? + + DISCiPLE features: + 8KB ROM + 8KB RAM + single floppy disk interface (2 drives) + Centronics parallel printer interface + "magic button" style memory snapshot grabber + 2 ATARI joystick ports (Sinclair 1/Kempston, Sinclair 2) + 2 network connectors (Interface 1 compatible, 3.5mm mono jack) + inhibit button (to lock out the interface) + pass-through expansion connector (to chain other devices) + + +D features: + same as DISCiPLE + lost the joystick/network ports, inhibit button and pass-through expansion connector + + DISCiPLE's official DOS was "GDOS". + +D's official DOS was "G+DOS". + Both of these were later superseded by "SAM DOS" (used by MGT's Sam Coupé.) + A 3rd party company SD Software released an alternative DOS "UNI-DOS" for both interfaces. (consisting of a disk and replacement ROM) + + FDD support: + + DISCiPLE's manual states any Shugart 400 SD/DD drive should work: + "The disciple will accept 5.25" or 3.5" drives, whether they are 40 track or 80 track, + single sided or double sided, single density or double density." + + +D's manual states any Shugart 400 DD drive should work (but not SD) + "we recommend 3.5" or 5.25" 80-track double sided and double density drives, + which will give you up to 780K of storage per drive. But Shugart + 400-type 3" drives will also work." + + +D only: Pin 26 /DDEN of the WD1772 is tied to ground, so permanent DD mode. + DISCiPLE only: /DDEN can be directly controlled via s/w by an IO write to 0x1f, bit 2. + + Disks use "MGT filesystem". + A good description available at https://faqwiki.zxnet.co.uk/wiki/MGT_filesystem + + Disk format is 512 bytes/sector, 10 sectors/track + 40 track, 1 side = 204,800 bytes (512*10*40*1) + 40 track, 2 side = 409,600 bytes + 80 track, 1 side = 409,600 bytes + 80 track, 2 side = 819,200 bytes <-- only this one supported so far + + .mgt files work ok + .img files don't work (not in coupedsk.cpp) + + The DOS must be loaded from a "System Disk" which is itself created from "System Tape" which was supplied with the unit. + The ROM provides just the RUN command, which boots the system disk and loads the full DOS. + Presumably the unit wasn't supplied with a system disk due to wide range of drives that can be used? (3", 3.5", 5.25") + The DOS survives a reset, so reloading of system disk is only required after full power cycle. + + A few useful commands: + RUN Boots the system + CAT 1 Displays catalogue (drive 1) + CAT 1! Displays shortened catalogue (drive 1) + SAVE D1 "filename" Saves file + VERIFY D1 "filename" Confirms save has been made + LOAD D1 "filename" Loads file (except Snapshot files) + LOAD D1 "filename" S Loads 48K Snapshot file + LOAD D1 "filename" K Loads 128K Snapshot file + LOAD D1 "filename" SCREEN$ Loads screen file + LOAD Pn Loads the program (from its number) + ERASE D1 "file" TO "new file" Renames a file + ERASE D1 "filename" Erases a file + SAVE D1 "file" TO D2 Copies a file from drive1 to drive2 + FORMAT D1 Formats disc in drive 1 + FORMAT D1 TO 2 Formats drive 1; copies from 2 to 1 + + DISCiPLE snapshot button: + Caps Shift + button system freezes with a multi-coloured border effect + then, key 3 save current SCREEN + 4 save 48K PROGRAM + 5 save 128K PROGRAM + Caps Shift + number saves to drive 2 (or 1 if running from 2) + + +D snapshot button: + button system freezes with a multi-coloured border effect (don't need to hold caps shift) + then, key 3 save current SCREEN + 4 save 48K PROGRAM + 5 save 128K PROGRAM + X do nothing, return to running program + Caps Shift + number saves to drive 2 (or 1 if running from 2) + + DISCiPLE GDOS versions: + The rom/system disk versions must match, + v2 rom: use system disk/system tape ver 2, 2b, 2c + v3 rom: use system disk/system tape ver 3a, 3b or 3d + + +D G+DOS versions: + a v1 (-non a) exists but has yet to be found/dumped, + from "pick-poke-it" user manual: + "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." + + DISCiPLE only curiosities: + The pass-through expansion connector has 4 extra pins (1 top/bottom each end) + so 2x30 pins compared to ususal 2x28 of Spectrum expansion slot. + Presumably this was intended for some unique expansion device that never appeared? + One of these extra pins can be directly controlled via s/w by an IO write to 0x1f, bit 5. + 2 other pins appear to be able to override the /ce signal from PAL ic9 to the rom. + 4th pin is unused. + + The design allows for use of a larger 27128 (16KB) rom, + with the highest address line A13 controllable via s/w by an IO write to 0x1f, bit 3. + No larger roms seem to exist (or perhaps not yet found...?) + Some 16KB dumps can be found but these are combined dumps of the 8KB rom and 8KB ram (with the full DOS loaded). + + + Current status: + -------------- + + DISCiPLE + GDOS v3: all ok, occassional "no system file" when loading system disk, ok on 2nd attempt + GDOS v2: all ok + UNIDOS: all ok + + +D + G+DOS: all ok + UNIDOS: all ok + + + Not working with 128K/+2 yet... + +**********************************************************************/ + + +#include "emu.h" +#include "mgt.h" + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +DEFINE_DEVICE_TYPE(SPECTRUM_PLUSD, spectrum_plusd_device, "spectrum_plusd", "MGT +D") +DEFINE_DEVICE_TYPE(SPECTRUM_DISCIPLE, spectrum_disciple_device, "spectrum_disciple", "MGT DISCiPLE") + +//------------------------------------------------- +// INPUT_PORTS( plusd ) +//------------------------------------------------- + +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) +INPUT_PORTS_END + +//------------------------------------------------- +// INPUT_PORTS( disciple ) +//------------------------------------------------- + +INPUT_PORTS_START(disciple) + PORT_INCLUDE(plusd) + + // Joystick 1 (right-hand) is both Kempston (port 0x1f) and Sinclair 1 (keys 6,7,8,9,0) + // Joystick 2 (left-hand) is Sinclair 2 (keys 1,2,3,4,5) + + PORT_START("JOY1") /* Sinclair 1 (keys 6,7,8,9,0) 0xeffe , Kempston 0x1f */ + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_BUTTON1) PORT_PLAYER(1) PORT_NAME("Kempston\\Sinclair P1 Button 1") + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_UP) PORT_8WAY PORT_PLAYER(1) PORT_NAME("Kempston\\Sinclair P1 Up") + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN) PORT_8WAY PORT_PLAYER(1) PORT_NAME("Kempston\\Sinclair P1 Down") + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT) PORT_8WAY PORT_PLAYER(1) PORT_NAME("Kempston\\Sinclair P1 Right") + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT) PORT_8WAY PORT_PLAYER(1) PORT_NAME("Kempston\\Sinclair P1 Left") + + PORT_START("JOY2") /* Sinclair 2 (keys 1,2,3,4,5) 0xf7fe */ + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT) PORT_8WAY PORT_PLAYER(2) PORT_NAME("Sinclair P2 Left") PORT_CODE(KEYCODE_4_PAD) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT) PORT_8WAY PORT_PLAYER(2) PORT_NAME("Sinclair P2 Right") PORT_CODE(KEYCODE_6_PAD) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN) PORT_8WAY PORT_PLAYER(2) PORT_NAME("Sinclair P2 Down") PORT_CODE(KEYCODE_2_PAD) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_UP) PORT_8WAY PORT_PLAYER(2) PORT_NAME("Sinclair P2 Up") PORT_CODE(KEYCODE_8_PAD) + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_BUTTON1) PORT_PLAYER(2) PORT_NAME("Sinclair P2 Button 1") PORT_CODE(KEYCODE_0_PAD) +INPUT_PORTS_END + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor spectrum_plusd_device::device_input_ports() const +{ + return INPUT_PORTS_NAME(plusd); +} + +ioport_constructor spectrum_disciple_device::device_input_ports() const +{ + return INPUT_PORTS_NAME(disciple); +} + +//------------------------------------------------- +// SLOT_INTERFACE( plusd_floppies ) +//------------------------------------------------- + +static void plusd_floppies(device_slot_interface &device) +{ + device.option_add("35dd", FLOPPY_35_DD); +} + +//------------------------------------------------- +// floppy_format_type floppy_formats +//------------------------------------------------- + +FLOPPY_FORMATS_MEMBER(spectrum_plusd_device::floppy_formats) + FLOPPY_MGT_FORMAT +FLOPPY_FORMATS_END + +//------------------------------------------------- +// ROM( plusd ) +//------------------------------------------------- + +ROM_START(plusd) + ROM_REGION(0x2000, "rom", 0) + + ROM_DEFAULT_BIOS("gdos") + + ROM_SYSTEM_BIOS(0, "gdos", "G+DOS v1a") + ROMX_LOAD("plusd_g.rom", 0x0000, 0x2000, CRC(569f7e55) SHA1(6b841dc5797ef7eb219ad455cd1e434ca3b9d30d), ROM_BIOS(0)) + + ROM_SYSTEM_BIOS(1, "unidos", "UNI-DOS v2") + ROMX_LOAD("plusd_uni.rom", 0x0000, 0x2000, CRC(60920496) SHA1(399c8c7c8335bc59849a2182c32347603fd0288a), ROM_BIOS(1)) + + ROM_REGION( 0x200, "plds", 0 ) + ROM_LOAD( "alice_pal20l8.ic4", 0x000, 0x144, CRC(60135856) SHA1(41273f13a3680b29ba84ae1e85829482c783c55e) ) +ROM_END + +//------------------------------------------------- +// ROM( disciple ) +//------------------------------------------------- + +ROM_START(disciple) + ROM_REGION(0x2000, "rom", 0) + + ROM_DEFAULT_BIOS("gdos") + + ROM_SYSTEM_BIOS(0, "gdos", "GDOS v3") + ROMX_LOAD("disciple_g.rom", 0x0000, 0x2000, CRC(82047489) SHA1(9a75ed4b293f968985be4c9aa893cd88276d1ced), ROM_BIOS(0)) + + ROM_SYSTEM_BIOS(1, "gdos2", "GDOS v2") + ROMX_LOAD("disciple_g2.rom", 0x0000, 0x2000, CRC(9d971781) SHA1(a03e67e4ee275a85153843f42269fa980875d551), ROM_BIOS(1)) + + ROM_SYSTEM_BIOS(2, "unidos", "UNI-DOS v2") + ROMX_LOAD("disciple_uni.rom", 0x0000, 0x2000, CRC(1fe7f4fa) SHA1(6277abe6358c99ab894795536a1eb9393f25b9b1), ROM_BIOS(2)) + + ROM_REGION( 0x400, "plds", 0 ) + ROM_LOAD( "pal20l8.ic8", 0x000, 0x144, CRC(e53b2fcc) SHA1(85ce9634890d41be37cd9e0252698e5350a4c9c9) ) + ROM_LOAD( "pal20l8.ic9", 0x200, 0x144, CRC(43ff2e38) SHA1(b872377ea9f91b29a811b0d484699ffe87bdf9fd) ) +ROM_END + +//------------------------------------------------- +// device_add_mconfig - add device configuration +//------------------------------------------------- + +void spectrum_plusd_device::device_add_mconfig(machine_config &config) +{ + WD1772(config, m_fdc, 8_MHz_XTAL); + FLOPPY_CONNECTOR(config, "fdc:0", plusd_floppies, "35dd", spectrum_plusd_device::floppy_formats).enable_sound(true); + FLOPPY_CONNECTOR(config, "fdc:1", plusd_floppies, "35dd", spectrum_plusd_device::floppy_formats).enable_sound(true); + + /* printer port */ + CENTRONICS(config, m_centronics, centronics_devices, "printer"); + m_centronics->busy_handler().set(FUNC(spectrum_plusd_device::busy_w)); + + /* software list */ + SOFTWARE_LIST(config, "flop_list").set_original("spectrum_mgt_flop"); +} + +void spectrum_disciple_device::device_add_mconfig(machine_config &config) +{ + spectrum_plusd_device::device_add_mconfig(config); + + /* pass-through */ + 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)); +} + +const tiny_rom_entry *spectrum_plusd_device::device_rom_region() const +{ + return ROM_NAME(plusd); +} + +const tiny_rom_entry *spectrum_disciple_device::device_rom_region() const +{ + return ROM_NAME(disciple); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// spectrum_plusd_device - constructor +//------------------------------------------------- + +spectrum_plusd_device::spectrum_plusd_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, type, tag, owner, clock) + , device_spectrum_expansion_interface(mconfig, *this) + , m_rom(*this, "rom") + , m_fdc(*this, "fdc") + , m_floppy(*this, "fdc:%u", 0) + , m_centronics(*this, "centronics") + , m_centronics_busy(false) +{ +} + +spectrum_plusd_device::spectrum_plusd_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : spectrum_plusd_device(mconfig, SPECTRUM_PLUSD, tag, owner, clock) +{ +} + +//------------------------------------------------- +// spectrum_disciple_device - constructor +//------------------------------------------------- + +spectrum_disciple_device::spectrum_disciple_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : spectrum_plusd_device(mconfig, SPECTRUM_DISCIPLE, tag, owner, clock) + , m_exp(*this, "exp") + , m_joy1(*this, "JOY1") + , m_joy2(*this, "JOY2") +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void spectrum_plusd_device::device_start() +{ + std::fill(std::begin(m_ram), std::end(m_ram), 0); + save_item(NAME(m_romcs)); + save_item(NAME(m_ram)); + save_item(NAME(m_centronics_busy)); +} + +void spectrum_disciple_device::device_start() +{ + spectrum_plusd_device::device_start(); + save_item(NAME(m_map)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void spectrum_plusd_device::device_reset() +{ + m_romcs = 0; +} + +void spectrum_disciple_device::device_reset() +{ + spectrum_plusd_device::device_reset(); + m_map = false; +} + +//************************************************************************** +// IMPLEMENTATION spectrum_plusd_device +//************************************************************************** + +READ_LINE_MEMBER(spectrum_plusd_device::romcs) +{ + return m_romcs; +} + +void spectrum_plusd_device::pre_opcode_fetch(offs_t offset) +{ + if (!machine().side_effects_disabled()) + { + switch (offset) + { + case 0x0000: + case 0x0008: + case 0x003a: + case 0x0066: + m_romcs = 1; + break; + } + } +} + +uint8_t spectrum_plusd_device::iorq_r(offs_t offset) +{ + uint8_t data = 0xff; + + switch (offset & 0xff) + { + case 0xe3: // fdc status reg + case 0xeb: // fdc track reg + case 0xf3: // fdc sector reg + case 0xfb: // fdc data reg + data = m_fdc->read((offset >> 3) & 0x03); + break; + case 0xe7: // page in + if (!machine().side_effects_disabled()) + m_romcs = 1; + break; + case 0xf7: // bit 7: printer busy + data = m_centronics_busy ? 0x80 : 0x00; + break; + } + + return data; +} + +void spectrum_plusd_device::iorq_w(offs_t offset, uint8_t data) +{ + switch (offset & 0xff) + { + case 0xe3: // fdc command reg + case 0xeb: // fdc track reg + case 0xf3: // fdc sector reg + case 0xfb: // fdc data reg + m_fdc->write((offset >> 3) & 0x03, data); + break; + case 0xef: // bit 0-1: drive select, 6: printer strobe, 7: side select + { + uint8_t drive = data & 3; + floppy_image_device* floppy = m_floppy[drive > 0 ? drive-1 : drive]->get_device(); + m_fdc->set_floppy(floppy); + m_centronics->write_strobe(BIT(data, 6)); + if (floppy) floppy->ss_w(BIT(data, 7)); + } + break; + case 0xe7: // page out + m_romcs = 0; + break; + case 0xf7: // printer data + 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)); + break; + } +} + +uint8_t spectrum_plusd_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 & 0x1fff]; + break; + } + } + + return data; +} + +void spectrum_plusd_device::mreq_w(offs_t offset, uint8_t data) +{ + if (m_romcs) + { + switch (offset & 0xe000) + { + case 0x2000: + m_ram[offset & 0x1fff] = data; + break; + } + } +} + +INPUT_CHANGED_MEMBER(spectrum_plusd_device::snapshot_button) +{ + if (newval && !oldval) + { + m_slot->nmi_w(CLEAR_LINE); + } + else + { + m_slot->nmi_w(ASSERT_LINE); + } +} + +WRITE_LINE_MEMBER(spectrum_plusd_device::busy_w) +{ + m_centronics_busy = state; +} + +//************************************************************************** +// IMPLEMENTATION spectrum_disciple_device +//************************************************************************** + +READ_LINE_MEMBER(spectrum_disciple_device::romcs) +{ + return m_romcs | m_exp->romcs(); +} + +void spectrum_disciple_device::pre_opcode_fetch(offs_t offset) +{ + m_exp->pre_opcode_fetch(offset); + + if (!machine().side_effects_disabled()) + { + switch (offset) + { + case 0x0000: + case 0x0008: + case 0x0066: + case 0x028e: + m_romcs = 1; + break; + } + } +} + +uint8_t spectrum_disciple_device::iorq_r(offs_t offset) +{ + uint8_t data = m_exp->iorq_r(offset); + + switch (offset & 0xff) + { + case 0x1b: // fdc status reg + case 0x5b: // fdc track reg + case 0x9b: // fdc sector reg + case 0xdb: // fdc data reg + data = m_fdc->read((offset >> 6) & 0x03); + break; + case 0x1f: // bit 0-4: kempston joystick, bit 6: printer busy, bit 7: network + data = bitswap<8>(~m_joy1->read(), 7, 6, 5, 0, 1, 2, 4, 3 ) & 0x1f; + data |= m_centronics_busy ? 0x00 : 0x40; // inverted by IC10 74ls240 + // 7: network... + break; + case 0x7b: // reset boot + if (!machine().side_effects_disabled()) + m_map = false; + break; + case 0xbb: // page in + if (!machine().side_effects_disabled()) + m_romcs = 1; + break; + case 0xfe: // sinclair joysticks + if (((offset >> 8) & 16) == 0) + data = m_joy1->read() | (0xff ^ 0x1f); + if (((offset >> 8) & 8) == 0) + data = m_joy2->read() | (0xff ^ 0x1f); + break; + } + + return data; +} + +void spectrum_disciple_device::iorq_w(offs_t offset, uint8_t data) +{ + switch (offset & 0xff) + { + case 0x1b: // fdc command reg + case 0x5b: // fdc track reg + case 0x9b: // fdc sector reg + case 0xdb: // fdc data reg + m_fdc->write((offset >> 6) & 0x03, data); + break; + case 0x1f: // bit 0: drive select, 1: side select, 2: density, 3: rom bank, 4: inhibit switch control, 5: exp select, 6: printer strobe, 7: network + { + floppy_image_device* floppy = m_floppy[~data & 1]->get_device(); + m_fdc->set_floppy(floppy); + if (floppy) floppy->ss_w(BIT(data, 1)); + m_fdc->dden_w(BIT(data, 2)); + // 3: rom bank... + // 4: inhibit switch control... + // 5: exp select... + m_centronics->write_strobe(BIT(data, 6)); + // 7: network... + } + break; + case 0x3b: // wait when net=1 + // ... + break; + case 0x7b: // set boot + m_map = true; + break; + case 0xbb: // page out + m_romcs = 0; + break; + case 0xfb: // printer data + 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)); + break; + } + + m_exp->iorq_w(offset, data); +} + +uint8_t spectrum_disciple_device::mreq_r(offs_t offset) +{ + uint8_t data = 0xff; + + if (m_romcs) + { + if (m_map) + { + switch (offset & 0xe000) + { + case 0x0000: + data = m_ram[offset & 0x1fff]; + break; + case 0x2000: + data = m_rom->base()[offset & 0x1fff]; + break; + } + } + else + { + switch (offset & 0xe000) + { + case 0x0000: + data = m_rom->base()[offset & 0x1fff]; + break; + case 0x2000: + data = m_ram[offset & 0x1fff]; + break; + } + } + } + + if (m_exp->romcs()) + data &= m_exp->mreq_r(offset); + + return data; +} + +void spectrum_disciple_device::mreq_w(offs_t offset, uint8_t data) +{ + if (m_romcs) + { + if (m_map) + { + switch (offset & 0xe000) + { + case 0x0000: + m_ram[offset & 0x1fff] = data; + break; + } + } + else + { + switch (offset & 0xe000) + { + case 0x2000: + m_ram[offset & 0x1fff] = data; + break; + } + } + } + + if (m_exp->romcs()) + m_exp->mreq_w(offset, data); +} diff --git a/src/devices/bus/spectrum/mgt.h b/src/devices/bus/spectrum/mgt.h new file mode 100644 index 00000000000..e87cca4f276 --- /dev/null +++ b/src/devices/bus/spectrum/mgt.h @@ -0,0 +1,103 @@ +// license:BSD-3-Clause +// copyright-holders:TwistedTom +/********************************************************************** + + DISCiPLE Multi-purpose Interface + +D Disk and Printer Interface + + (Miles Gordon Technology) + +**********************************************************************/ + +#ifndef MAME_BUS_SPECTRUM_MGT_H +#define MAME_BUS_SPECTRUM_MGT_H + +#pragma once + +#include "exp.h" +#include "softlist.h" +#include "imagedev/floppy.h" +#include "machine/wd_fdc.h" +#include "bus/centronics/ctronics.h" +#include "formats/coupedsk.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class spectrum_plusd_device: public device_t, public device_spectrum_expansion_interface +{ +public: + // construction/destruction + spectrum_plusd_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); + spectrum_plusd_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + DECLARE_FLOPPY_FORMATS(floppy_formats); + DECLARE_INPUT_CHANGED_MEMBER(snapshot_button); + +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 ioport_constructor device_input_ports() const override; + virtual const tiny_rom_entry *device_rom_region() const override; + + virtual void pre_opcode_fetch(offs_t offset) override; + virtual uint8_t mreq_r(offs_t offset) override; + virtual void mreq_w(offs_t offset, uint8_t data) override; + virtual uint8_t iorq_r(offs_t offset) override; + virtual void iorq_w(offs_t offset, uint8_t data) override; + virtual DECLARE_READ_LINE_MEMBER(romcs) override; + + DECLARE_WRITE_LINE_MEMBER(busy_w); + + required_memory_region m_rom; + required_device<wd_fdc_device_base> m_fdc; + required_device_array<floppy_connector, 2> m_floppy; + required_device<centronics_device> m_centronics; + + int m_romcs; + uint8_t m_ram[8 * 1024]; + bool m_centronics_busy; +}; + +class spectrum_disciple_device: public spectrum_plusd_device +{ +public: + // construction/destruction + spectrum_disciple_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 ioport_constructor device_input_ports() const override; + virtual const tiny_rom_entry *device_rom_region() const override; + + virtual void pre_opcode_fetch(offs_t offset) override; + virtual uint8_t mreq_r(offs_t offset) override; + virtual void mreq_w(offs_t offset, uint8_t data) override; + virtual uint8_t iorq_r(offs_t offset) override; + virtual void iorq_w(offs_t offset, uint8_t data) override; + virtual DECLARE_READ_LINE_MEMBER(romcs) override; + +private: + required_device<spectrum_expansion_slot_device> m_exp; + required_ioport m_joy1; + required_ioport m_joy2; + + bool m_map; +}; + + +// device type definition +DECLARE_DEVICE_TYPE(SPECTRUM_PLUSD, spectrum_plusd_device) +DECLARE_DEVICE_TYPE(SPECTRUM_DISCIPLE, spectrum_disciple_device) + +#endif // MAME_BUS_SPECTRUM_MGT_H diff --git a/src/devices/machine/wd_fdc.cpp b/src/devices/machine/wd_fdc.cpp index 691a7914b10..d2353fd26a5 100644 --- a/src/devices/machine/wd_fdc.cpp +++ b/src/devices/machine/wd_fdc.cpp @@ -91,6 +91,7 @@ wd_fdc_device_base::wd_fdc_device_base(const machine_config &mconfig, device_typ { force_ready = false; disable_motor_control = false; + spinup_on_interrupt = false; } void wd_fdc_device_base::set_force_ready(bool _force_ready) @@ -1122,6 +1123,8 @@ void wd_fdc_device_base::cmd_w(uint8_t val) { // checkme delay_cycles(t_cmd, dden ? delay_register_commit * 2 : delay_register_commit); + if (spinup_on_interrupt) // see note in WD1772 constructor + spinup(); } else { @@ -2895,6 +2898,11 @@ wd1772_device::wd1772_device(const machine_config &mconfig, const char *tag, dev head_control = false; motor_control = true; ready_hooked = false; + + /* Sam Coupe/+D/Disciple expect a 0xd0 force interrupt command to cause a spin-up. + eg. +D issues 2x 0xd0, then waits for index pulses to start, bails out with no disk error if that doesn't happen. + Not sure if other chips should do this too? */ + spinup_on_interrupt = true; } int wd1772_device::settle_time() const diff --git a/src/devices/machine/wd_fdc.h b/src/devices/machine/wd_fdc.h index 038fee362f6..d6b07260078 100644 --- a/src/devices/machine/wd_fdc.h +++ b/src/devices/machine/wd_fdc.h @@ -108,6 +108,7 @@ protected: const int *step_times; int delay_register_commit; int delay_command_commit; + bool spinup_on_interrupt; static constexpr int fd179x_step_times[4] = { 6000, 12000, 20000, 30000 }; static constexpr int fd176x_step_times[4] = { 12000, 24000, 40000, 60000 }; diff --git a/src/lib/formats/coupedsk.cpp b/src/lib/formats/coupedsk.cpp index 803f69bbbb7..045e42b7bb5 100644 --- a/src/lib/formats/coupedsk.cpp +++ b/src/lib/formats/coupedsk.cpp @@ -115,7 +115,7 @@ bool mgt_format::save(io_generic *io, floppy_image *image) for(int head=0; head < 2; head++) { for(int track=0; track < 80; track++) { get_track_data_mfm_pc(track, head, image, 2000, 512, sector_count, sectdata); - io_generic_write(io, sectdata, (head*80 + track)*track_size, track_size); + io_generic_write(io, sectdata, (track*2+head)*track_size, track_size); } } |