From 69271581e6fe9a5d9be28c0f00db364055e59a6a Mon Sep 17 00:00:00 2001 From: ksherlock Date: Tue, 8 Feb 2022 12:00:32 -0500 Subject: [PATCH] bus/a2bus: Added Apple II 3.5" Disk Controller Card. (#9215) Apple II 3.5" Disk Controller Card, Apple P/N A0076LL/A, Announced July 1991, Released March 1992. $149.95 MSRP --- scripts/src/bus.lua | 2 + src/devices/bus/a2bus/a2superdrive.cpp | 348 +++++++++++++++++++++++++ src/devices/bus/a2bus/a2superdrive.h | 22 ++ src/devices/bus/a2bus/cards.cpp | 4 + src/devices/machine/swim1.cpp | 2 - src/mame/drivers/apple2gs.cpp | 5 + 6 files changed, 381 insertions(+), 2 deletions(-) create mode 100644 src/devices/bus/a2bus/a2superdrive.cpp create mode 100644 src/devices/bus/a2bus/a2superdrive.h diff --git a/scripts/src/bus.lua b/scripts/src/bus.lua index 8667c54788e..5882bdf7d34 100644 --- a/scripts/src/bus.lua +++ b/scripts/src/bus.lua @@ -2529,6 +2529,8 @@ if (BUSES["A2BUS"]~=null) then MAME_DIR .. "src/devices/bus/a2bus/a2softcard.h", MAME_DIR .. "src/devices/bus/a2bus/a2ssc.cpp", MAME_DIR .. "src/devices/bus/a2bus/a2ssc.h", + MAME_DIR .. "src/devices/bus/a2bus/a2superdrive.cpp", + MAME_DIR .. "src/devices/bus/a2bus/a2superdrive.h", MAME_DIR .. "src/devices/bus/a2bus/a2swyft.cpp", MAME_DIR .. "src/devices/bus/a2bus/a2swyft.h", MAME_DIR .. "src/devices/bus/a2bus/a2themill.cpp", diff --git a/src/devices/bus/a2bus/a2superdrive.cpp b/src/devices/bus/a2bus/a2superdrive.cpp new file mode 100644 index 00000000000..5d550763d4b --- /dev/null +++ b/src/devices/bus/a2bus/a2superdrive.cpp @@ -0,0 +1,348 @@ +// license:BSD-3-Clause +// copyright-holders:Kelvin Sherlock +/********************************************************************* + + a2superdrive.cpp + + Apple II 3.5" Disk Controller Card (Apple, 1991) + aka SuperDrive Card, aka NuMustang (development codename) + + 32k ram + 32k eprom + 15.6672Mhz crystal + SWIM 1 Chip (1987) + 65c02 processor (~2mhz) + + uc: + + $0000-$7fff is ram + $8000-$ffff is rom + $0a00-$0aff is i/o + + apple 2 bus: + + $c0n0-$c0nf - memory latch. selects a 1k window for $c800-$cbff + $cn00-$cnff - uc ram ($7b00-$7bff) + $c800-$cbff - uc ram ($0000-$3cff, based on memory latch) + $cc00-$cfff - uc ram ($7c00-$7fff) + + spamming Control-D while booting will invoke the built-in + diagnostics. An alternative entry is Cx0DG from the monitor. + +*********************************************************************/ + + +#include "emu.h" +#include "a2superdrive.h" +#include "cpu/m6502/w65c02s.h" +#include "machine/applefdintf.h" +#include "machine/swim1.h" +#include "imagedev/floppy.h" + +#define C16M (15.6672_MHz_XTAL) + + +namespace { + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class a2bus_superdrive_device: + public device_t, + public device_a2bus_card_interface +{ +public: + // construction/destruction + a2bus_superdrive_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + +protected: + a2bus_superdrive_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); + + virtual void device_start() override; + virtual void device_reset() override; + virtual void device_add_mconfig(machine_config &config) override; + virtual const tiny_rom_entry *device_rom_region() const override; + + // overrides of standard a2bus slot functions + virtual uint8_t read_c0nx(uint8_t offset) override; + virtual void write_c0nx(uint8_t offset, uint8_t data) override; + virtual uint8_t read_cnxx(uint8_t offset) override; + virtual void write_cnxx(uint8_t offset, uint8_t data) override; + virtual uint8_t read_c800(uint16_t offset) override; + virtual void write_c800(uint16_t offset, uint8_t data) override; + +private: + + void m65c02_mem(address_map &map); + + void m65c02_w(offs_t offset, uint8_t value); + uint8_t m65c02_r(offs_t offset); + + void phases_w(uint8_t phases); + void sel35_w(int sel35); + void devsel_w(uint8_t devsel); + void hdsel_w(int hdsel); + + + required_device m_65c02; + required_region_ptr m_rom; + required_shared_ptr m_ram; + + required_device m_fdc; + + uint8_t m_bank_select; + uint8_t m_side; +}; + + +#define SUPERDRIVE_ROM_REGION "superdrive_rom" + + +ROM_START( superdrive ) + ROM_REGION(0x8000, SUPERDRIVE_ROM_REGION, 0) + ROM_LOAD( "341-0438-a.bin", 0x0000, 0x08000, CRC(c73ff25b) SHA1(440c3f84176c7b9f542da0b6ddf4fb13ec326c46) ) +ROM_END + + +const tiny_rom_entry *a2bus_superdrive_device::device_rom_region() const +{ + return ROM_NAME( superdrive ); +} + +void a2bus_superdrive_device::m65c02_mem(address_map &map) +{ + map(0x0000, 0x7fff).ram().share(m_ram); + map(0x0a00, 0x0aff).rw(FUNC(a2bus_superdrive_device::m65c02_r), FUNC(a2bus_superdrive_device::m65c02_w)); + map(0x8000, 0xffff).rom().region(SUPERDRIVE_ROM_REGION, 0x0000); +} + + +void a2bus_superdrive_device::device_add_mconfig(machine_config &config) +{ + + W65C02S(config, m_65c02, DERIVED_CLOCK(2, 7)); /* ~ 2.046 MHz */ + m_65c02->set_addrmap(AS_PROGRAM, &a2bus_superdrive_device::m65c02_mem); + + SWIM1(config, m_fdc, C16M); + + applefdintf_device::add_35_hd(config, "fdc:0"); + applefdintf_device::add_35_hd(config, "fdc:1"); + + m_fdc->devsel_cb().set(FUNC(a2bus_superdrive_device::devsel_w)); + m_fdc->hdsel_cb().set(FUNC(a2bus_superdrive_device::hdsel_w)); + m_fdc->phases_cb().set(FUNC(a2bus_superdrive_device::phases_w)); + m_fdc->sel35_cb().set(FUNC(a2bus_superdrive_device::sel35_w)); +} + + + +a2bus_superdrive_device::a2bus_superdrive_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_a2bus_card_interface(mconfig, *this), + m_65c02(*this, "superdrive_65c02"), + m_rom(*this, SUPERDRIVE_ROM_REGION), + m_ram(*this, "superdrive_ram"), + m_fdc(*this, "fdc"), + m_bank_select(0), + m_side(0) +{ } + +a2bus_superdrive_device::a2bus_superdrive_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock): + a2bus_superdrive_device(mconfig, A2BUS_SUPERDRIVE, tag, owner, clock) +{ } + +void a2bus_superdrive_device::device_start() +{ + save_item(NAME(m_bank_select)); + save_item(NAME(m_side)); +} + + +void a2bus_superdrive_device::device_reset() +{ + m_bank_select = 0; + m_side = 0; +} + + +// overrides of standard a2bus slot functions +uint8_t a2bus_superdrive_device::read_c0nx(uint8_t offset) +{ + if (machine().side_effects_disabled()) return 0; + + m_bank_select = offset & 0x0f; + return 0; +} + +void a2bus_superdrive_device::write_c0nx(uint8_t offset, uint8_t data) +{ + m_bank_select = offset & 0x0f; +} + +uint8_t a2bus_superdrive_device::read_cnxx(uint8_t offset) +{ + return m_ram[0x7b00 + offset]; +} + +void a2bus_superdrive_device::write_cnxx(uint8_t offset, uint8_t data) +{ + //m_ram[0x7b00 + offset] = data; +} + +/* + * $c800 - $cbff is uc RAM, controlled via c0nx + * $cc00 - $cfff is uc RAM, hardcoded to $7c00 - $7fff + */ +uint8_t a2bus_superdrive_device::read_c800(uint16_t offset) +{ + unsigned address; + + if (offset < 0x400) + address = (m_bank_select << 10) + offset; + else + address = 0x7c00 + offset - 0x400; + + return m_ram[address]; +} + +void a2bus_superdrive_device::write_c800(uint16_t offset, uint8_t data) +{ + unsigned address; + + if (offset < 0x400) + address = (m_bank_select << 10) + offset; + else + address = 0x7c00 + offset - 0x400; + + m_ram[address] = data; +} + + +/* uc 65c02 i/o at $0a00 */ +void a2bus_superdrive_device::m65c02_w(offs_t offset, uint8_t value) +{ + // $00-$0f = swim registers + // $40 = head sel low + // $41 = head sel high + // $80 = diagnostic led on + // $81 = diagnostic led off + + floppy_image_device *floppy = nullptr; + + if (offset < 16) + { + m_fdc->write(offset, value); + return; + } + + switch (offset) + { + case 0x40: + m_side = 0; + floppy = m_fdc->get_floppy(); + if (floppy) floppy->ss_w(m_side); + break; + + case 0x41: + m_side = 1; + floppy = m_fdc->get_floppy(); + if (floppy) floppy->ss_w(m_side); + break; + + case 0x80: + logerror("LED on\n"); + break; + + case 0x81: + logerror("LED off\n"); + break; + + default: + logerror("write($0a%02x,%02x)\n", offset, value); + break; + } +} + +uint8_t a2bus_superdrive_device::m65c02_r(offs_t offset) +{ + floppy_image_device *floppy = nullptr; + + if (offset < 16) + return m_fdc->read(offset); + + if (machine().side_effects_disabled()) return 0; + + switch (offset) + { + case 0x40: + m_side = 0; + floppy = m_fdc->get_floppy(); + if (floppy) floppy->ss_w(m_side); + break; + + case 0x41: + m_side = 1; + floppy = m_fdc->get_floppy(); + if (floppy) floppy->ss_w(m_side); + break; + + case 0x80: + logerror("LED on\n"); + break; + + case 0x81: + logerror("LED off\n"); + break; + + default: + logerror("read($0a%02x)\n", offset); + break; + } + return 0; +} + + +void a2bus_superdrive_device::devsel_w(uint8_t devsel) +{ + floppy_image_device *floppy = nullptr; + + switch (devsel) + { + case 1: + floppy = m_fdc->subdevice("0")->get_device(); + break; + case 2: + floppy = m_fdc->subdevice("1")->get_device(); + break; + } + + m_fdc->set_floppy(floppy); +} + +void a2bus_superdrive_device::phases_w(uint8_t phases) +{ + floppy_image_device *floppy = m_fdc->get_floppy(); + if (floppy) + floppy->seek_phase_w(phases); +} + + +void a2bus_superdrive_device::sel35_w(int sel35) +{ +} + +void a2bus_superdrive_device::hdsel_w(int hdsel) +{ + /* Q3/HDSEL pin (ISM MODE register bit 5) is used to control the clock speed */ + /* MFM runs at 15.6672, GCR at 15.6672/2 */ + + m_fdc->set_clock_scale( hdsel ? 1.0 : 0.5); +} + +} // anonymous namespace + + +DEFINE_DEVICE_TYPE_PRIVATE(A2BUS_SUPERDRIVE, device_a2bus_card_interface, a2bus_superdrive_device, "a2superdrive", "Apple II 3.5\" Disk Controller Card") + diff --git a/src/devices/bus/a2bus/a2superdrive.h b/src/devices/bus/a2bus/a2superdrive.h new file mode 100644 index 00000000000..4181892e5cd --- /dev/null +++ b/src/devices/bus/a2bus/a2superdrive.h @@ -0,0 +1,22 @@ +// license:BSD-3-Clause +// copyright-holders:Kelvin Sherlock +/********************************************************************* + + a2superdrive.h + + Implementation of the Apple II 3.5 Disk Controller Card + +*********************************************************************/ + +#ifndef MAME_BUS_A2BUS_SUPERDRIVE_H +#define MAME_BUS_A2BUS_SUPERDRIVE_H + +#pragma once + +#include "a2bus.h" + + +// device type definition +DECLARE_DEVICE_TYPE(A2BUS_SUPERDRIVE, device_a2bus_card_interface) + +#endif // MAME_BUS_A2BUS_SUPERDRIVE_H diff --git a/src/devices/bus/a2bus/cards.cpp b/src/devices/bus/a2bus/cards.cpp index 984b3c73902..73b04bc2df3 100644 --- a/src/devices/bus/a2bus/cards.cpp +++ b/src/devices/bus/a2bus/cards.cpp @@ -33,6 +33,7 @@ #include "bus/a2bus/a2scsi.h" #include "bus/a2bus/a2softcard.h" #include "bus/a2bus/a2ssc.h" +#include "bus/a2bus/a2superdrive.h" #include "bus/a2bus/a2swyft.h" #include "bus/a2bus/a2themill.h" #include "bus/a2bus/a2thunderclock.h" @@ -69,6 +70,7 @@ #include "bus/a2bus/titan3plus2.h" #include "bus/a2bus/softcard3.h" + void apple2_slot0_cards(device_slot_interface &device) { device.option_add("lang", A2BUS_RAMCARD16K); // Apple II RAM Language Card @@ -217,6 +219,7 @@ void apple2e_cards(device_slot_interface &device) device.option_add("a2sd", A2BUS_A2SD); // Florian Reitz AppleIISD device.option_add("grafex", A2BUS_GRAFEX); // Grafex card (uPD7220 graphics) device.option_add("pdromdrive", A2BUS_PRODOSROMDRIVE); // ProDOS ROM Drive + device.option_add("superdrive", A2BUS_SUPERDRIVE); // Apple II 3.5" Disk Controller } void apple2gs_cards(device_slot_interface &device) @@ -288,6 +291,7 @@ void apple2gs_cards(device_slot_interface &device) device.option_add("q68plus", A2BUS_Q68PLUS); // Stellation Q68 Plus 68000 card device.option_add("grafex", A2BUS_GRAFEX); // Grafex card (uPD7220 graphics) device.option_add("pdromdrive", A2BUS_PRODOSROMDRIVE); // ProDOS ROM Drive + device.option_add("superdrive", A2BUS_SUPERDRIVE); // Apple II 3.5" Disk Controller } void apple3_cards(device_slot_interface &device) diff --git a/src/devices/machine/swim1.cpp b/src/devices/machine/swim1.cpp index 7e9a047d3d5..a366f66a4a2 100644 --- a/src/devices/machine/swim1.cpp +++ b/src/devices/machine/swim1.cpp @@ -9,8 +9,6 @@ #include "emu.h" #include "swim1.h" -#include "cpu/m68000/m68000.h" - DEFINE_DEVICE_TYPE(SWIM1, swim1_device, "swim1", "Apple SWIM1 (Sander/Wozniak Integrated Machine) version 1 floppy controller") swim1_device::swim1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : diff --git a/src/mame/drivers/apple2gs.cpp b/src/mame/drivers/apple2gs.cpp index 6c9b265547d..4e40652ca44 100644 --- a/src/mame/drivers/apple2gs.cpp +++ b/src/mame/drivers/apple2gs.cpp @@ -459,6 +459,7 @@ private: bool m_ramrd, m_ramwrt; bool m_lcram, m_lcram2, m_lcprewrite, m_lcwriteenable; bool m_ioudis; + bool m_rombank; u8 m_shadow, m_speed, m_textcol; u8 m_motors_active, m_slotromsel, m_intflag, m_vgcint, m_inten, m_newvideo; @@ -1393,6 +1394,7 @@ void apple2gs_state::machine_start() save_item(NAME(m_an2)); save_item(NAME(m_an3)); save_item(NAME(m_intcxrom)); + save_item(NAME(m_rombank)); save_item(NAME(m_80store)); save_item(NAME(m_slotc3rom)); save_item(NAME(m_altzp)); @@ -1494,6 +1496,7 @@ void apple2gs_state::machine_reset() m_slotc3rom = false; m_irqmask = 0; m_intcxrom = false; + m_rombank = false; m_80store = false; m_video->m_80store = false; m_altzp = false; @@ -2611,6 +2614,7 @@ u8 apple2gs_state::c000_r(offs_t offset) (m_ramwrt ? 0x10 : 0x00) | (m_lcram ? 0x00 : 0x08) | (m_lcram2 ? 0x04 : 0x00) | + (m_rombank ? 0x02 : 0x00) | (m_intcxrom ? 0x01 : 0x00); case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77: @@ -3065,6 +3069,7 @@ void apple2gs_state::c000_w(offs_t offset, u8 data) m_ramwrt = (data & 0x10); m_lcram = (data & 0x08) ? false : true; m_lcram2 = (data & 0x04); + m_rombank = (data & 0x02); m_intcxrom = (data & 0x01); // update the aux state