spectrum: implemented Swift Disc and Swift Disc II interfaces

This commit is contained in:
MetalliC 2020-07-17 00:50:06 +03:00
parent 34c03bbb02
commit 896a982d1b
8 changed files with 704 additions and 0 deletions

View File

@ -3788,6 +3788,8 @@ if (BUSES["SPECTRUM"]~=null) then
MAME_DIR .. "src/devices/bus/spectrum/protek.h",
MAME_DIR .. "src/devices/bus/spectrum/sdi.cpp",
MAME_DIR .. "src/devices/bus/spectrum/sdi.h",
MAME_DIR .. "src/devices/bus/spectrum/sixword.cpp",
MAME_DIR .. "src/devices/bus/spectrum/sixword.h",
MAME_DIR .. "src/devices/bus/spectrum/speccydos.cpp",
MAME_DIR .. "src/devices/bus/spectrum/speccydos.h",
MAME_DIR .. "src/devices/bus/spectrum/specdrum.cpp",

View File

@ -1733,6 +1733,18 @@ if (FORMATS["SVI_DSK"]~=null or _OPTIONS["with-tools"]) then
}
end
--------------------------------------------------
--
--@src/lib/formats/swd_dsk.h,FORMATS["SWD_DSK"] = true
--------------------------------------------------
if (FORMATS["SWD_DSK"]~=null or _OPTIONS["with-tools"]) then
files {
MAME_DIR.. "src/lib/formats/swd_dsk.cpp",
MAME_DIR.. "src/lib/formats/swd_dsk.h",
}
end
--------------------------------------------------
--
--@src/lib/formats/tandy2k_dsk.h,FORMATS["TANDY2K_DSK"] = true

View File

@ -1085,6 +1085,7 @@ FORMATS["SPC1000_CAS"] = true
FORMATS["ST_DSK"] = true
FORMATS["SVI_CAS"] = true
FORMATS["SVI_DSK"] = true
FORMATS["SWD_DSK"] = true
FORMATS["TANDY2K_DSK"] = true
FORMATS["THOM_CAS"] = true
FORMATS["THOM_DSK"] = true

View File

@ -172,6 +172,7 @@ void spectrum_expansion_slot_device::mreq_w(offs_t offset, uint8_t data)
#include "logitek.h"
#include "protek.h"
#include "sdi.h"
#include "sixword.h"
#include "specdrum.h"
#include "speccydos.h"
#include "uslot.h"
@ -210,6 +211,8 @@ void spectrum_expansion_devices(device_slot_interface &device)
device.option_add("sdi", SPECTRUM_SDI);
device.option_add("speccydos", SPECTRUM_SPECCYDOS);
device.option_add("specdrum", SPECTRUM_SPECDRUM);
device.option_add("swiftdisc", SPECTRUM_SWIFTDISC);
device.option_add("swiftdisc2", SPECTRUM_SWIFTDISC2);
device.option_add("uslot", SPECTRUM_USLOT);
device.option_add("usource", SPECTRUM_USOURCE);
device.option_add("uspeech", SPECTRUM_USPEECH);
@ -232,6 +235,8 @@ void spec128_expansion_devices(device_slot_interface &device)
device.option_add("protek", SPECTRUM_PROTEK);
device.option_add("speccydos", SPECTRUM_SPECCYDOS);
device.option_add("specdrum", SPECTRUM_SPECDRUM);
device.option_add("swiftdisc", SPECTRUM_SWIFTDISC);
device.option_add("swiftdisc2", SPECTRUM_SWIFTDISC2);
device.option_add("wafadrive", SPECTRUM_WAFA);
}

View File

@ -0,0 +1,504 @@
// 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
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 form 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.
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.
It seems RAM was planned to be extended to 16KB, but 2nd RAM IC is not populated on known devices.
Was available in several favours - with or without printer port, various number of supported drives, etc.
Dumped v4.2 firmware supports 2 disk drives, but hardware still supports up to 4x.
Notes / TODOs:
- serial printer interface not hooked
*********************************************************************/
#include "emu.h"
#include "sixword.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, 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 - device-specific input ports
//-------------------------------------------------
ioport_constructor spectrum_swiftdisc_device::device_input_ports() const
{
return INPUT_PORTS_NAME(swiftdisc);
}
//-------------------------------------------------
// 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_format_type floppy_formats
//-------------------------------------------------
FLOPPY_FORMATS_MEMBER(spectrum_swiftdisc_device::floppy_formats)
FLOPPY_SWD_FORMAT
FLOPPY_FORMATS_END
//-------------------------------------------------
// 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);
// 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));
}
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_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)
{
}
//-------------------------------------------------
// 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));
}
//-------------------------------------------------
// device_reset - device-specific reset
//-------------------------------------------------
void spectrum_swiftdisc_device::device_reset()
{
m_romcs = 0;
m_rombank = 0;
m_control = 0;
}
void spectrum_swiftdisc2_device::device_reset()
{
spectrum_swiftdisc_device::device_reset();
m_rambank = 0;
}
//**************************************************************************
// IMPLEMENTATION (swiftdisc)
//**************************************************************************
READ_LINE_MEMBER(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
data = 0; // D0 - DTR input, D1 - RX input
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;
m_control = data;
// D3 - /TX output
}
break;
case 0x1000:
case 0x2000:
m_ram[offset - 0x1000] = data;
break;
case 0x3000:
if (!BIT(offset, 3))
m_fdc->write(offset & 3, data);
break;
}
}
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();
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 &= ~1; // D0 - nc, but seems was planned to do something, leftover from prev version ?
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;
}
}
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 &= ~1; // IO port mirror
if (!BIT(offset, 5) && !BIT(m_control, 3))
data = m_joy->read();
if (BIT(m_control, 2))
{
if (!BIT(offset, 3))
{
data |= 0x80; // D7 - /serial input
}
if (!BIT(offset, 4))
{
data &= ~0x0f;
data |= 3;
data |= 8; // D3 - /serial input
}
}
return data;
}
void spectrum_swiftdisc2_device::iorq_w(offs_t offset, uint8_t data)
{
if (m_romcs && (offset & 0xf890) == 0x3000)
control_w(data);
if (BIT(m_control, 2))
{
if (!BIT(offset, 3))
{
// D0 - /serial output
}
if (!BIT(offset, 4))
{
// D0 - 0=reset above latch
// D4 - /serial output
}
}
m_exp->iorq_w(offset, data);
}
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;
}

