diff options
Diffstat (limited to 'src/devices/bus/spectrum/mgt.cpp')
-rw-r--r-- | src/devices/bus/spectrum/mgt.cpp | 725 |
1 files changed, 725 insertions, 0 deletions
diff --git a/src/devices/bus/spectrum/mgt.cpp b/src/devices/bus/spectrum/mgt.cpp new file mode 100644 index 00000000000..b196a88a1f7 --- /dev/null +++ b/src/devices/bus/spectrum/mgt.cpp @@ -0,0 +1,725 @@ +// 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: + The rom/system disk versions must match, + v1 rom: system disk/system tape ver 1 + v1a rom: system disk/system tape ver 2a + + +D only curiosities: + The earliest v1.0 unit has a very crude pcb (no solder resist or silkscreen markings), + has various rework modifications (cut tracks, flying wires, piggy-backed chips etc.), + 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 (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." + + 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 + GDOS v2: all ok + UNIDOS: all ok + + +D + G+DOS: all ok + UNIDOS: all ok + + + DISCiPLE and 128K compatibility notes: + there is some magic involved and its still not clear how exactly it boots on 128K (but it was confirmed to work on real hardware), + currently we assume paging in cannot be triggered for a while after reset. + +**********************************************************************/ + +#include "emu.h" +#include "mgt.h" +#include "softlist_dev.h" + +#include "formats/coupedsk.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_MINUS_PAD) PORT_CHANGED_MEMBER(DEVICE_SELF, FUNC(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) + + PORT_START("INH") + PORT_CONFNAME(0x01, 0x01, "Inhibit Button") PORT_CHANGED_MEMBER(DEVICE_SELF, FUNC(spectrum_disciple_device::inhibit_button), 0) + PORT_CONFSETTING(0x01, "Off (Disciple enabled)") + PORT_CONFSETTING(0x00, "On (Disciple disabled)") +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_formats +//------------------------------------------------- + +void spectrum_plusd_device::floppy_formats(format_registration &fr) +{ + fr.add_mfm_containers(); + fr.add(FLOPPY_MGT_FORMAT); +} + +//------------------------------------------------- +// 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_SYSTEM_BIOS(2, "gdos1", "G+DOS v1") + ROMX_LOAD("plusd_g1.rom", 0x0000, 0x2000, CRC(e29c0d41) SHA1(fd7e4557d0080a3532200ce72211eb1b185d7d0a), ROM_BIOS(2)) + + ROM_REGION( 0x400, "plds", 0 ) + ROM_LOAD( "alice_pal20l8.ic4", 0x000, 0x144, CRC(60135856) SHA1(41273f13a3680b29ba84ae1e85829482c783c55e) ) + ROM_LOAD( "v1_pal16l6.icx", 0x200, 0x157, CRC(77076102) SHA1(5142068ae01ff29979b08e6b322512750fbc6a04) ) // v1.0 pcb, ic ref unknown (no silkscreen on pcb!), gal20v8 target +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)); + 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 +{ + 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") + , m_inhibit(*this, "INH") + , m_control(0) // CHECKME: what is 74LS374 power-on state ? +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void spectrum_plusd_device::device_start() +{ + m_romcs = 0; + 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)); + save_item(NAME(m_control)); + save_item(NAME(m_reset_delay)); + + m_reset_timer = timer_alloc(FUNC(spectrum_disciple_device::reset_tick), this); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void spectrum_plusd_device::device_reset() +{ + m_centronics->write_strobe(0); +} + +void spectrum_disciple_device::device_reset() +{ + m_romcs = 0; + m_map = false; + m_reset_delay = true; + m_reset_timer->adjust(attotime::from_usec(10)); // delay time is a guess +} + +//************************************************************************** +// IMPLEMENTATION spectrum_plusd_device +//************************************************************************** + +bool 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 0x0008: + case 0x003a: + case 0x0066: + m_romcs = 1; + break; + } + } +} + +uint8_t spectrum_plusd_device::iorq_r(offs_t offset) +{ + uint8_t data = offset & 1 ? m_slot->fb_r() : 0xff; + + switch (offset & 0x7e) // address lines 0 and 7-15 ignored + { + case 0x62: // fdc status reg + case 0x6a: // fdc track reg + case 0x72: // fdc sector reg + case 0x7a: // fdc data reg + data = m_fdc->read((offset >> 3) & 0x03); + break; + case 0x66: // page in + if (!machine().side_effects_disabled()) + m_romcs = 1; + break; + case 0x76: // 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 & 0x7e) // address lines 0 and 7-15 ignored + { + case 0x62: // fdc command reg + case 0x6a: // fdc track reg + case 0x72: // fdc sector reg + case 0x7a: // fdc data reg + m_fdc->write((offset >> 3) & 0x03, data); + break; + case 0x6e: // bit 0-1: drive select, 6: printer strobe, 7: side select + { + floppy_image_device* floppy = nullptr; + if (data & 1) + floppy = m_floppy[0]->get_device(); + else if (data & 2) + floppy = m_floppy[1]->get_device(); + m_fdc->set_floppy(floppy); + m_centronics->write_strobe(BIT(data, 6)); + if (floppy) floppy->ss_w(BIT(data, 7)); + } + break; + case 0x66: // page out + m_romcs = 0; + break; + case 0x76: // 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); + } +} + +void spectrum_plusd_device::busy_w(int state) +{ + m_centronics_busy = state; +} + +//************************************************************************** +// IMPLEMENTATION spectrum_disciple_device +//************************************************************************** + +bool spectrum_disciple_device::romcs() +{ + return m_romcs || m_exp->romcs(); +} + +void spectrum_disciple_device::pre_opcode_fetch(offs_t offset) +{ + if (m_inhibit->read() || !BIT(m_control, 4)) // when inhibit button pressed - /M1 passthrought might be blocked + m_exp->pre_opcode_fetch(offset); + + if (!machine().side_effects_disabled()) + { + switch (offset) + { + case 0x0001: + case 0x0008: + case 0x0066: + case 0x028e: + if (!m_reset_delay && (m_inhibit->read() || BIT(m_control, 4))) + 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_reset_delay) + m_map = false; + break; + case 0xbb: // page in + if (!machine().side_effects_disabled() && !m_reset_delay && (m_inhibit->read() || BIT(m_control, 4))) + 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... + m_control = data; + if (!m_inhibit->read() && !BIT(m_control, 4)) + m_romcs = 0; + } + break; + case 0x3b: // wait when net=1 + // ... + break; + case 0x7b: // set boot + if (!m_reset_delay) + m_map = true; + break; + case 0xbb: // page out + if (!m_reset_delay) + 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); +} + +TIMER_CALLBACK_MEMBER(spectrum_disciple_device::reset_tick) +{ + m_reset_delay = false; +} |