summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/machine
diff options
context:
space:
mode:
author arbee <rb6502@users.noreply.github.com>2020-05-23 19:30:21 -0400
committer arbee <rb6502@users.noreply.github.com>2020-05-23 19:30:21 -0400
commitf6cea0ce99b5424835d28c80f1d759a7c2a78e5d (patch)
tree03fb0cca148244019b13dbcfc1366106fb46ff1b /src/devices/machine
parent1c684902e29cea17232ad763956a9865fa651e69 (diff)
new files (nw)
Diffstat (limited to 'src/devices/machine')
-rwxr-xr-xsrc/devices/machine/applefdintf.cpp73
-rwxr-xr-xsrc/devices/machine/applefdintf.h103
-rw-r--r--src/devices/machine/iwm.cpp439
-rw-r--r--src/devices/machine/iwm.h88
-rw-r--r--src/devices/machine/swim1.cpp173
-rw-r--r--src/devices/machine/swim1.h48
-rw-r--r--src/devices/machine/swim2.cpp175
-rw-r--r--src/devices/machine/swim2.h48
-rw-r--r--src/devices/machine/swim3.cpp173
-rw-r--r--src/devices/machine/swim3.h48
10 files changed, 1368 insertions, 0 deletions
diff --git a/src/devices/machine/applefdintf.cpp b/src/devices/machine/applefdintf.cpp
new file mode 100755
index 00000000000..3b1590720c1
--- /dev/null
+++ b/src/devices/machine/applefdintf.cpp
@@ -0,0 +1,73 @@
+// license:BSD-3-Clause
+// copyright-holders:Nathan Woods, Raphael Nabet, R. Belmont
+
+#include "emu.h"
+#include "applefdintf.h"
+#include "formats/ap2_dsk.h"
+#include "formats/ap_dsk35.h"
+#include "formats/pc_dsk.h"
+
+FLOPPY_FORMATS_MEMBER(applefdintf_device::formats_525_13)
+ FLOPPY_EDD_FORMAT,
+ FLOPPY_WOZ_FORMAT
+FLOPPY_FORMATS_END
+
+FLOPPY_FORMATS_MEMBER(applefdintf_device::formats_525)
+ FLOPPY_A216S_FORMAT,
+ FLOPPY_RWTS18_FORMAT,
+ FLOPPY_EDD_FORMAT,
+ FLOPPY_WOZ_FORMAT
+FLOPPY_FORMATS_END
+
+FLOPPY_FORMATS_MEMBER(applefdintf_device::formats_35)
+ FLOPPY_DC42_FORMAT,
+ FLOPPY_PC_FORMAT
+FLOPPY_FORMATS_END
+
+void applefdintf_device::floppies_525(device_slot_interface &device)
+{
+ device.option_add("525", FLOPPY_525_SD);
+}
+
+void applefdintf_device::floppies_35(device_slot_interface &device)
+{
+ device.option_add("35", FLOPPY_35_HD);
+}
+
+applefdintf_device::applefdintf_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) :
+ device_t(mconfig, type, tag, owner, clock),
+ m_phases_cb(*this),
+ m_devsel_cb(*this),
+ m_sel35_cb(*this),
+ m_hdsel_cb(*this)
+{
+}
+
+void applefdintf_device::device_start()
+{
+ m_phases_cb.resolve_safe();
+ m_devsel_cb.resolve_safe();
+ m_sel35_cb.resolve_safe();
+ m_hdsel_cb.resolve_safe();
+ save_item(NAME(m_phases));
+ save_item(NAME(m_phases_input));
+}
+
+void applefdintf_device::device_reset()
+{
+ m_phases = 0xf0;
+ m_phases_input = 0x00;
+ update_phases();
+}
+
+void applefdintf_device::phases_w(u8 phases)
+{
+ m_phases_input = phases;
+ update_phases();
+}
+
+void applefdintf_device::update_phases()
+{
+ u8 mask = m_phases >> 4;
+ m_phases_cb((m_phases & mask) | (m_phases_input & (mask ^ 0xf)));
+}
diff --git a/src/devices/machine/applefdintf.h b/src/devices/machine/applefdintf.h
new file mode 100755
index 00000000000..c6cc7a2d451
--- /dev/null
+++ b/src/devices/machine/applefdintf.h
@@ -0,0 +1,103 @@
+// license:BSD-3-Clause
+// copyright-holders:O. Galibert
+/*********************************************************************
+
+ applefdintf.h
+
+ Common interface of various Apple Floppy Disk Controllers, implemented
+ in the classic Apple controller, the IWM and the SWIM variants
+
+
+*********************************************************************/
+
+#ifndef MAME_MACHINE_APPLEFDINTF_H
+#define MAME_MACHINE_APPLEFDINTF_H
+
+#pragma once
+
+#include "imagedev/floppy.h"
+
+class applefdintf_device : public device_t
+{
+public:
+ // read/write handlers for cpu access
+ virtual uint8_t read(offs_t offset) = 0;
+ virtual void write(offs_t offset, u8 data) = 0;
+
+ // phases line management
+ // Input from the exterior for the devices where they are bidirectional
+ void phases_w(u8 phases);
+ // Push output for when driven by the chip
+ auto phases_cb() { return m_phases_cb.bind(); }
+
+ // sel35 line when present (active high)
+ auto sel35_cb() { return m_sel35_cb.bind(); }
+
+ // drive select lines (two of them in the low bits, active high)
+ auto devsel_cb() { return m_devsel_cb.bind(); }
+
+ // hdsel line when present and in output mode (active high)
+ auto hdsel_cb() { return m_hdsel_cb.bind(); }
+
+ // floppy selection input, to be updated according to the previous callbacks,
+ // nullptr if none selected
+ virtual void set_floppy(floppy_image_device *floppy) = 0;
+
+ // get the currently selected floppy
+ virtual floppy_image_device *get_floppy() const = 0;
+
+ // Floppy formats
+ // 13-sector 5.25
+ DECLARE_FLOPPY_FORMATS(formats_525_13);
+
+ // 5.25
+ DECLARE_FLOPPY_FORMATS(formats_525);
+
+ // 3.5
+ DECLARE_FLOPPY_FORMATS(formats_35);
+
+ // Floppy drives slot-level
+ // 5.25
+ static void floppies_525(device_slot_interface &device);
+ template<typename T> static void add_525_13(machine_config &config, T &floppy) {
+ FLOPPY_CONNECTOR(config, floppy, floppies_525, "525", formats_525_13);
+ }
+ template<typename T> static void add_525_13_nc(machine_config &config, T &floppy) {
+ FLOPPY_CONNECTOR(config, floppy, floppies_525, "", formats_525_13);
+ }
+
+ template<typename T> static void add_525(machine_config &config, T &floppy) {
+ FLOPPY_CONNECTOR(config, floppy, floppies_525, "525", formats_525);
+ }
+ template<typename T> static void add_525_nc(machine_config &config, T &floppy) {
+ FLOPPY_CONNECTOR(config, floppy, floppies_525, "", formats_525);
+ }
+
+ // 3.5
+ static void floppies_35(device_slot_interface &device);
+ template<typename T> static void add_35(machine_config &config, T &floppy) {
+ FLOPPY_CONNECTOR(config, floppy, floppies_35, "35", formats_35);
+ }
+ template<typename T> static void add_35_nc(machine_config &config, T &floppy) {
+ FLOPPY_CONNECTOR(config, floppy, floppies_35, "", formats_35);
+ }
+
+protected:
+ devcb_write8 m_phases_cb, m_devsel_cb;
+ devcb_write_line m_sel35_cb, m_hdsel_cb;
+
+ // Current phase value in the bottom bits, input/output flags in the top bits
+ u8 m_phases;
+
+ // Current value of the driven external phases input
+ u8 m_phases_input;
+
+ applefdintf_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;
+
+ void update_phases();
+};
+
+#endif // MAME_MACHINE_APPLEFDINTF_H
diff --git a/src/devices/machine/iwm.cpp b/src/devices/machine/iwm.cpp
new file mode 100644
index 00000000000..e3524afbee4
--- /dev/null
+++ b/src/devices/machine/iwm.cpp
@@ -0,0 +1,439 @@
+// license:BSD-3-Clause
+// copyright-holders:Olivier Galibert
+/*********************************************************************
+
+ iwm.c
+
+ Implementation of the Apple IWM floppy disk controller
+
+*********************************************************************/
+
+#include "emu.h"
+#include "iwm.h"
+
+DEFINE_DEVICE_TYPE(IWM_FDC, iwm_device, "iwm", "Apple IWM floppy controller")
+
+iwm_device::iwm_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, uint32_t q3_clock) :
+ applefdintf_device(mconfig, IWM_FDC, tag, owner, clock),
+ m_q3_clock(q3_clock)
+{
+ m_q3_fclk_ratio = double(clock)/double(q3_clock); // ~0.25
+ m_fclk_q3_ratio = double(q3_clock)/double(clock); // ~4
+}
+
+u64 iwm_device::q3_to_fclk(u64 cycles) const
+{
+ return u64(m_q3_fclk_ratio * double(cycles) + 0.5);
+}
+
+u64 iwm_device::fclk_to_q3(u64 cycles) const
+{
+ return u64(m_fclk_q3_ratio * double(cycles) + 0.5);
+}
+
+void iwm_device::device_start()
+{
+ applefdintf_device::device_start();
+
+ m_timer = timer_alloc();
+ save_item(NAME(m_last_sync));
+ save_item(NAME(m_next_state_change));
+ save_item(NAME(m_sync_update));
+ save_item(NAME(m_async_update));
+ save_item(NAME(m_flux_write_start));
+ save_item(NAME(m_flux_write));
+ save_item(NAME(m_flux_write_count));
+ save_item(NAME(m_q3_clock));
+ save_item(NAME(m_active));
+ save_item(NAME(m_rw));
+ save_item(NAME(m_rw_state));
+ save_item(NAME(m_data));
+ save_item(NAME(m_whd));
+ save_item(NAME(m_mode));
+ save_item(NAME(m_status));
+ save_item(NAME(m_control));
+ save_item(NAME(m_rsh));
+ save_item(NAME(m_wsh));
+}
+
+void iwm_device::device_reset()
+{
+ applefdintf_device::device_reset();
+
+ m_floppy = nullptr;
+ m_last_sync = machine().time().as_ticks(clock());
+ m_next_state_change = 0;
+ m_active = MODE_IDLE;
+ m_rw = MODE_IDLE;
+ m_rw_state = S_IDLE;
+ m_data = 0x00;
+ m_whd = 0xff;
+ m_mode = 0x00;
+ m_status = 0x00;
+ m_control = 0x00;
+ m_wsh = 0x00;
+ m_rsh = 0x00;
+ m_flux_write_start = 0;
+ m_flux_write_count = 0;
+ m_devsel_cb(1);
+}
+
+void iwm_device::device_timer(emu_timer &, device_timer_id, int, void *)
+{
+ if(m_active == MODE_DELAY) {
+ m_active = MODE_IDLE;
+ if(m_floppy)
+ m_floppy->mon_w(true);
+ m_status &= ~0x20;
+ }
+}
+
+void iwm_device::set_floppy(floppy_image_device *floppy)
+{
+ if(m_floppy == floppy)
+ return;
+
+ sync();
+
+ if(m_floppy)
+ m_floppy->mon_w(true);
+ m_floppy = floppy;
+ if(m_active)
+ m_floppy->mon_w(false);
+ update_phases();
+}
+
+floppy_image_device *iwm_device::get_floppy() const
+{
+ return m_floppy;
+}
+
+uint8_t iwm_device::read(offs_t offset)
+{
+ return control(offset, 0x00);
+}
+
+void iwm_device::write(offs_t offset, u8 data)
+{
+ control(offset, data);
+}
+
+void iwm_device::flush_write()
+{
+ if(m_floppy && m_last_sync > m_flux_write_start) {
+ if(m_flux_write_count && m_flux_write[m_flux_write_count-1] == m_last_sync)
+ m_flux_write_count--;
+ attotime start = cycles_to_time(m_flux_write_start);
+ attotime end = cycles_to_time(m_last_sync);
+ std::vector<attotime> fluxes(m_flux_write_count);
+ for(u32 i=0; i != m_flux_write_count; i++)
+ fluxes[i] = cycles_to_time(m_flux_write[i]);
+ m_floppy->write_flux(start, end, m_flux_write_count, m_flux_write_count ? &fluxes[0] : nullptr);
+ }
+ m_flux_write_count = 0;
+ m_flux_write_start = m_last_sync;
+}
+
+u8 iwm_device::control(int offset, u8 data)
+{
+ sync();
+ logerror("control trigger %x, %02x\n", offset, data);
+ u8 changed = m_control | (m_phases & 0xf);
+ if(offset < 8) {
+ if(offset & 1)
+ m_phases |= 1 << (offset >> 1);
+ else
+ m_phases &= ~(1 << (offset >> 1));
+ update_phases();
+ } else {
+ if(offset & 1)
+ m_control |= 1 << (offset >> 1);
+ else
+ m_control &= ~(1 << (offset >> 1));
+ }
+
+ changed ^= m_control | (m_phases & 0xf);
+
+ if(changed & 0x20)
+ m_devsel_cb(m_control & 0x20 ? 2 : 1);
+
+ if(changed & 0x10) {
+ if(m_control & 0x10) {
+ m_active = MODE_ACTIVE;
+ if(m_floppy)
+ m_floppy->mon_w(false);
+ m_status |= 0x20;
+ } else {
+ if(m_mode & 0x04) {
+ m_active = MODE_IDLE;
+ if(m_floppy) {
+ m_floppy->mon_w(true);
+ m_floppy->seek_phase_w(0);
+ }
+ m_status &= ~0x20;
+ } else {
+ m_active = MODE_DELAY;
+ m_timer->adjust(cycles_to_time(8388608));
+ }
+ }
+ }
+
+ if(changed & 0xd0) {
+ if((m_control & 0xc0) == 0x00 && m_active) {
+ if(m_rw == MODE_WRITE)
+ flush_write();
+ m_rw = MODE_READ;
+ m_rw_state = S_IDLE;
+ m_next_state_change = 0;
+ m_sync_update = 0;
+ m_async_update = 0;
+ m_data = 0x00;
+
+ } else if((m_control & 0xc0) == 0xc0 && (changed & 0xc0) == 0x40 && m_active && m_rw != MODE_WRITE) {
+ m_rw = MODE_WRITE;
+ m_rw_state = S_IDLE;
+ m_next_state_change = 0;
+ m_flux_write_start = m_last_sync;
+ m_flux_write_count = 0;
+ if(m_floppy)
+ m_floppy->set_write_splice(cycles_to_time(m_flux_write_start));
+
+ } else if(m_rw == MODE_WRITE) {
+ if(!(m_control & 0x80)) {
+ flush_write();
+ m_rw = MODE_IDLE;
+ }
+ } else
+ m_rw = MODE_IDLE;
+ }
+
+ if(changed || 1) {
+ u8 s = m_control & 0xc0;
+ const char *slot = "?";
+ if(s == 0x00 && !m_active)
+ slot = "idle / ff";
+ if(s == 0x00 && m_active)
+ slot = "read / read data";
+ if(s == 0x40)
+ slot = "wp sense / read status";
+ if(s == 0x80)
+ slot = "write / read whd";
+ if(s == 0xc0 && !m_active)
+ slot = "mode set / write mode";
+ if(s == 0xc0 && m_active)
+ slot = "write load / write data";
+
+ logerror("control %c%c %c%c %c%c%c%c (%s) [%s, %s]\n",
+ m_control & 0x80 ? '1' : '0',
+ m_control & 0x40 ? '1' : '0',
+ m_control & 0x20 ? 'b' : 'a',
+ m_control & 0x10 ? '#' : '.',
+ m_phases & 0x08 ? '#' : '.',
+ m_phases & 0x04 ? '#' : '.',
+ m_phases & 0x02 ? '#' : '.',
+ m_phases & 0x01 ? '#' : '.',
+ slot,
+ m_active == MODE_IDLE ? "idle" : m_active == MODE_DELAY ? "delay" : "active",
+ m_rw == MODE_IDLE ? "idle" : m_rw == MODE_READ ? "read" : "write");
+ }
+
+ if(m_active && !(m_control & 0xc0) && !is_sync() && (m_data & 0x80))
+ m_async_update = m_last_sync + 14;
+
+ switch(m_control & 0xc0) {
+ case 0x00: return m_active ? m_data : 0xff;
+ case 0x40: return m_status;
+ case 0x80: return m_whd;
+ case 0xc0: if(offset & 1) { if(m_active) data_w(data); else mode_w(data); } return 0xff;
+ }
+
+ abort();
+}
+
+void iwm_device::mode_w(u8 data)
+{
+ m_mode = data;
+ m_status = (m_status & 0xe0) | (data & 0x1f);
+ logerror("mode %02x%s%s%s%s%s%s%s\n", m_mode,
+ m_mode & 0x80 ? " b7" : "",
+ m_mode & 0x40 ? " mz-reset" : "",
+ m_mode & 0x20 ? " test" : " normal",
+ m_mode & 0x10 ? " 8MHz" : " 7MHz",
+ m_mode & 0x08 ? " fast" : " slow",
+ m_mode & 0x04 ? "" : " timer",
+ m_mode & 0x02 ? " async" : " sync",
+ m_mode & 0x01 ? " latched" : "");
+}
+
+void iwm_device::data_w(u8 data)
+{
+ m_data = data;
+ if(is_sync() && m_rw == MODE_WRITE)
+ m_wsh = data;
+}
+
+u64 iwm_device::time_to_cycles(const attotime &tm) const
+{
+ return tm.as_ticks(clock());
+}
+
+attotime iwm_device::cycles_to_time(u64 cycles) const
+{
+ return attotime::from_ticks(cycles, clock());
+}
+
+bool iwm_device::is_sync() const
+{
+ return m_mode & 0x02 ? false : true;
+}
+
+u64 iwm_device::half_window_size() const
+{
+ switch(m_mode & 0x18) {
+ case 0x00: return 14;
+ case 0x08: return 7;
+ case 0x10: return 16;
+ case 0x18: return 8;
+ }
+ abort();
+}
+
+u64 iwm_device::window_size() const
+{
+ switch(m_mode & 0x18) {
+ case 0x00: return 28;
+ case 0x08: return 14;
+ case 0x10: return 36;
+ case 0x18: return 16;
+ }
+ abort();
+}
+
+u64 iwm_device::read_register_update_delay() const
+{
+ return m_mode & 0x08 ? 4 : 8;
+}
+
+u64 iwm_device::write_sync_half_window_size() const
+{
+ return m_mode & 0x08 ? 2 : 4;
+}
+
+void iwm_device::sync()
+{
+ if(!m_active)
+ return;
+
+ u64 next_sync = machine().time().as_ticks(clock());
+ switch(m_rw) {
+ case MODE_IDLE:
+ m_last_sync = next_sync;
+ break;
+
+ case MODE_READ: {
+ u64 next_flux_change = 0;
+ while(next_sync > m_last_sync) {
+ if(next_flux_change <= m_last_sync) {
+ attotime flux = m_floppy ? m_floppy->get_next_transition(cycles_to_time(m_last_sync+1)) : attotime::never;
+ next_flux_change = flux.is_never() ? u64(-1) : time_to_cycles(flux);
+ if(next_flux_change <= m_last_sync)
+ next_flux_change = m_last_sync+1;
+ }
+ if(next_sync < m_next_state_change) {
+ m_last_sync = next_sync;
+ break;
+ }
+ if(m_last_sync < m_next_state_change)
+ m_last_sync = m_next_state_change;
+ switch(m_rw_state) {
+ case S_IDLE:
+ m_rsh = 0x00;
+ m_rw_state = SR_WINDOW_EDGE_0;
+ m_next_state_change = m_last_sync + window_size();
+ m_sync_update = 0;
+ m_async_update = 0;
+ break;
+
+ case SR_WINDOW_EDGE_0:
+ case SR_WINDOW_EDGE_1: {
+ u64 endw = m_next_state_change + (m_rw_state == SR_WINDOW_EDGE_0 ? window_size() : half_window_size());
+ if(m_rw_state == SR_WINDOW_EDGE_0 && endw >= next_flux_change && next_sync >= next_flux_change) {
+ m_last_sync = m_next_state_change = next_flux_change;
+ m_rw_state = SR_WINDOW_EDGE_1;
+ break;
+ }
+ if(next_sync < endw) {
+ m_last_sync = next_sync;
+ break;
+ }
+ m_rsh = (m_rsh << 1) | (m_rw_state == SR_WINDOW_EDGE_1 ? 1 : 0);
+ m_next_state_change = m_last_sync = endw;
+ m_rw_state = SR_WINDOW_EDGE_0;
+ if(is_sync()) {
+ if(m_rsh >= 0x80) {
+ m_data = m_rsh;
+ m_rsh = 0;
+ } else if(m_rsh >= 0x04) {
+ m_data = m_rsh;
+ m_sync_update = 0;
+ } else if(m_rsh >= 0x02)
+ m_sync_update = m_last_sync + read_register_update_delay();
+
+ } else if(m_rsh >= 0x80) {
+ m_data = m_rsh;
+ m_rsh = 0;
+ }
+ break;
+ }
+ }
+ }
+ if(m_sync_update && m_sync_update <= m_last_sync) {
+ if(is_sync())
+ m_data = m_rsh;
+ m_sync_update = 0;
+ }
+ if(m_async_update && m_async_update <= m_last_sync) {
+ if(!is_sync()) {
+ m_data = 0;
+ }
+ m_async_update = 0;
+ }
+ break;
+ }
+
+ case MODE_WRITE: {
+ while(next_sync > m_last_sync) {
+ if(next_sync < m_next_state_change) {
+ m_last_sync = next_sync;
+ break;
+ }
+ if(m_last_sync < m_next_state_change)
+ m_last_sync = m_next_state_change;
+ switch(m_rw_state) {
+ case S_IDLE:
+ m_wsh = m_data;
+ m_rw_state = SW_WINDOW_MIDDLE;
+ m_next_state_change = q3_to_fclk(fclk_to_q3(m_last_sync) + write_sync_half_window_size());
+ m_flux_write_count = 0;
+ break;
+
+ case SW_WINDOW_MIDDLE:
+ if(m_wsh & 0x80)
+ m_flux_write[m_flux_write_count++] = m_last_sync;
+ m_wsh <<= 1;
+ m_next_state_change = q3_to_fclk(fclk_to_q3(m_last_sync) + write_sync_half_window_size());
+
+ m_rw_state = SW_WINDOW_END;
+ break;
+ case SW_WINDOW_END:
+ if(m_flux_write_count == m_flux_write.size())
+ flush_write();
+ m_next_state_change = q3_to_fclk(fclk_to_q3(m_last_sync) + write_sync_half_window_size());
+ m_rw_state = SW_WINDOW_MIDDLE;
+ break;
+ }
+ }
+ break;
+ }
+}
+}
diff --git a/src/devices/machine/iwm.h b/src/devices/machine/iwm.h
new file mode 100644
index 00000000000..6bb48f5043b
--- /dev/null
+++ b/src/devices/machine/iwm.h
@@ -0,0 +1,88 @@
+// license:BSD-3-Clause
+// copyright-holders:Olivier Galibert
+/*********************************************************************
+
+ Apple IWM floppy disk controller
+
+*********************************************************************/
+
+#pragma once
+
+#ifndef MAME_MACHINE_IWM_H
+#define MAME_MACHINE_IWM_H
+
+#include "applefdintf.h"
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+
+class iwm_device: public applefdintf_device
+{
+public:
+ // construction/destruction
+ iwm_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, uint32_t q3_clock = 0);
+ iwm_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, XTAL q3_clock) :
+ iwm_device(mconfig, tag, owner, clock, q3_clock.value()) {}
+
+ virtual u8 read(offs_t offset) override;
+ virtual void write(offs_t offset, u8 data) override;
+
+ virtual void set_floppy(floppy_image_device *floppy) override;
+ virtual floppy_image_device *get_floppy() const override;
+
+protected:
+ virtual void device_start() override;
+ virtual void device_reset() override;
+ virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+
+private:
+ enum {
+ MODE_IDLE,
+ MODE_ACTIVE, MODE_DELAY, // m_active modes
+ MODE_READ, MODE_WRITE // m_rw modes
+ };
+
+ // state machine states
+ enum {
+ S_IDLE,
+ SR_WINDOW_EDGE_0,
+ SR_WINDOW_EDGE_1,
+ SW_WINDOW_MIDDLE,
+ SW_WINDOW_END
+ };
+
+ floppy_image_device *m_floppy;
+ emu_timer *m_timer;
+ double m_q3_fclk_ratio, m_fclk_q3_ratio;
+ u64 m_last_sync, m_next_state_change, m_sync_update, m_async_update;
+ u64 m_flux_write_start;
+ std::array<u64, 16> m_flux_write;
+ u32 m_flux_write_count;
+ u32 m_q3_clock;
+ int m_active, m_rw, m_rw_state;
+ u8 m_data, m_whd, m_mode, m_status, m_control;
+ u8 m_rsh, m_wsh;
+
+ void sync();
+ u8 control(int offset, u8 data);
+ u64 time_to_cycles(const attotime &tm) const;
+ attotime cycles_to_time(u64 cycles) const;
+ u64 fclk_to_q3(u64 cycles) const;
+ u64 q3_to_fclk(u64 cycles) const;
+
+ void mode_w(u8 data);
+ void data_w(u8 data);
+
+ u64 window_size() const;
+ u64 half_window_size() const;
+ u64 read_register_update_delay() const;
+ u64 write_sync_half_window_size() const;
+ inline bool is_sync() const;
+ void flush_write();
+};
+
+DECLARE_DEVICE_TYPE(IWM, iwm_device)
+
+#endif /* MAME_MACHINE_IWM_H */
diff --git a/src/devices/machine/swim1.cpp b/src/devices/machine/swim1.cpp
new file mode 100644
index 00000000000..1af6cb60301
--- /dev/null
+++ b/src/devices/machine/swim1.cpp
@@ -0,0 +1,173 @@
+// license:BSD-3-Clause
+// copyright-holders:Olivier Galibert
+/*********************************************************************
+
+ Implementation of the Apple SWIM1 floppy disk controller
+
+*********************************************************************/
+
+#include "emu.h"
+#include "swim1.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) :
+ applefdintf_device(mconfig, SWIM1, tag, owner, clock)
+{
+}
+
+void swim1_device::device_start()
+{
+ applefdintf_device::device_start();
+ save_item(NAME(m_mode));
+ save_item(NAME(m_setup));
+ save_item(NAME(m_param_idx));
+ save_item(NAME(m_param));
+}
+
+void swim1_device::device_reset()
+{
+ applefdintf_device::device_reset();
+ m_mode = 0x40;
+ m_setup = 0x00;
+ m_param_idx = 0;
+ memset(m_param, 0, sizeof(m_param));
+ m_floppy = nullptr;
+
+ m_devsel_cb(0);
+ m_sel35_cb(true);
+ m_hdsel_cb(false);
+}
+
+void swim1_device::device_timer(emu_timer &, device_timer_id, int, void *)
+{
+}
+
+void swim1_device::set_floppy(floppy_image_device *floppy)
+{
+ if(m_floppy == floppy)
+ return;
+
+ if(m_floppy)
+ m_floppy->mon_w(true);
+ m_floppy = floppy;
+ if(m_mode & 0x80)
+ m_floppy->mon_w(false);
+ update_phases();
+}
+
+floppy_image_device *swim1_device::get_floppy() const
+{
+ return m_floppy;
+}
+
+void swim1_device::show_mode() const
+{
+ logerror("mode%s %s hdsel=%c %c%s %c%c%s\n",
+ m_mode & 0x80 ? " motoron" : "",
+ m_mode & 0x40 ? "ism" : "iwm",
+ m_mode & 0x20 ? '1' : '0',
+ m_mode & 0x10 ? 'w' : 'r',
+ m_mode & 0x08 ? " action" : "",
+ m_mode & 0x04 ? 'a' : '-',
+ m_mode & 0x02 ? 'b' : '-',
+ m_mode & 0x01 ? " clear" : "");
+
+}
+
+u8 swim1_device::read(offs_t offset)
+{
+ static const char *const names[] = {
+ "?0", "?1", "?2", "?3", "?4", "?5", "?6", "?7",
+ "data", "mark", "crc", "param", "phases", "setup", "status", "handshake"
+ };
+ switch(offset) {
+ case 0x3: case 0xb: {
+ u8 r = m_param[m_param_idx];
+ m_param_idx = (m_param_idx + 1) & 15;
+ return r;
+ }
+ case 0x4: case 0xc:
+ return m_phases;
+ case 0x5: case 0xd:
+ return m_setup;
+ case 0xe:
+ return m_mode;
+ default:
+ logerror("read %s\n", names[offset & 15]);
+ break;
+ }
+ return 0xff;
+}
+
+void swim1_device::write(offs_t offset, u8 data)
+{
+ machine().debug_break();
+ static const char *const names[] = {
+ "data", "mark", "crc", "param", "phases", "setup", "mode0", "mode1",
+ "?8", "?9", "?a", "?b", "?c", "?d", "?e", "?f"
+ };
+ switch(offset) {
+ case 0x3: case 0xb: {
+#if 0
+ static const char *const pname[16] = {
+ "minct", "mult", "ssl", "sss", "sll", "sls", "rpt", "csls",
+ "lsl", "lss", "lll", "lls", "late", "time0", "early", "time1"
+ };
+#endif
+ static const char *const pname[4] = {
+ "late", "time0", "early", "time1"
+ };
+ logerror("param[%s] = %02x\n", pname[m_param_idx], data);
+ m_param[m_param_idx] = data;
+ m_param_idx = (m_param_idx + 1) & 3;
+ break;
+ }
+ case 0x4: {
+ m_phases = data;
+ update_phases();
+ break;
+ }
+
+ case 0x5: case 0xd:
+ m_setup = data;
+#if 0
+ logerror("setup timer=%s tsm=%s %s ecm=%s %s %s 3.5=%s %s\n",
+ m_setup & 0x80 ? "on" : "off",
+ m_setup & 0x40 ? "off" : "on",
+ m_setup & 0x20 ? "ibm" : "apple",
+ m_setup & 0x10 ? "on" : "off",
+ m_setup & 0x08 ? "fclk/2" : "fclk",
+ m_setup & 0x04 ? "gcr" : "mfm",
+ m_setup & 0x02 ? "off" : "on",
+ m_setup & 0x01 ? "hdsel" : "q3");
+#endif
+ logerror("setup timer=%s tsm=%s %s ecm=%s %s %s 3.5=%s %s\n",
+ m_setup & 0x80 ? "on" : "off",
+ m_setup & 0x40 ? "off" : "on",
+ m_setup & 0x20 ? "ibm" : "apple",
+ m_setup & 0x10 ? "on" : "off",
+ m_setup & 0x08 ? "fclk/2" : "fclk",
+ m_setup & 0x04 ? "gcr" : "mfm",
+ m_setup & 0x02 ? "off" : "on",
+ m_setup & 0x01 ? "hdsel" : "q3");
+ break;
+
+ case 0x6:
+ m_mode &= ~data;
+ m_mode |= 0x40;
+ m_param_idx = 0;
+ show_mode();
+ break;
+
+ case 0x7:
+ m_mode |= data;
+ show_mode();
+ break;
+
+ default:
+ logerror("write %s, %02x\n", names[offset], data);
+ break;
+ }
+}
+
diff --git a/src/devices/machine/swim1.h b/src/devices/machine/swim1.h
new file mode 100644
index 00000000000..ce47069516f
--- /dev/null
+++ b/src/devices/machine/swim1.h
@@ -0,0 +1,48 @@
+// license:BSD-3-Clause
+// copyright-holders:Olivier Galibert
+/*********************************************************************
+
+ Apple SWIM1 floppy disk controller
+
+*********************************************************************/
+
+#pragma once
+
+#ifndef MAME_MACHINE_SWIM1_H
+#define MAME_MACHINE_SWIM1_H
+
+#include "applefdintf.h"
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+
+class swim1_device : public applefdintf_device
+{
+public:
+ // construction/destruction
+ swim1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ virtual u8 read(offs_t offset) override;
+ virtual void write(offs_t offset, u8 data) override;
+
+ virtual void set_floppy(floppy_image_device *floppy) override;
+ virtual floppy_image_device *get_floppy() const override;
+
+protected:
+ virtual void device_start() override;
+ virtual void device_reset() override;
+ virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+
+private:
+ floppy_image_device *m_floppy;
+ u8 m_param[4];
+ u8 m_mode, m_setup, m_param_idx;
+
+ void show_mode() const;
+};
+
+DECLARE_DEVICE_TYPE(SWIM1, swim1_device)
+
+#endif /* MAME_MACHINE_SWIM1_H */
diff --git a/src/devices/machine/swim2.cpp b/src/devices/machine/swim2.cpp
new file mode 100644
index 00000000000..165345d1523
--- /dev/null
+++ b/src/devices/machine/swim2.cpp
@@ -0,0 +1,175 @@
+// license:BSD-3-Clause
+// copyright-holders:Olivier Galibert
+/*********************************************************************
+
+ Implementation of the Apple SWIM2 floppy disk controller
+
+*********************************************************************/
+
+#include "emu.h"
+#include "swim2.h"
+
+DEFINE_DEVICE_TYPE(SWIM2, swim2_device, "swim2", "Apple SWIM2 (Sander/Wozniak Integrated Machine) version 2 floppy controller")
+
+swim2_device::swim2_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ applefdintf_device(mconfig, SWIM2, tag, owner, clock)
+{
+}
+
+void swim2_device::device_start()
+{
+ applefdintf_device::device_start();
+
+ save_item(NAME(m_mode));
+ save_item(NAME(m_setup));
+ save_item(NAME(m_param_idx));
+ save_item(NAME(m_param));
+}
+
+void swim2_device::device_reset()
+{
+ applefdintf_device::device_reset();
+
+ m_mode = 0x40;
+ m_setup = 0x00;
+ m_param_idx = 0;
+ memset(m_param, 0, sizeof(m_param));
+ m_floppy = nullptr;
+
+ m_devsel_cb(0);
+ m_sel35_cb(true);
+ m_hdsel_cb(false);
+}
+
+void swim2_device::device_timer(emu_timer &, device_timer_id, int, void *)
+{
+}
+
+void swim2_device::set_floppy(floppy_image_device *floppy)
+{
+ if(m_floppy == floppy)
+ return;
+
+ if(m_floppy)
+ m_floppy->mon_w(true);
+ m_floppy = floppy;
+ if(m_mode & 0x80)
+ m_floppy->mon_w(false);
+ update_phases();
+}
+
+floppy_image_device *swim2_device::get_floppy() const
+{
+ return m_floppy;
+}
+
+void swim2_device::show_mode() const
+{
+ logerror("mode%s %s hdsel=%c %c%s %c%c%s\n",
+ m_mode & 0x80 ? " motoron" : "",
+ m_mode & 0x40 ? "ism" : "iwm",
+ m_mode & 0x20 ? '1' : '0',
+ m_mode & 0x10 ? 'w' : 'r',
+ m_mode & 0x08 ? " action" : "",
+ m_mode & 0x04 ? 'a' : '-',
+ m_mode & 0x02 ? 'b' : '-',
+ m_mode & 0x01 ? " clear" : "");
+
+}
+
+u8 swim2_device::read(offs_t offset)
+{
+ static const char *const names[] = {
+ "?0", "?1", "?2", "?3", "?4", "?5", "?6", "?7",
+ "data", "mark", "crc", "param", "phases", "setup", "status", "handshake"
+ };
+ switch(offset) {
+ case 0x3: case 0xb: {
+ u8 r = m_param[m_param_idx];
+ m_param_idx = (m_param_idx + 1) & 15;
+ return r;
+ }
+ case 0x4: case 0xc:
+ return m_phases;
+ case 0x5: case 0xd:
+ return m_setup;
+ case 0xe:
+ return m_mode;
+ default:
+ logerror("read %s\n", names[offset & 15]);
+ break;
+ }
+ return 0xff;
+}
+
+void swim2_device::write(offs_t offset, u8 data)
+{
+ machine().debug_break();
+ static const char *const names[] = {
+ "data", "mark", "crc", "param", "phases", "setup", "mode0", "mode1",
+ "?8", "?9", "?a", "?b", "?c", "?d", "?e", "?f"
+ };
+ switch(offset) {
+ case 0x3: case 0xb: {
+#if 0
+ static const char *const pname[16] = {
+ "minct", "mult", "ssl", "sss", "sll", "sls", "rpt", "csls",
+ "lsl", "lss", "lll", "lls", "late", "time0", "early", "time1"
+ };
+#endif
+ static const char *const pname[4] = {
+ "late", "time0", "early", "time1"
+ };
+ logerror("param[%s] = %02x\n", pname[m_param_idx], data);
+ m_param[m_param_idx] = data;
+ m_param_idx = (m_param_idx + 1) & 3;
+ break;
+ }
+ case 0x4: {
+ m_phases = data;
+ update_phases();
+ break;
+ }
+
+ case 0x5: case 0xd:
+ m_setup = data;
+#if 0
+ logerror("setup timer=%s tsm=%s %s ecm=%s %s %s 3.5=%s %s\n",
+ m_setup & 0x80 ? "on" : "off",
+ m_setup & 0x40 ? "off" : "on",
+ m_setup & 0x20 ? "ibm" : "apple",
+ m_setup & 0x10 ? "on" : "off",
+ m_setup & 0x08 ? "fclk/2" : "fclk",
+ m_setup & 0x04 ? "gcr" : "mfm",
+ m_setup & 0x02 ? "off" : "on",
+ m_setup & 0x01 ? "hdsel" : "q3");
+#endif
+ logerror("setup timer=%s tsm=%s %s ecm=%s %s %s 3.5=%s %s\n",
+ m_setup & 0x80 ? "on" : "off",
+ m_setup & 0x40 ? "off" : "on",
+ m_setup & 0x20 ? "ibm" : "apple",
+ m_setup & 0x10 ? "on" : "off",
+ m_setup & 0x08 ? "fclk/2" : "fclk",
+ m_setup & 0x04 ? "gcr" : "mfm",
+ m_setup & 0x02 ? "off" : "on",
+ m_setup & 0x01 ? "hdsel" : "q3");
+ break;
+
+ case 0x6:
+ m_mode &= ~data;
+ m_mode |= 0x40;
+ m_param_idx = 0;
+ show_mode();
+ break;
+
+ case 0x7:
+ m_mode |= data;
+ show_mode();
+ break;
+
+ default:
+ logerror("write %s, %02x\n", names[offset], data);
+ break;
+ }
+}
+
diff --git a/src/devices/machine/swim2.h b/src/devices/machine/swim2.h
new file mode 100644
index 00000000000..6a29a51356e
--- /dev/null
+++ b/src/devices/machine/swim2.h
@@ -0,0 +1,48 @@
+// license:BSD-3-Clause
+// copyright-holders:Olivier Galibert
+/*********************************************************************
+
+ Apple SWIM2 floppy disk controller
+
+*********************************************************************/
+
+#pragma once
+
+#ifndef MAME_MACHINE_SWIM2_H
+#define MAME_MACHINE_SWIM2_H
+
+#include "applefdintf.h"
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+
+class swim2_device : public applefdintf_device
+{
+public:
+ // construction/destruction
+ swim2_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ virtual u8 read(offs_t offset) override;
+ virtual void write(offs_t offset, u8 data) override;
+
+ virtual void set_floppy(floppy_image_device *floppy) override;
+ virtual floppy_image_device *get_floppy() const override;
+
+protected:
+ virtual void device_start() override;
+ virtual void device_reset() override;
+ virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+
+private:
+ floppy_image_device *m_floppy;
+ u8 m_param[4];
+ u8 m_mode, m_setup, m_param_idx;
+
+ void show_mode() const;
+};
+
+DECLARE_DEVICE_TYPE(SWIM2, swim2_device)
+
+#endif /* MAME_MACHINE_SWIM2_H */
diff --git a/src/devices/machine/swim3.cpp b/src/devices/machine/swim3.cpp
new file mode 100644
index 00000000000..9c836a0dc74
--- /dev/null
+++ b/src/devices/machine/swim3.cpp
@@ -0,0 +1,173 @@
+// license:BSD-3-Clause
+// copyright-holders:Olivier Galibert
+/*********************************************************************
+
+ Implementation of the Apple SWIM3 floppy disk controller
+
+*********************************************************************/
+
+#include "emu.h"
+#include "swim3.h"
+
+DEFINE_DEVICE_TYPE(SWIM3, swim3_device, "swim3", "Apple SWIM3 (Sander/Wozniak Integrated Machine) version 3 floppy controller")
+
+swim3_device::swim3_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ applefdintf_device(mconfig, SWIM3, tag, owner, clock)
+{
+}
+
+void swim3_device::device_start()
+{
+ applefdintf_device::device_start();
+ save_item(NAME(m_mode));
+ save_item(NAME(m_setup));
+ save_item(NAME(m_param_idx));
+ save_item(NAME(m_param));
+}
+
+void swim3_device::device_reset()
+{
+ applefdintf_device::device_reset();
+ m_mode = 0x40;
+ m_setup = 0x00;
+ m_param_idx = 0;
+ memset(m_param, 0, sizeof(m_param));
+ m_floppy = nullptr;
+
+ m_devsel_cb(0);
+ m_sel35_cb(true);
+ m_hdsel_cb(false);
+}
+
+void swim3_device::device_timer(emu_timer &, device_timer_id, int, void *)
+{
+}
+
+void swim3_device::set_floppy(floppy_image_device *floppy)
+{
+ if(m_floppy == floppy)
+ return;
+
+ if(m_floppy)
+ m_floppy->mon_w(true);
+ m_floppy = floppy;
+ if(m_mode & 0x80)
+ m_floppy->mon_w(false);
+ update_phases();
+}
+
+floppy_image_device *swim3_device::get_floppy() const
+{
+ return m_floppy;
+}
+
+void swim3_device::show_mode() const
+{
+ logerror("mode%s %s hdsel=%c %c%s %c%c%s\n",
+ m_mode & 0x80 ? " motoron" : "",
+ m_mode & 0x40 ? "ism" : "iwm",
+ m_mode & 0x20 ? '1' : '0',
+ m_mode & 0x10 ? 'w' : 'r',
+ m_mode & 0x08 ? " action" : "",
+ m_mode & 0x04 ? 'a' : '-',
+ m_mode & 0x02 ? 'b' : '-',
+ m_mode & 0x01 ? " clear" : "");
+
+}
+
+u8 swim3_device::read(offs_t offset)
+{
+ static const char *const names[] = {
+ "?0", "?1", "?2", "?3", "?4", "?5", "?6", "?7",
+ "data", "mark", "crc", "param", "phases", "setup", "status", "handshake"
+ };
+ switch(offset) {
+ case 0x3: case 0xb: {
+ u8 r = m_param[m_param_idx];
+ m_param_idx = (m_param_idx + 1) & 15;
+ return r;
+ }
+ case 0x4: case 0xc:
+ return m_phases;
+ case 0x5: case 0xd:
+ return m_setup;
+ case 0xe:
+ return m_mode;
+ default:
+ logerror("read %s\n", names[offset & 15]);
+ break;
+ }
+ return 0xff;
+}
+
+void swim3_device::write(offs_t offset, u8 data)
+{
+ machine().debug_break();
+ static const char *const names[] = {
+ "data", "mark", "crc", "param", "phases", "setup", "mode0", "mode1",
+ "?8", "?9", "?a", "?b", "?c", "?d", "?e", "?f"
+ };
+ switch(offset) {
+ case 0x3: case 0xb: {
+#if 0
+ static const char *const pname[16] = {
+ "minct", "mult", "ssl", "sss", "sll", "sls", "rpt", "csls",
+ "lsl", "lss", "lll", "lls", "late", "time0", "early", "time1"
+ };
+#endif
+ static const char *const pname[4] = {
+ "late", "time0", "early", "time1"
+ };
+ logerror("param[%s] = %02x\n", pname[m_param_idx], data);
+ m_param[m_param_idx] = data;
+ m_param_idx = (m_param_idx + 1) & 3;
+ break;
+ }
+ case 0x4: {
+ m_phases = data;
+ update_phases();
+ break;
+ }
+
+ case 0x5: case 0xd:
+ m_setup = data;
+#if 0
+ logerror("setup timer=%s tsm=%s %s ecm=%s %s %s 3.5=%s %s\n",
+ m_setup & 0x80 ? "on" : "off",
+ m_setup & 0x40 ? "off" : "on",
+ m_setup & 0x20 ? "ibm" : "apple",
+ m_setup & 0x10 ? "on" : "off",
+ m_setup & 0x08 ? "fclk/2" : "fclk",
+ m_setup & 0x04 ? "gcr" : "mfm",
+ m_setup & 0x02 ? "off" : "on",
+ m_setup & 0x01 ? "hdsel" : "q3");
+#endif
+ logerror("setup timer=%s tsm=%s %s ecm=%s %s %s 3.5=%s %s\n",
+ m_setup & 0x80 ? "on" : "off",
+ m_setup & 0x40 ? "off" : "on",
+ m_setup & 0x20 ? "ibm" : "apple",
+ m_setup & 0x10 ? "on" : "off",
+ m_setup & 0x08 ? "fclk/2" : "fclk",
+ m_setup & 0x04 ? "gcr" : "mfm",
+ m_setup & 0x02 ? "off" : "on",
+ m_setup & 0x01 ? "hdsel" : "q3");
+ break;
+
+ case 0x6:
+ m_mode &= ~data;
+ m_mode |= 0x40;
+ m_param_idx = 0;
+ show_mode();
+ break;
+
+ case 0x7:
+ m_mode |= data;
+ show_mode();
+ break;
+
+ default:
+ logerror("write %s, %02x\n", names[offset], data);
+ break;
+ }
+}
+
diff --git a/src/devices/machine/swim3.h b/src/devices/machine/swim3.h
new file mode 100644
index 00000000000..076a612377c
--- /dev/null
+++ b/src/devices/machine/swim3.h
@@ -0,0 +1,48 @@
+// license:BSD-3-Clause
+// copyright-holders:Olivier Galibert
+/*********************************************************************
+
+ Apple SWIM3 floppy disk controller
+
+*********************************************************************/
+
+#pragma once
+
+#ifndef MAME_MACHINE_SWIM3_H
+#define MAME_MACHINE_SWIM3_H
+
+#include "applefdintf.h"
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+
+class swim3_device : public applefdintf_device
+{
+public:
+ // construction/destruction
+ swim3_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ virtual u8 read(offs_t offset) override;
+ virtual void write(offs_t offset, u8 data) override;
+
+ virtual void set_floppy(floppy_image_device *floppy) override;
+ virtual floppy_image_device *get_floppy() const override;
+
+protected:
+ virtual void device_start() override;
+ virtual void device_reset() override;
+ virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+
+private:
+ floppy_image_device *m_floppy;
+ u8 m_param[4];
+ u8 m_mode, m_setup, m_param_idx;
+
+ void show_mode() const;
+};
+
+DECLARE_DEVICE_TYPE(SWIM3, swim3_device)
+
+#endif /* MAME_MACHINE_SWIM3_H */