View File

@ -0,0 +1,96 @@
// license:BSD-3-Clause
// copyright-holders:MetalliC
/*********************************************************************
SIXWORD Swift Disc Interface
*********************************************************************/
#ifndef MAME_BUS_SPECTRUM_SIXWORD_H
#define MAME_BUS_SPECTRUM_SIXWORD_H
#include "exp.h"
#include "softlist.h"
#include "imagedev/floppy.h"
#include "machine/wd_fdc.h"
#include "formats/swd_dsk.h"
//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
class spectrum_swiftdisc_device :
public device_t,
public device_spectrum_expansion_interface
{
public:
// construction/destruction
spectrum_swiftdisc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
DECLARE_FLOPPY_FORMATS(floppy_formats);
DECLARE_INPUT_CHANGED_MEMBER(nmi_button) { m_rombank |= newval << 12; m_slot->nmi_w(newval ? ASSERT_LINE : CLEAR_LINE); };
protected:
spectrum_swiftdisc_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;
// optional information overrides
virtual ioport_constructor device_input_ports() const override;
virtual void device_add_mconfig(machine_config &config) override;
virtual const tiny_rom_entry *device_rom_region() const override;
virtual void post_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 DECLARE_READ_LINE_MEMBER(romcs) override;
required_memory_region m_rom;
required_device<wd_fdc_device_base> m_fdc;
required_device_array<floppy_connector, 4> m_floppy;
required_device<spectrum_expansion_slot_device> m_exp;
required_ioport m_joy;
int m_romcs;
u8 m_ram[0x2000];
u16 m_rombank;
u8 m_control;
};
class spectrum_swiftdisc2_device :
public spectrum_swiftdisc_device
{
public:
// construction/destruction
spectrum_swiftdisc2_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;
virtual const tiny_rom_entry *device_rom_region() const override;
virtual void post_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;
void control_w(uint8_t data);
int m_rambank;
};
// device type definition
DECLARE_DEVICE_TYPE(SPECTRUM_SWIFTDISC, spectrum_swiftdisc_device)
DECLARE_DEVICE_TYPE(SPECTRUM_SWIFTDISC2, spectrum_swiftdisc2_device)
#endif // MAME_BUS_SPECTRUM_SIXWORD_H

View File

@ -0,0 +1,52 @@
// license:BSD-3-Clause
// copyright-holders:MetalliC
/*********************************************************************
formats/swd_dsk.c
Swift Disc disk images
*********************************************************************/
#include <cassert>
#include "formats/swd_dsk.h"
swd_format::swd_format() : wd177x_format(formats)
{
}
const char *swd_format::name() const
{
return "swd";
}
const char *swd_format::description() const
{
return "SWD floppy disk image";
}
const char *swd_format::extensions() const
{
return "swd";
}
int swd_format::get_image_offset(const format &f, int head, int track)
{
return (f.track_count * head + track) * compute_track_size(f);
}
const swd_format::format swd_format::formats[] = {
// note: original formatted disks use side# 1/2 instead of usual 0/1
{ // 3'5 640K 80 track double sided double density
floppy_image::FF_35, floppy_image::DSDD, floppy_image::MFM,
2000, 16, 80, 2, 256, {}, 1, {}, 60, 22, 56
},
{ // 5"25 640K 80 track double sided double density
floppy_image::FF_525, floppy_image::DSQD, floppy_image::MFM,
2000, 16, 80, 2, 256, {}, 1, {}, 60, 22, 56
},
{}
};
const floppy_format_type FLOPPY_SWD_FORMAT = &floppy_image_format_creator<swd_format>;

32
src/lib/formats/swd_dsk.h Normal file
View File

@ -0,0 +1,32 @@
// license:BSD-3-Clause
// copyright-holders:MetalliC
/*********************************************************************
formats/swd_dsk.h
Swift Disc disk images
*********************************************************************/
#ifndef MAME_FORMATS_SWD_DSK_H
#define MAME_FORMATS_SWD_DSK_H
#pragma once
#include "wd177x_dsk.h"
class swd_format : public wd177x_format {
public:
swd_format();
virtual const char *name() const override;
virtual const char *description() const override;
virtual const char *extensions() const override;
private:
static const format formats[];
virtual int get_image_offset(const format &f, int head, int track) override;
};
extern const floppy_format_type FLOPPY_SWD_FORMAT;
#endif // MAME_FORMATS_SWD_DSK_H