swim1: Embed the iwm

This commit is contained in:
Olivier Galibert 2021-01-18 22:50:26 +01:00
parent 2cb2bdc1a0
commit b3daa829c2
9 changed files with 673 additions and 130 deletions

View File

@ -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
-------------------------------------------------*/

View File

@ -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);

View File

@ -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;
}

View File

@ -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;

View File

@ -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<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 = 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();
}

View File

@ -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<u64, 32> 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)

View File

@ -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;

View File

@ -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]);

View File

@ -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)