From b3daa829c28f836d7e687ff6f4bf0c49048650f1 Mon Sep 17 00:00:00 2001 From: Olivier Galibert Date: Mon, 18 Jan 2021 22:50:26 +0100 Subject: [PATCH] swim1: Embed the iwm --- src/devices/machine/6522via.cpp | 15 + src/devices/machine/6522via.h | 3 + src/devices/machine/iwm.cpp | 37 +- src/devices/machine/iwm.h | 8 +- src/devices/machine/swim1.cpp | 622 ++++++++++++++++++++++++++++---- src/devices/machine/swim1.h | 66 +++- src/devices/machine/swim2.cpp | 36 +- src/mame/drivers/mac.cpp | 7 +- src/mame/machine/mac.cpp | 9 + 9 files changed, 673 insertions(+), 130 deletions(-) diff --git a/src/devices/machine/6522via.cpp b/src/devices/machine/6522via.cpp index 0027ba7389a..240de545092 100644 --- a/src/devices/machine/6522via.cpp +++ b/src/devices/machine/6522via.cpp @@ -576,6 +576,11 @@ void via6522_device::output_pa() m_out_a_handler(pa); } +uint8_t via6522_device::read_pa() const +{ + return (m_out_a & m_ddr_a) | ~m_ddr_a; +} + uint8_t via6522_device::input_pb() { uint8_t pb = m_in_b & ~m_ddr_b; @@ -604,6 +609,16 @@ void via6522_device::output_pb() m_out_b_handler(pb); } +uint8_t via6522_device::read_pb() const +{ + uint8_t pb = (m_out_b & m_ddr_b) | ~m_ddr_b; + + if (T1_SET_PB7(m_acr)) + pb = (pb & 0x7f) | (m_t1_pb7 << 7); + + return pb; +} + /*------------------------------------------------- via_r - CPU interface for VIA read -------------------------------------------------*/ diff --git a/src/devices/machine/6522via.h b/src/devices/machine/6522via.h index 164104190e4..013438f3ca7 100644 --- a/src/devices/machine/6522via.h +++ b/src/devices/machine/6522via.h @@ -113,6 +113,9 @@ public: void write_cb1(int state); void write_cb2(int state); + uint8_t read_pa() const; + uint8_t read_pb() const; + protected: // construction/destruction via6522_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); diff --git a/src/devices/machine/iwm.cpp b/src/devices/machine/iwm.cpp index 385561978b2..982371840ff 100644 --- a/src/devices/machine/iwm.cpp +++ b/src/devices/machine/iwm.cpp @@ -13,15 +13,24 @@ DEFINE_DEVICE_TYPE(IWM, 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) : +iwm_device::iwm_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, uint32_t q3_clock, bool disable_mon) : applefdintf_device(mconfig, IWM, tag, owner, clock), m_floppy(nullptr), - m_q3_clock(q3_clock) + m_q3_clock(q3_clock), + m_disable_mon(disable_mon) { - if (q3_clock != 0) - m_q3_fclk_ratio = double(clock)/double(q3_clock); // ~0.25 - if (clock != 0) - m_fclk_q3_ratio = double(q3_clock)/double(clock); // ~4 + m_q3_fclk_ratio = double(clock)/double(q3_clock); // ~0.25 + m_fclk_q3_ratio = double(q3_clock)/double(clock); // ~4 +} + +iwm_device::iwm_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : + applefdintf_device(mconfig, IWM, tag, owner, clock), + m_floppy(nullptr), + m_q3_clock(0), + m_disable_mon(false) +{ + m_q3_fclk_ratio = 0; + m_fclk_q3_ratio = 0; } u64 iwm_device::q3_to_fclk(u64 cycles) const @@ -84,8 +93,10 @@ void iwm_device::device_timer(emu_timer &, device_timer_id, int, void *) { if(m_active == MODE_DELAY) { m_active = MODE_IDLE; - if(m_floppy) + if(m_floppy && !m_disable_mon) m_floppy->mon_w(true); + if(m_disable_mon) + m_devsel_cb(0); m_status &= ~0x20; } } @@ -97,10 +108,10 @@ void iwm_device::set_floppy(floppy_image_device *floppy) sync(); - if(m_floppy) + if(m_floppy && !m_disable_mon) m_floppy->mon_w(true); m_floppy = floppy; - if(m_active) + if(m_active && !m_disable_mon) m_floppy->mon_w(false); update_phases(); } @@ -157,18 +168,18 @@ u8 iwm_device::control(int offset, u8 data) changed ^= m_control | (m_phases & 0xf); if(changed & 0x20) - m_devsel_cb(m_control & 0x20 ? 2 : 1); + m_devsel_cb(m_disable_mon && !(m_control & 0x10) ? 0 : m_control & 0x20 ? 2 : 1); if(changed & 0x10) { if(m_control & 0x10) { m_active = MODE_ACTIVE; - if(m_floppy) + if(m_floppy && !m_disable_mon) m_floppy->mon_w(false); m_status |= 0x20; } else { if(m_mode & 0x04) { m_active = MODE_IDLE; - if(m_floppy) { + if(m_floppy && !m_disable_mon) { m_floppy->mon_w(true); m_floppy->seek_phase_w(0); } @@ -244,7 +255,7 @@ u8 iwm_device::control(int offset, u8 data) switch(m_control & 0xc0) { case 0x00: return m_active ? m_data : 0xff; - case 0x40: return m_status; + case 0x40: return (m_status & 0x7f) | (!m_floppy || m_floppy->wpt_r() ? 0x80 : 0);; case 0x80: return m_whd; case 0xc0: if(offset & 1) { if(m_active) data_w(data); else mode_w(data); } return 0xff; } diff --git a/src/devices/machine/iwm.h b/src/devices/machine/iwm.h index 9c1f4214a68..b311feed299 100644 --- a/src/devices/machine/iwm.h +++ b/src/devices/machine/iwm.h @@ -22,9 +22,10 @@ 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()) {} + iwm_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + iwm_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, uint32_t q3_clock, bool disable_mon = false); + iwm_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, XTAL q3_clock, bool disable_mon = false) : + iwm_device(mconfig, tag, owner, clock, q3_clock.value(), disable_mon) {} virtual u8 read(offs_t offset) override; virtual void write(offs_t offset, u8 data) override; @@ -66,6 +67,7 @@ private: int m_active, m_rw, m_rw_state; u8 m_data, m_whd, m_mode, m_status, m_control; u8 m_rsh, m_wsh; + bool m_disable_mon; u8 control(int offset, u8 data); u64 time_to_cycles(const attotime &tm) const; diff --git a/src/devices/machine/swim1.cpp b/src/devices/machine/swim1.cpp index 70991e1b845..15f3e3b1a59 100644 --- a/src/devices/machine/swim1.cpp +++ b/src/devices/machine/swim1.cpp @@ -11,49 +11,92 @@ 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) +swim1_device::swim1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, uint32_t q3_clock) : + applefdintf_device(mconfig, SWIM1, tag, owner, clock), + m_q3_clock(q3_clock) { + m_iwm_q3_fclk_ratio = double(clock)/double(q3_clock); // ~0.125 + m_iwm_fclk_q3_ratio = double(q3_clock)/double(clock); // ~8 +} + +swim1_device::swim1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : + applefdintf_device(mconfig, SWIM1, tag, owner, clock), + m_q3_clock(0) +{ + m_iwm_q3_fclk_ratio = 0; + m_iwm_fclk_q3_ratio = 0; } 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)); + + save_item(NAME(m_last_sync)); + save_item(NAME(m_flux_write_start)); + save_item(NAME(m_flux_write)); + save_item(NAME(m_flux_write_count)); + + save_item(NAME(m_ism_mode)); + save_item(NAME(m_ism_setup)); + save_item(NAME(m_ism_param_idx)); + save_item(NAME(m_ism_param)); + + save_item(NAME(m_iwm_next_state_change)); + save_item(NAME(m_iwm_sync_update)); + save_item(NAME(m_iwm_async_update)); + save_item(NAME(m_iwm_active)); + save_item(NAME(m_iwm_rw)); + save_item(NAME(m_iwm_rw_state)); + save_item(NAME(m_iwm_data)); + save_item(NAME(m_iwm_whd)); + save_item(NAME(m_iwm_mode)); + save_item(NAME(m_iwm_status)); + save_item(NAME(m_iwm_control)); + save_item(NAME(m_iwm_rsh)); + save_item(NAME(m_iwm_wsh)); + save_item(NAME(m_iwm_to_ism_counter)); } 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_ism_mode = 0x00; + m_ism_setup = 0x00; + m_ism_param_idx = 0; + memset(m_ism_param, 0, sizeof(m_ism_param)); m_floppy = nullptr; + m_last_sync = machine().time().as_ticks(clock()); + m_flux_write_start = 0; + m_flux_write_count = 0; + + m_iwm_next_state_change = 0; + m_iwm_active = MODE_IDLE; + m_iwm_rw = MODE_IDLE; + m_iwm_rw_state = S_IDLE; + m_iwm_data = 0x00; + m_iwm_whd = 0xff; + m_iwm_mode = 0x00; + m_iwm_status = 0x00; + m_iwm_control = 0x00; + m_iwm_wsh = 0x00; + m_iwm_rsh = 0x00; + m_iwm_to_ism_counter = 0; + 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(); + if(m_ism_mode & 0x40) + m_hdsel_cb((m_ism_mode >> 5) & 1); } floppy_image_device *swim1_device::get_floppy() const @@ -61,116 +104,535 @@ floppy_image_device *swim1_device::get_floppy() const return m_floppy; } -void swim1_device::show_mode() const +void swim1_device::ism_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" : ""); + logerror("ism mode%s %s hdsel=%c %c%s %c%c%s\n", + m_ism_mode & 0x80 ? " motoron" : "", + m_ism_mode & 0x40 ? "ism" : "iwm", + m_ism_mode & 0x20 ? '1' : '0', + m_ism_mode & 0x10 ? 'w' : 'r', + m_ism_mode & 0x08 ? " action" : "", + m_ism_mode & 0x04 ? 'a' : '-', + m_ism_mode & 0x02 ? 'b' : '-', + m_ism_mode & 0x01 ? " clear" : ""); } u8 swim1_device::read(offs_t offset) +{ + if(m_ism_mode & 0x40) + return ism_read(offset); + else + return iwm_control(offset, 0x00); +} + +void swim1_device::write(offs_t offset, u8 data) +{ + if(m_ism_mode & 0x40) + ism_write(offset, data); + else + iwm_control(offset, data); +} + +u8 swim1_device::ism_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; + + logerror("read ism %s\n", names[offset & 7]); + switch(offset & 7) { + case 0x3: { + u8 r = m_ism_param[m_ism_param_idx]; + m_ism_param_idx = (m_ism_param_idx + 1) & 15; return r; } - case 0x4: case 0xc: + + case 0x4: // phases return m_phases; - case 0x5: case 0xd: - return m_setup; - case 0xe: - return m_mode; + + case 0x5: // setup + return m_ism_setup; + + case 0x6: // mode + return m_ism_mode; + default: - logerror("read %s\n", names[offset & 15]); + // logerror("read %s\n", names[offset & 7]); break; } return 0xff; } -void swim1_device::write(offs_t offset, u8 data) +void swim1_device::ism_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 + case 0x3: { 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; + logerror("param[%s] = %02x\n", pname[m_ism_param_idx], data); + m_ism_param[m_ism_param_idx] = data; + m_ism_param_idx = (m_ism_param_idx + 1) & 15; break; } case 0x4: { + logerror("ism phases %02x\n", data); m_phases = data; update_phases(); break; } - case 0x5: case 0xd: - m_setup = data; -#if 0 + case 0x5: + m_ism_setup = data; 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"); + m_ism_setup & 0x80 ? "on" : "off", + m_ism_setup & 0x40 ? "off" : "on", + m_ism_setup & 0x20 ? "ibm" : "apple", + m_ism_setup & 0x10 ? "on" : "off", + m_ism_setup & 0x08 ? "fclk/2" : "fclk", + m_ism_setup & 0x04 ? "gcr" : "mfm", + m_ism_setup & 0x02 ? "off" : "on", + m_ism_setup & 0x01 ? "hdsel" : "q3"); break; case 0x6: - m_mode &= ~data; - m_mode |= 0x40; - m_param_idx = 0; - show_mode(); + m_ism_mode &= ~data; + m_ism_param_idx = 0; + ism_show_mode(); + if(!(m_ism_mode & 0x40)) + logerror("switch to iwm\n"); break; case 0x7: - m_mode |= data; - show_mode(); + m_ism_mode |= data; + ism_show_mode(); break; default: - logerror("write %s, %02x\n", names[offset], data); + logerror("write %s, %02x\n", names[offset & 7], data); break; } } -void swim1_device::sync() +void swim1_device::device_timer(emu_timer &, device_timer_id, int, void *) +{ + if(m_iwm_active == MODE_DELAY) { + m_iwm_active = MODE_IDLE; + m_iwm_status &= ~0x20; + m_devsel_cb(0); + } +} + +void swim1_device::flush_write(u64 when) +{ + if(!m_flux_write_start) + return; + + if(!when) + when = m_last_sync; + + if(m_floppy && when > m_flux_write_start) { + if(m_flux_write_count && m_flux_write[m_flux_write_count-1] == when) + m_flux_write_count--; + attotime start = cycles_to_time(m_flux_write_start); + attotime end = cycles_to_time(when); + std::vector 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 = when; +} + +u8 swim1_device::iwm_control(int offset, u8 data) +{ + sync(); + u8 prev_iwm_to_ism_counter = m_iwm_to_ism_counter; + + logerror("iwm control trigger %x, %02x\n", offset, data); + u8 changed = m_iwm_control | (m_phases & 0xf); + if(offset < 8) { + if(offset & 1) + m_phases |= 1 << (offset >> 1); + else + m_phases &= ~(1 << (offset >> 1)); + update_phases(); + machine().debug_break(); + } else { + if(offset & 1) + m_iwm_control |= 1 << (offset >> 1); + else + m_iwm_control &= ~(1 << (offset >> 1)); + } + + changed ^= m_iwm_control | (m_phases & 0xf); + + if(changed & 0x30) + m_devsel_cb(m_iwm_control & 0x10 ? m_iwm_control & 0x20 ? 2 : 1 : 0); + + if(changed & 0x10) { + if(m_iwm_control & 0x10) { + m_iwm_active = MODE_ACTIVE; + m_iwm_status |= 0x20; + } else { + if(m_iwm_mode & 0x04) { + m_iwm_active = MODE_IDLE; + m_iwm_status &= ~0x20; + m_devsel_cb(0); + } else { + m_iwm_active = MODE_DELAY; + m_timer->adjust(cycles_to_time(8388608)); + } + } + } + + if(changed & 0xd0) { + if((m_iwm_control & 0xc0) == 0x00 && m_iwm_active) { + if(m_iwm_rw == MODE_WRITE) + flush_write(); + m_iwm_rw = MODE_READ; + m_iwm_rw_state = S_IDLE; + m_iwm_next_state_change = 0; + m_iwm_sync_update = 0; + m_iwm_async_update = 0; + m_iwm_data = 0x00; + + } else if((m_iwm_control & 0xc0) == 0xc0 && (changed & 0xc0) == 0x40 && m_iwm_active && m_iwm_rw != MODE_WRITE) { + m_iwm_rw = MODE_WRITE; + m_iwm_rw_state = S_IDLE; + m_iwm_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_iwm_rw == MODE_WRITE) { + if(!(m_iwm_control & 0x80)) { + flush_write(); + m_iwm_rw = MODE_IDLE; + } + } else + m_iwm_rw = MODE_IDLE; + } + + if(changed || 1) { + u8 s = m_iwm_control & 0xc0; + const char *slot = "?"; + if(s == 0x00 && !m_iwm_active) + slot = "idle / ff"; + if(s == 0x00 && m_iwm_active) + slot = "read / read data"; + if(s == 0x40) + slot = "wp sense / read status"; + if(s == 0x80) + slot = "write / read whd"; + if(s == 0xc0 && !m_iwm_active) + slot = "mode set / write mode"; + if(s == 0xc0 && m_iwm_active) + slot = "write load / write data"; + + logerror("control %c%c %c%c %c%c%c%c (%s) [%s, %s]\n", + m_iwm_control & 0x80 ? '1' : '0', + m_iwm_control & 0x40 ? '1' : '0', + m_iwm_control & 0x20 ? 'b' : 'a', + m_iwm_control & 0x10 ? '#' : '.', + m_phases & 0x08 ? '#' : '.', + m_phases & 0x04 ? '#' : '.', + m_phases & 0x02 ? '#' : '.', + m_phases & 0x01 ? '#' : '.', + slot, + m_iwm_active == MODE_IDLE ? "idle" : m_iwm_active == MODE_DELAY ? "delay" : "active", + m_iwm_rw == MODE_IDLE ? "idle" : m_iwm_rw == MODE_READ ? "read" : "write"); + } + + if(m_iwm_active && !(m_iwm_control & 0xc0) && !iwm_is_sync() && (m_iwm_data & 0x80)) + m_iwm_async_update = m_last_sync + 14; + + if(offset == 0xf) { + switch(m_iwm_to_ism_counter) { + case 0: case 2: + if(data & 0x40) + m_iwm_to_ism_counter++; + break; + case 1: + if(!(data & 0x40)) + m_iwm_to_ism_counter++; + break; + case 3: + if(data & 0x40) { + m_ism_mode |= 0x40; + machine().debug_break(); + logerror("switch to ism\n"); + } + break; + } + } + if(m_iwm_to_ism_counter != prev_iwm_to_ism_counter+1) + m_iwm_to_ism_counter = 0; + else + logerror("iwm counter = %d\n", m_iwm_to_ism_counter); + + switch(m_iwm_control & 0xc0) { + case 0x00: return m_iwm_active ? m_iwm_data : 0xff; + case 0x40: return (m_iwm_status & 0x7f) | (!m_floppy || m_floppy->wpt_r() ? 0x80 : 0); + case 0x80: return m_iwm_whd; + case 0xc0: if(offset & 1) { if(m_iwm_active) iwm_data_w(data); else iwm_mode_w(data); } return 0xff; + } + + abort(); +} + +void swim1_device::ism_crc_clear() +{ + m_ism_crc = 0xcdb4; +} + +void swim1_device::ism_crc_update(int bit) +{ + if((m_ism_crc ^ (bit ? 0x8000 : 0x0000)) & 0x8000) + m_ism_crc = (m_ism_crc << 1) ^ 0x1021; + else + m_ism_crc = m_ism_crc << 1; + +} + +u64 swim1_device::time_to_cycles(const attotime &tm) const +{ + return tm.as_ticks(clock()); +} + +attotime swim1_device::cycles_to_time(u64 cycles) const +{ + return attotime::from_ticks(cycles, clock()); +} + +u64 swim1_device::iwm_q3_to_fclk(u64 cycles) const +{ + return u64(m_iwm_q3_fclk_ratio * double(cycles) + 0.5); +} + +u64 swim1_device::iwm_fclk_to_q3(u64 cycles) const +{ + return u64(m_iwm_fclk_q3_ratio * double(cycles) + 0.5); +} + +void swim1_device::ism_fifo_clear() +{ + m_ism_fifo_pos = 0; + ism_crc_clear(); +} + +bool swim1_device::ism_fifo_push(u16 data) +{ + if(m_ism_fifo_pos == 2) + return true; + m_ism_fifo[m_ism_fifo_pos ++] = data; + return false; +} + +u16 swim1_device::ism_fifo_pop() +{ + if(m_ism_fifo_pos == 0) + return 0xffff; + u16 r = m_ism_fifo[0]; + m_ism_fifo[0] = m_ism_fifo[1]; + m_ism_fifo_pos --; + return r; +} + +void swim1_device::iwm_mode_w(u8 data) +{ + m_iwm_mode = data; + m_iwm_status = (m_iwm_status & 0xe0) | (data & 0x1f); + logerror("mode %02x%s%s%s%s%s%s%s\n", m_iwm_mode, + m_iwm_mode & 0x80 ? " b7" : "", + m_iwm_mode & 0x40 ? " mz-reset" : "", + m_iwm_mode & 0x20 ? " test" : " normal", + m_iwm_mode & 0x10 ? " 8MHz" : " 7MHz", + m_iwm_mode & 0x08 ? " fast" : " slow", + m_iwm_mode & 0x04 ? "" : " timer", + m_iwm_mode & 0x02 ? " async" : " sync", + m_iwm_mode & 0x01 ? " latched" : ""); +} + +void swim1_device::iwm_data_w(u8 data) +{ + m_iwm_data = data; + if(iwm_is_sync() && m_iwm_rw == MODE_WRITE) + m_iwm_wsh = data; +} + +bool swim1_device::iwm_is_sync() const +{ + return m_iwm_mode & 0x02 ? false : true; +} + +u64 swim1_device::iwm_half_window_size() const +{ + switch(m_iwm_mode & 0x18) { + case 0x00: return 14; + case 0x08: return 7; + case 0x10: return 16; + case 0x18: return 8; + } + abort(); +} + +u64 swim1_device::iwm_window_size() const +{ + switch(m_iwm_mode & 0x18) { + case 0x00: return 28; + case 0x08: return 14; + case 0x10: return 36; + case 0x18: return 16; + } + abort(); +} + +u64 swim1_device::iwm_read_register_update_delay() const +{ + return m_iwm_mode & 0x08 ? 4 : 8; +} + +u64 swim1_device::iwm_write_sync_half_window_size() const +{ + return m_iwm_mode & 0x08 ? 2 : 4; +} + +void swim1_device::iwm_sync() +{ + if(!m_iwm_active) + return; + + u64 next_sync = machine().time().as_ticks(clock()); + switch(m_iwm_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_iwm_next_state_change) { + m_last_sync = next_sync; + break; + } + if(m_last_sync < m_iwm_next_state_change) + m_last_sync = m_iwm_next_state_change; + switch(m_iwm_rw_state) { + case S_IDLE: + m_iwm_rsh = 0x00; + m_iwm_rw_state = SR_WINDOW_EDGE_0; + m_iwm_next_state_change = m_last_sync + iwm_window_size(); + m_iwm_sync_update = 0; + m_iwm_async_update = 0; + break; + + case SR_WINDOW_EDGE_0: + case SR_WINDOW_EDGE_1: { + u64 endw = m_iwm_next_state_change + (m_iwm_rw_state == SR_WINDOW_EDGE_0 ? iwm_window_size() : iwm_half_window_size()); + if(m_iwm_rw_state == SR_WINDOW_EDGE_0 && endw >= next_flux_change && next_sync >= next_flux_change) { + m_last_sync = m_iwm_next_state_change = next_flux_change; + m_iwm_rw_state = SR_WINDOW_EDGE_1; + break; + } + if(next_sync < endw) { + m_last_sync = next_sync; + break; + } + m_iwm_rsh = (m_iwm_rsh << 1) | (m_iwm_rw_state == SR_WINDOW_EDGE_1 ? 1 : 0); + m_iwm_next_state_change = m_last_sync = endw; + m_iwm_rw_state = SR_WINDOW_EDGE_0; + if(iwm_is_sync()) { + if(m_iwm_rsh >= 0x80) { + m_iwm_data = m_iwm_rsh; + m_iwm_rsh = 0; + } else if(m_iwm_rsh >= 0x04) { + m_iwm_data = m_iwm_rsh; + m_iwm_sync_update = 0; + } else if(m_iwm_rsh >= 0x02) + m_iwm_sync_update = m_last_sync + iwm_read_register_update_delay(); + + } else if(m_iwm_rsh >= 0x80) { + m_iwm_data = m_iwm_rsh; + logerror("DATAR %02x\n", m_iwm_data); + m_iwm_rsh = 0; + } + break; + } + } + } + if(m_iwm_sync_update && m_iwm_sync_update <= m_last_sync) { + if(iwm_is_sync()) + m_iwm_data = m_iwm_rsh; + m_iwm_sync_update = 0; + } + if(m_iwm_async_update && m_iwm_async_update <= m_last_sync) { + if(!iwm_is_sync()) { + m_iwm_data = 0; + } + m_iwm_async_update = 0; + } + break; + } + + case MODE_WRITE: { + while(next_sync > m_last_sync) { + if(next_sync < m_iwm_next_state_change) { + m_last_sync = next_sync; + break; + } + if(m_last_sync < m_iwm_next_state_change) + m_last_sync = m_iwm_next_state_change; + switch(m_iwm_rw_state) { + case S_IDLE: + m_iwm_wsh = m_iwm_data; + m_iwm_rw_state = SW_WINDOW_MIDDLE; + m_iwm_next_state_change = iwm_q3_to_fclk(iwm_fclk_to_q3(m_last_sync) + iwm_write_sync_half_window_size()); + m_flux_write_count = 0; + break; + + case SW_WINDOW_MIDDLE: + if(m_iwm_wsh & 0x80) + m_flux_write[m_flux_write_count++] = m_last_sync; + m_iwm_wsh <<= 1; + m_iwm_next_state_change = iwm_q3_to_fclk(iwm_fclk_to_q3(m_last_sync) + iwm_write_sync_half_window_size()); + + m_iwm_rw_state = SW_WINDOW_END; + break; + case SW_WINDOW_END: + if(m_flux_write_count == m_flux_write.size()) + flush_write(); + m_iwm_next_state_change = iwm_q3_to_fclk(iwm_fclk_to_q3(m_last_sync) + iwm_write_sync_half_window_size()); + m_iwm_rw_state = SW_WINDOW_MIDDLE; + break; + } + } + break; + } +} +} + +void swim1_device::ism_sync() { } + +void swim1_device::sync() +{ + if(m_ism_mode & 0x40) + return ism_sync(); + else + return iwm_sync(); +} diff --git a/src/devices/machine/swim1.h b/src/devices/machine/swim1.h index 67f76098b2b..0420dfbbffa 100644 --- a/src/devices/machine/swim1.h +++ b/src/devices/machine/swim1.h @@ -22,6 +22,7 @@ class swim1_device : public applefdintf_device { public: // construction/destruction + swim1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, uint32_t q3_clock); swim1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); virtual u8 read(offs_t offset) override; @@ -38,11 +39,68 @@ protected: 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; + enum { + MODE_IDLE, + MODE_ACTIVE, MODE_DELAY, // m_iwm_active modes + MODE_READ, MODE_WRITE // m_iwm_rw modes + }; - void show_mode() const; + // 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; + + u64 m_flux_write_start; + std::array m_flux_write; + u32 m_flux_write_count; + u64 m_last_sync; + double m_iwm_q3_fclk_ratio, m_iwm_fclk_q3_ratio; + u32 m_q3_clock; + + u8 m_ism_param[16]; + u8 m_ism_mode, m_ism_setup, m_ism_error, m_ism_param_idx, m_ism_fifo_pos, m_ism_tss_sr, m_ism_tss_output, m_ism_current_bit; + u16 m_ism_fifo[2], m_ism_sr; + u16 m_ism_crc, m_ism_mfm_sync_counter; + u32 m_ism_half_cycles_before_change; + + u64 m_iwm_next_state_change, m_iwm_sync_update, m_iwm_async_update; + int m_iwm_active, m_iwm_rw, m_iwm_rw_state; + u8 m_iwm_data, m_iwm_whd, m_iwm_mode, m_iwm_status, m_iwm_control; + u8 m_iwm_rsh, m_iwm_wsh; + u8 m_iwm_to_ism_counter; + + u64 time_to_cycles(const attotime &tm) const; + attotime cycles_to_time(u64 cycles) const; + void flush_write(u64 when = 0); + + u64 iwm_fclk_to_q3(u64 cycles) const; + u64 iwm_q3_to_fclk(u64 cycles) const; + u64 iwm_window_size() const; + u64 iwm_half_window_size() const; + u64 iwm_read_register_update_delay() const; + u64 iwm_write_sync_half_window_size() const; + inline bool iwm_is_sync() const; + void iwm_mode_w(u8 data); + void iwm_data_w(u8 data); + u8 iwm_control(int offset, u8 data); + void iwm_sync(); + + void ism_fifo_clear(); + bool ism_fifo_push(u16 data); + u16 ism_fifo_pop(); + void ism_show_mode() const; + void ism_crc_update(int bit); + void ism_crc_clear(); + u8 ism_read(offs_t offset); + void ism_write(offs_t offset, u8 data); + void ism_sync(); }; DECLARE_DEVICE_TYPE(SWIM1, swim1_device) diff --git a/src/devices/machine/swim2.cpp b/src/devices/machine/swim2.cpp index e45a4edd624..582a97a58b2 100644 --- a/src/devices/machine/swim2.cpp +++ b/src/devices/machine/swim2.cpp @@ -128,7 +128,6 @@ u8 swim2_device::read(offs_t offset) sync(); static const char *const names[] = { - "?0", "?1", "?2", "?3", "?4", "?5", "?6", "?7", "data", "mark", "crc", "param", "phases", "setup", "status", "handshake" }; switch(offset & 7) { @@ -201,7 +200,7 @@ u8 swim2_device::read(offs_t offset) } default: - logerror("read %s\n", names[offset & 15]); + logerror("read %s\n", names[offset & 7]); break; } return 0xff; @@ -215,7 +214,6 @@ void swim2_device::write(offs_t offset, u8 data) static const char *const names[] = { "data", "mark", "crc", "param", "phases", "setup", "mode0", "mode1", - "?8", "?9", "?a", "?b", "?c", "?d", "?e", "?f" }; switch(offset & 7) { @@ -275,7 +273,7 @@ void swim2_device::write(offs_t offset, u8 data) break; default: - logerror("write %s, %02x\n", names[offset], data); + logerror("write %s, %02x\n", names[offset & 7], data); break; } @@ -325,11 +323,6 @@ void swim2_device::write(offs_t offset, u8 data) } } -u64 swim2_device::time_to_cycles(const attotime &tm) const -{ - return tm.as_ticks(clock()); -} - void swim2_device::crc_clear() { m_crc = 0xcdb4; @@ -344,6 +337,11 @@ void swim2_device::crc_update(int bit) } +u64 swim2_device::time_to_cycles(const attotime &tm) const +{ + return tm.as_ticks(clock()); +} + attotime swim2_device::cycles_to_time(u64 cycles) const { return attotime::from_ticks(cycles, clock()); @@ -373,21 +371,6 @@ u16 swim2_device::fifo_pop() return r; } -// cell times -// 1 us: 31.32 -// 1.5us: 47.32 -// 2us: 31.16 63.32 -// 3us: 47.16 94.32 -// 4us: 63.16 125.32 -// 6us: 94.16 188.32 - -// time1 = 31, time0 = 16 for clock /1 mfm -// time1 = - -// 32 mfm, t1=63, t0=31 -// 16 mfm, t1=31.5, t0=15.5 -// 16 gcr, t1=31.5, t0=31.5 - void swim2_device::sync() { u64 next_sync = time_to_cycles(machine().time()); @@ -411,8 +394,7 @@ void swim2_device::sync() cycles = 0; break; } - } - + } if(m_tss_output & 0xc) { bool bit; @@ -424,7 +406,7 @@ void swim2_device::sync() m_tss_output = 0; } if(bit) { - if(m_flux_write_count == 32) + if(m_flux_write_count == m_flux_write.size()) flush_write(next_sync - (cycles >> 1)); m_flux_write[m_flux_write_count ++] = next_sync - (cycles >> 1); m_half_cycles_before_change = 63; diff --git a/src/mame/drivers/mac.cpp b/src/mame/drivers/mac.cpp index 5e8d5f8586c..15d81790f85 100644 --- a/src/mame/drivers/mac.cpp +++ b/src/mame/drivers/mac.cpp @@ -738,23 +738,24 @@ void mac_state::add_base_devices(machine_config &config, bool rtc, int woz_versi #if NEW_SWIM switch (woz_version) { case 0: - IWM(config, m_fdc, C7M, 1021800*2); + IWM(config, m_fdc, C7M, 1021800*2, true); break; case 1: - SWIM1(config, m_fdc, C15M); + SWIM1(config, m_fdc, C15M, 1021800*2); break; case 2: SWIM2(config, m_fdc, C15M); + m_fdc->hdsel_cb().set(FUNC(mac_state::hdsel_w)); break; case 3: SWIM3(config, m_fdc, C15M); + m_fdc->hdsel_cb().set(FUNC(mac_state::hdsel_w)); break; } m_fdc->phases_cb().set(FUNC(mac_state::phases_w)); m_fdc->sel35_cb().set(FUNC(mac_state::sel35_w)); m_fdc->devsel_cb().set(FUNC(mac_state::devsel_w)); - m_fdc->hdsel_cb().set(FUNC(mac_state::hdsel_w)); applefdintf_device::add_35(config, m_floppy[0]); applefdintf_device::add_35_nc(config, m_floppy[1]); diff --git a/src/mame/machine/mac.cpp b/src/mame/machine/mac.cpp index b38d583b81e..04ba900a561 100644 --- a/src/mame/machine/mac.cpp +++ b/src/mame/machine/mac.cpp @@ -93,6 +93,8 @@ #include "emu.h" #include "includes/mac.h" #include "machine/sonydriv.h" +#include "machine/iwm.h" +#include "machine/swim1.h" #define AUDIO_IS_CLASSIC (m_model <= MODEL_MAC_CLASSIC) #define MAC_HAS_VIA2 ((m_model >= MODEL_MAC_II) && (m_model != MODEL_MAC_IIFX)) @@ -850,7 +852,12 @@ void mac_state::mac_via_out_a(uint8_t data) set_scc_waitrequest((data & 0x80) >> 7); m_screen_buffer = (data & 0x40) >> 6; +#if NEW_SWIM + if (m_cur_floppy && (m_fdc->type() == IWM || m_fdc->type() == SWIM1)) + m_cur_floppy->ss_w((data & 0x20) >> 5); +#else sony_set_sel_line(m_fdc.target(), (data & 0x20) >> 5); +#endif } void mac_state::mac_via_out_b(uint8_t data) @@ -2502,6 +2509,8 @@ void mac_state::devsel_w(uint8_t devsel) else m_cur_floppy = nullptr; m_fdc->set_floppy(m_cur_floppy); + if(m_cur_floppy && (m_fdc->type() == IWM || m_fdc->type() == SWIM1)) + m_cur_floppy->ss_w((m_via1->read_pa() & 0x20) >> 5); } void mac_state::hdsel_w(int hdsel)