summaryrefslogtreecommitdiffstatshomepage
path: root/src/mess/machine/victor9k_fdc.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mess/machine/victor9k_fdc.c')
-rw-r--r--src/mess/machine/victor9k_fdc.c528
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
+}