summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/bus/spectrum/sixword.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/bus/spectrum/sixword.cpp')
-rw-r--r--src/devices/bus/spectrum/sixword.cpp604
1 files changed, 604 insertions, 0 deletions
diff --git a/src/devices/bus/spectrum/sixword.cpp b/src/devices/bus/spectrum/sixword.cpp
new file mode 100644
index 00000000000..7e55410e78b
--- /dev/null
+++ b/src/devices/bus/spectrum/sixword.cpp
@@ -0,0 +1,604 @@
+// license:BSD-3-Clause
+// copyright-holders:MetalliC
+/*********************************************************************
+
+ Swift Disc
+ (c) 1987 SIXWORD ltd (UK)
+
+ WD1770-based floppy drive interface with 8KB RAM and 16KB ROM, serial printer interface, joystick port and "interrupt" button,
+ supports up to 4x 3'5 (normally) or 5"25 drives, 640KB per disk, compatible with ZX Spectrum 128, was positioned as luxury device.
+ For additional charge was available ZX Interface 1 microdrive emulator software (currently missing).
+
+ How to use:
+ Press "Interrupt" button and you'll get into console where you may type commands, like:
+ C[AT] [drive] - list disk contents, drive 0-3
+ D[ATE] [dd-mm-yy] - set current date, or show firmware build date
+ F[ORMAT] diskname - format disk
+ S[AVE] filename - save snapshot to disk
+ L[OAD] filename - load snapshot from disk
+ A[LTER] address data - change value in RAM
+ Q[UIT] - return to BASIC/game
+ * - reset
+ Starting from Swift Disc O/S V2 most of commands may be called from BASIC using syntax like "COMMAND %drive;"filename"", for example:
+ CAT %0
+ LOAD %0;"game"
+ and so on, plus additional commands for sequential file access.
+ FORMAT %#4;"T",1200,79 - printer setup: channel 4, text mode, 1200 baud, 79 column
+
+ Manual: https://k1.spdns.de/Vintage/Sinclair/82/Peripherals/Disc%20Interfaces/SixWord%20Swift%20Disc%20Interface/Swift%20Disc%20Operating%20Manual.pdf
+
+
+ Swift Disc II
+ (c) 1989 SIXWORD ltd (UK)
+
+ Same as above but extended to 32KB ROM, most of discrete ICs replaced with PALs, smaller form factor.
+ Was available in several favours - with serial or parallel printer port.
+ It seems RAM was planned to be extended to 16KB, but 2nd RAM IC is not populated on known devices.
+ Dumped v4.2 firmware supports only 2 disk drives (but PCB still have wired drive 3 and 4 select) and serial port.
+
+ Notes / TODOs:
+ - serial out not working properly with v4.2 ROM, it produce short TX low pulse after each character, which (mistakenly) considered as start bit by current diserial.cpp.
+ - parallel port hookup based on ROM disassembly and may be not accurate (i.e. ports may require to be enabled by some of m_control bits, or something like that)
+
+*********************************************************************/
+
+#include "emu.h"
+#include "sixword.h"
+
+#include "formats/swd_dsk.h"
+
+
+/***************************************************************************
+ DEVICE DEFINITIONS
+***************************************************************************/
+
+DEFINE_DEVICE_TYPE(SPECTRUM_SWIFTDISC, spectrum_swiftdisc_device, "spectrum_swiftdisc", "Swift Disc Interface")
+DEFINE_DEVICE_TYPE(SPECTRUM_SWIFTDISC2, spectrum_swiftdisc2_device, "spectrum_swiftdisc2", "Swift Disc II Interface")
+
+
+//-------------------------------------------------
+// INPUT_PORTS
+//-------------------------------------------------
+
+INPUT_PORTS_START(swiftdisc)
+ PORT_START("BUTTON")
+ PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_BUTTON1) PORT_NAME("Interrupt Button") PORT_CODE(KEYCODE_MINUS_PAD) PORT_CHANGED_MEMBER(DEVICE_SELF, FUNC(spectrum_swiftdisc_device::nmi_button), 0)
+
+ PORT_START("JOY")
+ PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT) PORT_8WAY
+ PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT) PORT_8WAY
+ PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN) PORT_8WAY
+ PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP) PORT_8WAY
+ PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_BUTTON1)
+ PORT_BIT(0xe0, IP_ACTIVE_HIGH, IPT_UNUSED)
+INPUT_PORTS_END
+
+INPUT_PORTS_START(swiftdisc2)
+ PORT_INCLUDE(swiftdisc)
+
+ PORT_START("CONF")
+ PORT_CONFNAME(0x01, 0x01, "Printer intrface")
+ PORT_CONFSETTING(0x01, "Serial")
+ PORT_CONFSETTING(0x00, "Parallel")
+INPUT_PORTS_END
+
+//-------------------------------------------------
+// input_ports - device-specific input ports
+//-------------------------------------------------
+
+ioport_constructor spectrum_swiftdisc_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME(swiftdisc);
+}
+
+ioport_constructor spectrum_swiftdisc2_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME(swiftdisc2);
+}
+
+//-------------------------------------------------
+// SLOT_INTERFACE( floppies )
+//-------------------------------------------------
+
+static void swiftdisc_floppies(device_slot_interface &device)
+{
+ device.option_add("35dd", FLOPPY_35_DD);
+ device.option_add("525qd", FLOPPY_525_QD);
+}
+
+//-------------------------------------------------
+// floppy_formats
+//-------------------------------------------------
+
+void spectrum_swiftdisc_device::floppy_formats(format_registration &fr)
+{
+ fr.add_mfm_containers();
+ fr.add(FLOPPY_SWD_FORMAT);
+}
+
+//-------------------------------------------------
+// ROM( swiftdisc )
+//-------------------------------------------------
+
+ROM_START(swiftdisc)
+ ROM_REGION(0x4000, "rom", 0)
+ ROM_DEFAULT_BIOS("v34")
+
+ // v2.3 known to exists, not dumped
+ ROM_SYSTEM_BIOS(0, "v24", "v2.4")
+ ROMX_LOAD("24.ic8", 0x0000, 0x4000, CRC(547f660a) SHA1(73a1b96271760fb0edfc1302368372501455bbfc), ROM_BIOS(0))
+ ROM_SYSTEM_BIOS(1, "v34", "v3.4")
+ ROMX_LOAD("34.ic8", 0x0000, 0x4000, CRC(f7092c0c) SHA1(5afe0364afedc83c03995d44914fe7f207fb5c28), ROM_BIOS(1))
+ROM_END
+
+ROM_START(swiftdisc2)
+ ROM_REGION(0x8000, "rom", 0)
+ ROM_DEFAULT_BIOS("v42")
+
+ ROM_SYSTEM_BIOS(0, "v42", "v4.2")
+ ROMX_LOAD("42.bin", 0x0000, 0x8000, CRC(a6fde15b) SHA1(496be6f655974b6162ff430b6ba0c7002164b736), ROM_BIOS(0))
+
+ ROM_REGION(260, "pals", 0)
+ ROM_LOAD("dec1_pal16l8.bin", 0, 260, BAD_DUMP CRC(1433067c) SHA1(a0cf09a86a0d7a71332005bbb04d27d3aa45291c)) // one of logic equations clearly wrong
+ ROM_LOAD("dec2_pal16l8.bin", 0, 260, CRC(4d088879) SHA1(d1d60b38068d457db25f5df304a705999f285fd9))
+ ROM_LOAD("dec3_pal16l8.bin", 0, 260, CRC(8306722c) SHA1(2ad28d44bc33a50ed5f93f2520f25100dd36841d))
+ROM_END
+
+//-------------------------------------------------
+// device_add_mconfig - add device configuration
+//-------------------------------------------------
+
+void spectrum_swiftdisc_device::device_add_mconfig(machine_config &config)
+{
+ WD1770(config, m_fdc, 8_MHz_XTAL);
+ m_fdc->intrq_wr_callback().set(DEVICE_SELF_OWNER, FUNC(spectrum_expansion_slot_device::nmi_w));
+ m_fdc->drq_wr_callback().set(DEVICE_SELF_OWNER, FUNC(spectrum_expansion_slot_device::nmi_w));
+
+ FLOPPY_CONNECTOR(config, "fdc:0", swiftdisc_floppies, "35dd", spectrum_swiftdisc_device::floppy_formats).enable_sound(true);
+ FLOPPY_CONNECTOR(config, "fdc:1", swiftdisc_floppies, "35dd", spectrum_swiftdisc_device::floppy_formats).enable_sound(true);
+ FLOPPY_CONNECTOR(config, "fdc:2", swiftdisc_floppies, nullptr, spectrum_swiftdisc_device::floppy_formats).enable_sound(true);
+ FLOPPY_CONNECTOR(config, "fdc:3", swiftdisc_floppies, nullptr, spectrum_swiftdisc_device::floppy_formats).enable_sound(true);
+
+ RS232_PORT(config, m_rs232, default_rs232_devices, "printer");
+
+ // 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));
+}
+
+void spectrum_swiftdisc2_device::device_add_mconfig(machine_config &config)
+{
+ spectrum_swiftdisc_device::device_add_mconfig(config);
+
+ // parallel printer port
+ CENTRONICS(config, m_centronics, centronics_devices, nullptr);
+ m_centronics->busy_handler().set(FUNC(spectrum_swiftdisc2_device::busy_w));
+}
+
+const tiny_rom_entry *spectrum_swiftdisc_device::device_rom_region() const
+{
+ return ROM_NAME(swiftdisc);
+}
+
+const tiny_rom_entry *spectrum_swiftdisc2_device::device_rom_region() const
+{
+ return ROM_NAME(swiftdisc2);
+}
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// spectrum_swiftdisc_device - constructor
+//-------------------------------------------------
+
+spectrum_swiftdisc_device::spectrum_swiftdisc_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_exp(*this, "exp")
+ , m_rs232(*this, "rs232")
+ , m_joy(*this, "JOY")
+{
+}
+
+spectrum_swiftdisc_device::spectrum_swiftdisc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : spectrum_swiftdisc_device(mconfig, SPECTRUM_SWIFTDISC, tag, owner, clock)
+{
+}
+
+spectrum_swiftdisc2_device::spectrum_swiftdisc2_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : spectrum_swiftdisc_device(mconfig, SPECTRUM_SWIFTDISC2, tag, owner, clock)
+ , m_centronics(*this, "centronics")
+ , m_conf(*this, "CONF")
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void spectrum_swiftdisc_device::device_start()
+{
+ memset(m_ram, 0, sizeof(m_ram));
+
+ save_item(NAME(m_romcs));
+ save_item(NAME(m_ram));
+ save_item(NAME(m_rombank));
+ save_item(NAME(m_control));
+}
+
+void spectrum_swiftdisc2_device::device_start()
+{
+ spectrum_swiftdisc_device::device_start();
+ save_item(NAME(m_rambank));
+ save_item(NAME(m_busy));
+ save_item(NAME(m_txd_on));
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void spectrum_swiftdisc_device::device_reset()
+{
+ m_romcs = 0;
+ m_rombank = 0;
+ m_control = 0;
+ m_rs232->write_txd(1);
+}
+
+void spectrum_swiftdisc2_device::device_reset()
+{
+ spectrum_swiftdisc_device::device_reset();
+ m_rambank = 0;
+ m_busy = 0;
+ m_txd_on = 0;
+ m_rs232->write_dtr(1);
+ m_centronics->write_strobe(1);
+}
+
+//**************************************************************************
+// IMPLEMENTATION (swiftdisc)
+//**************************************************************************
+
+bool spectrum_swiftdisc_device::romcs()
+{
+ return m_romcs || m_exp->romcs();
+}
+
+void spectrum_swiftdisc_device::post_opcode_fetch(offs_t offset)
+{
+ m_exp->post_opcode_fetch(offset);
+
+ if (!machine().side_effects_disabled())
+ {
+ switch (offset)
+ {
+ case 0x000b:
+ m_romcs = !m_romcs;
+ break;
+ case 0x0066:
+ if (m_rombank & 0x1000)
+ m_romcs = !m_romcs;
+ break;
+ }
+ }
+}
+
+uint8_t spectrum_swiftdisc_device::mreq_r(offs_t offset)
+{
+ u8 data = 0xff;
+
+ if (m_romcs)
+ {
+ switch (offset & 0xf000)
+ {
+ case 0x0000:
+ data = m_rom->base()[m_rombank + offset];
+ break;
+ case 0x1000:
+ case 0x2000:
+ data = m_ram[offset - 0x1000];
+ break;
+ case 0x3000:
+ if (!BIT(offset, 3))
+ data = m_fdc->read(offset & 3);
+ else
+ {
+ // D0 - RS232 DSR, D1 - RS232 RX
+ data &= ~3;
+ data |= m_rs232->dsr_r() << 0;
+ data |= m_rs232->rxd_r() << 1;
+ }
+ break;
+ }
+ }
+
+ if (m_exp->romcs())
+ data &= m_exp->mreq_r(offset);
+
+ return data;
+}
+
+void spectrum_swiftdisc_device::mreq_w(offs_t offset, uint8_t data)
+{
+ if (m_romcs)
+ {
+ switch (offset & 0xf000)
+ {
+ case 0x0000:
+ if (BIT(offset, 3))
+ m_rombank ^= 0x1000;
+ else
+ {
+ floppy_image_device* floppy = nullptr;
+ for (int i = 3; i >= 0; i--)
+ {
+ floppy_image_device* fl = m_floppy[i]->get_device();
+ if (fl)
+ {
+ fl->ss_w(BIT(data, 4));
+ if (BIT(data, i))
+ floppy = fl;
+ }
+ }
+ m_fdc->set_floppy(floppy);
+
+ m_rombank &= ~0x2000;
+ m_rombank |= BIT(data, 5) << 13;
+
+ // D3 - RS232 /TX
+ m_rs232->write_txd(!BIT(data, 3));
+ m_control = data;
+ }
+ break;
+ case 0x1000:
+ case 0x2000:
+ m_ram[offset - 0x1000] = data;
+ break;
+ case 0x3000:
+ if (!BIT(offset, 3))
+ m_fdc->write(offset & 3, data);
+ break;
+ }
+ }
+
+ if (m_exp->romcs())
+ m_exp->mreq_w(offset, data);
+}
+
+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() & 0x1f;
+
+ return data;
+}
+
+
+//**************************************************************************
+// IMPLEMENTATION (swiftdisc2)
+//**************************************************************************
+
+void spectrum_swiftdisc2_device::post_opcode_fetch(offs_t offset)
+{
+ m_exp->post_opcode_fetch(offset);
+
+ if (!machine().side_effects_disabled())
+ {
+ switch (offset)
+ {
+ case 0x000b:
+ m_romcs = !m_romcs;
+ break;
+ case 0x0066:
+ if (m_rombank & 0x1000)
+ m_romcs = !m_romcs;
+ break;
+ case 0x1709:
+ if (BIT(m_control,2))
+ m_romcs = !m_romcs;
+ break;
+ }
+ }
+}
+
+uint8_t spectrum_swiftdisc2_device::mreq_r(offs_t offset)
+{
+ u8 data = 0xff;
+
+ if (m_romcs)
+ {
+ switch (offset & 0xf000)
+ {
+ case 0x0000:
+ data = m_rom->base()[m_rombank + offset];
+ break;
+ case 0x1000:
+ case 0x2000:
+ if (!m_rambank)
+ data = m_ram[offset - 0x1000];
+ else
+ {
+ data = 0xff; // 2nd RAM IC not populated
+ logerror("Swift2 RAM2 read %04x\n", offset);
+ }
+ break;
+ case 0x3000:
+ if (!BIT(offset, 4))
+ data = m_fdc->read(offset & 3);
+ else
+ data = control_r();
+ break;
+ }
+ }
+
+ if (m_exp->romcs())
+ data &= m_exp->mreq_r(offset);
+
+ return data;
+}
+
+void spectrum_swiftdisc2_device::mreq_w(offs_t offset, uint8_t data)
+{
+ if (m_romcs)
+ {
+ switch (offset & 0xf000)
+ {
+ case 0x0000:
+ if (BIT(offset, 8))
+ m_rambank = !m_rambank;
+ break;
+ case 0x1000:
+ case 0x2000:
+ if (!m_rambank)
+ m_ram[offset - 0x1000] = data;
+ else
+ {
+ // 2nd RAM IC not populated
+ logerror("Swift2 RAM2 write %04x %02x\n", offset, data);
+ }
+ break;
+ case 0x3000:
+ if ((offset & 0x890) == 0)
+ m_fdc->write(offset & 3, data);
+
+ if (BIT(offset, 4))
+ control_w(data);
+ break;
+ }
+ }
+
+ if (m_exp->romcs())
+ m_exp->mreq_w(offset, data);
+}
+
+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();
+
+ if (!BIT(offset, 5) && !BIT(m_control, 3))
+ data = m_joy->read() & 0x1f;
+
+ if (m_conf->read())
+ {
+ if (BIT(m_control, 2))
+ {
+ if (!BIT(offset, 3)) // port F7
+ {
+ // D7 - RS232 /RX
+ data &= ~0x80;
+ data |= !m_rs232->rxd_r() << 7;
+ }
+ if (!BIT(offset, 4)) // port EF
+ {
+ // D3 - RS232 /DSR
+ data &= ~0x8;
+ data |= !m_rs232->dsr_r() << 3;
+ }
+ }
+ }
+ else
+ {
+ if (!BIT(offset, 3)) // port F7
+ {
+ // D7 - Centronics /BUSY
+ data &= ~0x80;
+ data |= !m_busy << 7;
+ }
+ }
+
+ return data;
+}
+
+void spectrum_swiftdisc2_device::iorq_w(offs_t offset, uint8_t data)
+{
+ if (m_romcs && (offset & 0xf890) == 0x3000)
+ control_w(data);
+
+ if (m_conf->read())
+ {
+ if (BIT(m_control, 2))
+ {
+ if (!BIT(offset, 3)) // port F7
+ {
+ // D0 - RS232 /TX
+ if (m_txd_on)
+ m_rs232->write_txd(!BIT(data, 0));
+ }
+ if (!BIT(offset, 4)) // port EF
+ {
+ // D0 - 0=reset /TX latch (set output to 1)
+ // D4 - RS232 /DTR
+ m_txd_on = BIT(data, 0);
+ if (!m_txd_on)
+ m_rs232->write_txd(1);
+ m_rs232->write_dtr(!BIT(data, 4));
+ }
+ }
+ }
+ else
+ {
+ if (!BIT(offset, 3)) // F7
+ {
+ // D0 - Centronics /STROBE
+ m_centronics->write_strobe(BIT(data, 0));
+ }
+ if (!BIT(offset, 4)) // EF
+ {
+ // D0 - D7 - Centronics 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));
+ }
+ }
+
+ m_exp->iorq_w(offset, data);
+}
+
+uint8_t spectrum_swiftdisc2_device::control_r()
+{
+ // D0 - printer interface type, 0 - parallel, 1 - serial
+ return 0xfe | m_conf->read();
+}
+
+void spectrum_swiftdisc2_device::control_w(uint8_t data)
+{
+ floppy_image_device* floppy = nullptr;
+ for (int i = 3; i >= 0; i--)
+ {
+ floppy_image_device* fl = m_floppy[i]->get_device();
+ if (fl)
+ {
+ fl->ss_w(BIT(data, 4));
+ if (!BIT(data, i))
+ floppy = fl;
+ }
+ }
+ m_fdc->set_floppy(floppy);
+
+ m_rombank &= ~0x6000;
+ m_rombank |= BIT(data, 5) << 13;
+ m_rombank |= BIT(data, 6) << 14;
+
+ if (BIT(data, 7) && !BIT(m_control, 7)) // swap bank at 0->1
+ m_rombank ^= 0x1000;
+ m_control = data;
+}