diff options
Diffstat (limited to 'src/mess/machine/victor9k_fdc.c')
-rw-r--r-- | src/mess/machine/victor9k_fdc.c | 528 |
1 files changed, 487 insertions, 41 deletions
diff --git a/src/mess/machine/victor9k_fdc.c b/src/mess/machine/victor9k_fdc.c index 9f920357918..be26841fb37 100644 --- a/src/mess/machine/victor9k_fdc.c +++ b/src/mess/machine/victor9k_fdc.c @@ -13,7 +13,12 @@ TODO: - - everything + - floppy format + - spindle speed + - stepper + - read PLL + - TACH0/1 + - write logic */ @@ -147,7 +152,7 @@ static MACHINE_CONFIG_FRAGMENT( victor_9000_fdc ) MCFG_DEVICE_ADD(M6522_4_TAG, VIA6522, XTAL_30MHz/30) MCFG_VIA6522_WRITEPA_HANDLER(WRITE8(victor_9000_fdc_t, via4_pa_w)) MCFG_VIA6522_WRITEPB_HANDLER(WRITE8(victor_9000_fdc_t, via4_pb_w)) - MCFG_VIA6522_CA2_HANDLER(WRITELINE(victor_9000_fdc_t, mode_w)) + MCFG_VIA6522_CA2_HANDLER(WRITELINE(victor_9000_fdc_t, wrsync_w)) MCFG_VIA6522_IRQ_HANDLER(WRITELINE(victor_9000_fdc_t, via4_irq_w)) MCFG_DEVICE_ADD(M6522_5_TAG, VIA6522, XTAL_30MHz/30) @@ -192,6 +197,8 @@ machine_config_constructor victor_9000_fdc_t::device_mconfig_additions() const victor_9000_fdc_t::victor_9000_fdc_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : device_t(mconfig, VICTOR_9000_FDC, "Victor 9000 FDC", tag, owner, clock, "victor9k_fdc", __FILE__), m_irq_cb(*this), + m_syn_cb(*this), + m_lbrdy_cb(*this), m_maincpu(*this, I8048_TAG), m_via4(*this, M6522_4_TAG), m_via5(*this, M6522_5_TAG), @@ -210,20 +217,25 @@ victor_9000_fdc_t::victor_9000_fdc_t(const machine_config &mconfig, const char * m_rdy1(0), m_ds0(1), m_ds1(1), - m_lms(0), + m_l0ms(0), + m_l1ms(0), m_st0(0), m_st1(0), m_stp0(0), m_stp1(0), m_drive(0), m_side(0), - m_brdy(1), - m_sync(1), - m_gcrerr(0), m_via4_irq(CLEAR_LINE), m_via5_irq(CLEAR_LINE), - m_via6_irq(CLEAR_LINE) + m_via6_irq(CLEAR_LINE), + m_syn(0), + m_lbrdy(1) { + cur_live.tm = attotime::never; + cur_live.state = IDLE; + cur_live.next_state = -1; + cur_live.write_position = 0; + cur_live.write_start_time = attotime::never; } @@ -233,6 +245,11 @@ victor_9000_fdc_t::victor_9000_fdc_t(const machine_config &mconfig, const char * void victor_9000_fdc_t::device_start() { + // allocate timer + t_gen = timer_alloc(TM_GEN); + t_tach0 = timer_alloc(TM_TACH0); + t_tach1 = timer_alloc(TM_TACH1); + // state saving save_item(NAME(m_da)); save_item(NAME(m_da0)); @@ -245,19 +262,21 @@ void victor_9000_fdc_t::device_start() save_item(NAME(m_rdy1)); save_item(NAME(m_ds0)); save_item(NAME(m_ds1)); - save_item(NAME(m_lms)); + save_item(NAME(m_l0ms)); + save_item(NAME(m_l1ms)); save_item(NAME(m_st0)); save_item(NAME(m_st1)); save_item(NAME(m_stp0)); save_item(NAME(m_stp1)); save_item(NAME(m_drive)); save_item(NAME(m_side)); - save_item(NAME(m_brdy)); - save_item(NAME(m_sync)); - save_item(NAME(m_gcrerr)); + save_item(NAME(m_drw)); + save_item(NAME(m_erase)); save_item(NAME(m_via4_irq)); save_item(NAME(m_via5_irq)); save_item(NAME(m_via6_irq)); + save_item(NAME(m_syn)); + save_item(NAME(m_lbrdy)); } @@ -267,8 +286,12 @@ void victor_9000_fdc_t::device_start() void victor_9000_fdc_t::device_reset() { + live_abort(); + // resolve callbacks m_irq_cb.resolve_safe(); + m_syn_cb.resolve_safe(); + m_lbrdy_cb.resolve_safe(); // reset devices m_via4->reset(); @@ -291,6 +314,20 @@ void victor_9000_fdc_t::device_reset() void victor_9000_fdc_t::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) { + switch (id) + { + case TM_GEN: + live_sync(); + live_run(); + + case TM_TACH0: + // TODO + break; + + case TM_TACH1: + // TODO + break; + } } @@ -315,7 +352,7 @@ READ8_MEMBER( victor_9000_fdc_t::floppy_p1_r ) */ - return m_lms; + return (m_l1ms << 4) | m_l0ms; } @@ -370,30 +407,48 @@ WRITE8_MEMBER( victor_9000_fdc_t::floppy_p2_w ) */ - if (BIT(data, 0)) m_floppy0->mon_w(0); - if (BIT(data, 1)) m_floppy0->mon_w(1); - if (BIT(data, 2)) m_floppy1->mon_w(0); - if (BIT(data, 3)) m_floppy1->mon_w(1); + bool sync = false; - int sel0 = BIT(data, 5); + int mtr0 = m_mtr0; + if ((data & 0x03) == 0x01) mtr0 = 0; + if ((data & 0x03) == 0x02) mtr0 = 1; + if (m_mtr0 != mtr0) sync = true; - if (m_sel0 && !sel0) - { - m_da0 = m_da; - //m_floppy0->set_rpm(); - } + int mtr1 = m_mtr1; + if ((data & 0x0c) == 0x04) mtr1 = 0; + if ((data & 0x0c) == 0x08) mtr1 = 1; + if (m_mtr1 != mtr1) sync = true; - m_sel0 = sel0; + int sel0 = BIT(data, 5); + if (m_sel0 != sel0) sync = true; int sel1 = BIT(data, 4); + if (m_sel1 != sel1) sync = true; - if (m_sel1 && !sel1) + if (sync) { - m_da1 = m_da; - //m_floppy1->set_rpm(); - } + live_sync(); + + m_mtr0 = mtr0; + m_mtr1 = mtr1; + m_sel0 = sel0; + m_sel1 = sel1; + + if (LOG) logerror("%s MTR0 %u MTR1 %u SEL0 %u SEL1 %u\n", machine().time().as_string(), m_mtr0, m_mtr1, m_sel0, m_sel1); - m_sel1 = sel1; + update_spindle_motor(); + checkpoint(); + + if (!m_mtr0 || !m_mtr1) { + if(cur_live.state == IDLE) { + live_start(); + } + } else { + live_abort(); + } + + live_run(); + } } @@ -417,13 +472,39 @@ READ8_MEMBER( victor_9000_fdc_t::tach1_r ) } +void victor_9000_fdc_t::update_stepper_motor(floppy_image_device *floppy, int stp, int old_st, int st) +{ + // TODO +} + +void victor_9000_fdc_t::update_spindle_motor() +{ + if (m_sel0) m_da0 = m_da; + m_floppy0->mon_w(m_mtr0); + m_floppy0->set_rpm(300); // TODO + t_tach0->adjust(attotime::never); // TODO + + if (m_sel1) m_da1 = m_da; + m_floppy1->mon_w(m_mtr1); + m_floppy1->set_rpm(300); // TODO + t_tach1->adjust(attotime::never); // TODO +} + + //------------------------------------------------- // da_w - //------------------------------------------------- WRITE8_MEMBER( victor_9000_fdc_t::da_w ) { - m_da = data; + if (m_da != data) + { + live_sync(); + m_da = data; + update_spindle_motor(); + checkpoint(); + live_run(); + } } WRITE8_MEMBER( victor_9000_fdc_t::via4_pa_w ) @@ -443,8 +524,18 @@ WRITE8_MEMBER( victor_9000_fdc_t::via4_pa_w ) */ - m_lms = (m_lms & 0xf0) | (data & 0x0f); - m_st0 = data >> 4; + m_l0ms = data & 0x0f; + + UINT8 st0 = data >> 4; + + if (m_st0 != st0) + { + live_sync(); + update_stepper_motor(m_floppy0, m_stp0, st0, m_st0); + m_st0 = st0; + checkpoint(); + live_run(); + } } WRITE8_MEMBER( victor_9000_fdc_t::via4_pb_w ) @@ -464,12 +555,30 @@ WRITE8_MEMBER( victor_9000_fdc_t::via4_pb_w ) */ - m_lms = (data << 4) | (m_lms & 0x0f); - m_st1 = data >> 4; + m_l1ms = data & 0x0f; + + UINT8 st1 = data >> 4; + + if (m_st1 != st1) + { + live_sync(); + update_stepper_motor(m_floppy1, m_stp1, st1, m_st1); + m_st1 = st1; + checkpoint(); + live_run(); + } } -WRITE_LINE_MEMBER( victor_9000_fdc_t::mode_w ) +WRITE_LINE_MEMBER( victor_9000_fdc_t::wrsync_w ) { + if (m_wrsync != state) + { + live_sync(); + m_wrsync = state; + cur_live.wrsync = state; + checkpoint(); + live_run(); + } } WRITE_LINE_MEMBER( victor_9000_fdc_t::via4_irq_w ) @@ -479,7 +588,6 @@ WRITE_LINE_MEMBER( victor_9000_fdc_t::via4_irq_w ) m_irq_cb(m_via4_irq || m_via5_irq || m_via6_irq); } - READ8_MEMBER( victor_9000_fdc_t::via5_pa_r ) { /* @@ -497,7 +605,10 @@ READ8_MEMBER( victor_9000_fdc_t::via5_pa_r ) */ - return 0; + UINT8 e = checkpoint_live.e; + UINT8 i = checkpoint_live.i; + + return BIT(e, 6) << 7 | BIT(i, 7) << 6 | BIT(e, 5) << 5 | BIT(e, 4) << 4 | BIT(e, 2) << 3 | BIT(i, 1) << 2 | (e & 0x03); } WRITE8_MEMBER( victor_9000_fdc_t::via5_pb_w ) @@ -516,6 +627,15 @@ WRITE8_MEMBER( victor_9000_fdc_t::via5_pb_w ) PB7 WD7 */ + + if (m_wd != data) + { + live_sync(); + m_wd = data; + cur_live.wd = data; + checkpoint(); + live_run(); + } } WRITE_LINE_MEMBER( victor_9000_fdc_t::via5_irq_w ) @@ -555,7 +675,7 @@ READ8_MEMBER( victor_9000_fdc_t::via6_pa_r ) data |= (m_drive ? m_floppy1->wpt_r() : m_floppy0->wpt_r()) << 6; // disk sync detect - data |= m_sync << 7; + data |= checkpoint_live.sync << 7; return data; } @@ -583,11 +703,31 @@ WRITE8_MEMBER( victor_9000_fdc_t::via6_pa_w ) // LED, drive B output_set_led_value(LED_B, BIT(data, 2)); + bool sync = false; + // dual side select - m_side = BIT(data, 4); + int side = BIT(data, 4); + if (m_side != side) sync = true; // select drive A/B - m_drive = BIT(data, 5); + int drive = BIT(data, 5); + if (m_drive != drive) sync = true; + + if (sync) + { + live_sync(); + + m_side = side; + cur_live.side = side; + m_floppy0->ss_w(side); + m_floppy1->ss_w(side); + + m_drive = drive; + cur_live.drive = drive; + + checkpoint(); + live_run(); + } } READ8_MEMBER( victor_9000_fdc_t::via6_pb_r ) @@ -648,19 +788,58 @@ WRITE8_MEMBER( victor_9000_fdc_t::via6_pb_w ) if (!BIT(data, 2)) m_maincpu->reset(); + bool sync = false; + // stepper enable A - m_stp0 = BIT(data, 6); + int stp0 = BIT(data, 6); + if (m_stp0 != stp0) sync = true; // stepper enable B - m_stp1 = BIT(data, 7); + int stp1 = BIT(data, 7); + if (m_stp1 != stp1) sync = true; + + if (sync) + { + live_sync(); + + m_stp0 = stp0; + update_stepper_motor(m_floppy0, m_stp0, m_st0, m_st0); + + m_stp1 = stp1; + update_stepper_motor(m_floppy1, m_stp1, m_st1, m_st1); + + checkpoint(); + live_run(); + } } WRITE_LINE_MEMBER( victor_9000_fdc_t::drw_w ) { + if (m_drw != state) + { + live_sync(); + m_drw = cur_live.drw = state; + checkpoint(); + if (LOG) logerror("%s DRW %u\n", machine().time().as_string(), state); + if (state) { + stop_writing(machine().time()); + } else { + start_writing(machine().time()); + } + live_run(); + } } WRITE_LINE_MEMBER( victor_9000_fdc_t::erase_w ) { + if (m_erase != state) + { + live_sync(); + m_erase = cur_live.erase = state; + checkpoint(); + if (LOG) logerror("%s ERASE %u\n", machine().time().as_string(), state); + live_run(); + } } WRITE_LINE_MEMBER( victor_9000_fdc_t::via6_irq_w ) @@ -669,3 +848,270 @@ WRITE_LINE_MEMBER( victor_9000_fdc_t::via6_irq_w ) m_irq_cb(m_via4_irq || m_via5_irq || m_via6_irq); } + +READ8_MEMBER( victor_9000_fdc_t::cs7_r ) +{ + if (!checkpoint_live.lbrdy) + { + live_sync(); + cur_live.lbrdy = 1; + m_lbrdy_cb(1); + checkpoint(); + live_run(); + } + + return m_via5->read(space, offset); +} + +WRITE8_MEMBER( victor_9000_fdc_t::cs7_w ) +{ + if (!checkpoint_live.lbrdy) + { + live_sync(); + cur_live.lbrdy = 1; + m_lbrdy_cb(1); + checkpoint(); + live_run(); + } + + m_via5->write(space, offset, data); +} + +floppy_image_device* victor_9000_fdc_t::get_floppy() +{ + return m_drive ? m_floppy1 : m_floppy0; +} + +void victor_9000_fdc_t::live_start() +{ + cur_live.tm = machine().time(); + cur_live.state = RUNNING; + cur_live.next_state = -1; + + cur_live.shift_reg = 0; + cur_live.shift_reg_write = 0; + cur_live.bit_counter = 0; + + cur_live.drive = m_drive; + cur_live.side = m_side; + cur_live.drw = m_drw; + cur_live.wd = m_wd; + cur_live.wrsync = m_wrsync; + cur_live.erase = m_erase; + + checkpoint_live = cur_live; + + live_run(); +} + +void victor_9000_fdc_t::checkpoint() +{ + get_next_edge(machine().time()); + checkpoint_live = cur_live; +} + +void victor_9000_fdc_t::rollback() +{ + cur_live = checkpoint_live; + get_next_edge(cur_live.tm); +} + +void victor_9000_fdc_t::start_writing(const attotime &tm) +{ + cur_live.write_start_time = tm; + cur_live.write_position = 0; +} + +void victor_9000_fdc_t::stop_writing(const attotime &tm) +{ + commit(tm); + cur_live.write_start_time = attotime::never; +} + +bool victor_9000_fdc_t::write_next_bit(bool bit, const attotime &limit) +{ + if(cur_live.write_start_time.is_never()) { + cur_live.write_start_time = cur_live.tm; + cur_live.write_position = 0; + } + + attotime etime = cur_live.tm + m_period; + if(etime > limit) + return true; + + if(bit && cur_live.write_position < ARRAY_LENGTH(cur_live.write_buffer)) + cur_live.write_buffer[cur_live.write_position++] = cur_live.tm; + + if (LOG) logerror("%s write bit %u (%u)\n", cur_live.tm.as_string(), cur_live.bit_counter, bit); + + return false; +} + +void victor_9000_fdc_t::commit(const attotime &tm) +{ + if(cur_live.write_start_time.is_never() || tm == cur_live.write_start_time || !cur_live.write_position) + return; + + if (LOG) logerror("%s committing %u transitions since %s\n", tm.as_string(), cur_live.write_position, cur_live.write_start_time.as_string()); + + if(get_floppy()) + get_floppy()->write_flux(cur_live.write_start_time, tm, cur_live.write_position, cur_live.write_buffer); + + cur_live.write_start_time = tm; + cur_live.write_position = 0; +} + +void victor_9000_fdc_t::live_delay(int state) +{ + cur_live.next_state = state; + if(cur_live.tm != machine().time()) + t_gen->adjust(cur_live.tm - machine().time()); + else + live_sync(); +} + +void victor_9000_fdc_t::live_sync() +{ + if(!cur_live.tm.is_never()) { + if(cur_live.tm > machine().time()) { + rollback(); + live_run(machine().time()); + commit(cur_live.tm); + } else { + commit(cur_live.tm); + if(cur_live.next_state != -1) { + cur_live.state = cur_live.next_state; + cur_live.next_state = -1; + } + if(cur_live.state == IDLE) { + stop_writing(cur_live.tm); + cur_live.tm = attotime::never; + } + } + cur_live.next_state = -1; + checkpoint(); + } +} + +void victor_9000_fdc_t::live_abort() +{ + if(!cur_live.tm.is_never() && cur_live.tm > machine().time()) { + rollback(); + live_run(machine().time()); + } + + stop_writing(cur_live.tm); + + cur_live.tm = attotime::never; + cur_live.state = IDLE; + cur_live.next_state = -1; + cur_live.write_position = 0; + cur_live.write_start_time = attotime::never; + + cur_live.brdy = 1; + cur_live.lbrdy = 1; + cur_live.sync = 1; + cur_live.gcr_err = 1; +} + +void victor_9000_fdc_t::live_run(const attotime &limit) +{ + if(cur_live.state == IDLE || cur_live.next_state != -1) + return; + + for(;;) { + switch(cur_live.state) { + case RUNNING: { + bool syncpoint = false; + + if (cur_live.tm > limit) + return; + + // read bit + int bit = get_next_bit(cur_live.tm, limit); + if(bit < 0) + return; + + cur_live.shift_reg <<= 1; + cur_live.shift_reg |= bit; + cur_live.shift_reg &= 0x3ff; + + // sync + int sync = !(cur_live.shift_reg == 0x3ff); + + // bit counter + if (!sync) { + cur_live.bit_counter = 0; + } else if (cur_live.sync) { + cur_live.bit_counter++; + if (cur_live.bit_counter == 10) { + cur_live.bit_counter = 0; + } + } + + // GCR decoder + if (cur_live.drw) { + cur_live.i = cur_live.drw << 10 | cur_live.shift_reg; + } else { + cur_live.i = 0x300 | ((cur_live.wd & 0xf0) << 1) | cur_live.wrsync << 4 | (cur_live.wd & 0x0f); + } + + cur_live.e = m_gcr_rom->base()[cur_live.i]; + + // byte ready + int brdy = cur_live.bit_counter == 9; + + // GCR error + int gcr_err = !(brdy || BIT(cur_live.e, 3)); + + if (brdy != cur_live.brdy) { + if (LOG) logerror("%s BRDY %u\n", cur_live.tm.as_string(),brdy); + cur_live.brdy = brdy; + if (!brdy) cur_live.lbrdy = 0; + syncpoint = true; + } + + if (sync != cur_live.sync) { + if (LOG) logerror("%s SYNC %u\n", cur_live.tm.as_string(),sync); + cur_live.sync = sync; + syncpoint = true; + } + + if (gcr_err != cur_live.gcr_err) { + if (LOG) logerror("%s GCR ERR %u\n", cur_live.tm.as_string(),gcr_err); + cur_live.gcr_err = gcr_err; + syncpoint = true; + } + + if (syncpoint) { + commit(cur_live.tm); + + cur_live.tm += m_period; + live_delay(RUNNING_SYNCPOINT); + return; + } + + cur_live.tm += m_period; + break; + } + + case RUNNING_SYNCPOINT: { + m_lbrdy_cb(cur_live.lbrdy); + + cur_live.state = RUNNING; + checkpoint(); + break; + } + } + } +} + +void victor_9000_fdc_t::get_next_edge(const attotime &when) +{ + // TODO +} + +int victor_9000_fdc_t::get_next_bit(attotime &tm, const attotime &limit) +{ + return -1; // TODO +} |