From b3d0193b666a4f83259553ad80d4c09b8dce7777 Mon Sep 17 00:00:00 2001 From: Olivier Galibert Date: Tue, 27 Nov 2012 16:53:24 +0000 Subject: [PATCH] upd765, wd1772: Move to emu [O. Galibert] --- .gitattributes | 4 - src/emu/emu.mak | 2 + src/emu/machine/upd765.c | 2320 +++++++++++++++++++++++++++++++++++++ src/emu/machine/upd765.h | 441 +++++++ src/emu/machine/wd1772.c | 1907 ++++++++++++++++++++++++++++++ src/emu/machine/wd1772.h | 431 +++++++ src/mess/machine/pc_fdc.h | 2 +- src/mess/machine/upd765.c | 2320 ------------------------------------- src/mess/machine/upd765.h | 441 ------- src/mess/machine/wd1772.c | 1907 ------------------------------ src/mess/machine/wd1772.h | 431 ------- src/mess/mess.mak | 2 - 12 files changed, 5102 insertions(+), 5106 deletions(-) delete mode 100644 src/mess/machine/upd765.c delete mode 100644 src/mess/machine/upd765.h delete mode 100644 src/mess/machine/wd1772.c delete mode 100644 src/mess/machine/wd1772.h diff --git a/.gitattributes b/.gitattributes index 5d3dfefc44d..794e5e58720 100644 --- a/.gitattributes +++ b/.gitattributes @@ -7317,8 +7317,6 @@ src/mess/machine/upd7002.c svneol=native#text/plain src/mess/machine/upd7002.h svneol=native#text/plain src/mess/machine/upd71071.c svneol=native#text/plain src/mess/machine/upd71071.h svneol=native#text/plain -src/mess/machine/upd765.c svneol=native#text/plain -src/mess/machine/upd765.h svneol=native#text/plain src/mess/machine/ut88.c svneol=native#text/plain src/mess/machine/v1050kb.c svneol=native#text/plain src/mess/machine/v1050kb.h svneol=native#text/plain @@ -7412,8 +7410,6 @@ src/mess/machine/wangpckb.c svneol=native#text/plain src/mess/machine/wangpckb.h svneol=native#text/plain src/mess/machine/wd11c00_17.c svneol=native#text/plain src/mess/machine/wd11c00_17.h svneol=native#text/plain -src/mess/machine/wd1772.c svneol=native#text/plain -src/mess/machine/wd1772.h svneol=native#text/plain src/mess/machine/wd2010.c svneol=native#text/plain src/mess/machine/wd2010.h svneol=native#text/plain src/mess/machine/wswan.c svneol=native#text/plain diff --git a/src/emu/emu.mak b/src/emu/emu.mak index 349078dc6fc..2b83a1e7b16 100644 --- a/src/emu/emu.mak +++ b/src/emu/emu.mak @@ -269,7 +269,9 @@ EMUMACHINEOBJS = \ $(EMUMACHINE)/upd1990a.o \ $(EMUMACHINE)/upd4701.o \ $(EMUMACHINE)/upd7201.o \ + $(EMUMACHINE)/upd765.o \ $(EMUMACHINE)/v3021.o \ + $(EMUMACHINE)/wd1772.o \ $(EMUMACHINE)/wd17xx.o \ $(EMUMACHINE)/wd33c93.o \ $(EMUMACHINE)/x2212.o \ diff --git a/src/emu/machine/upd765.c b/src/emu/machine/upd765.c index e69de29bb2d..d994406a9d2 100644 --- a/src/emu/machine/upd765.c +++ b/src/emu/machine/upd765.c @@ -0,0 +1,2320 @@ +#include "debugger.h" + +#include "upd765.h" + +const device_type UPD765A = &device_creator; +const device_type UPD765B = &device_creator; +const device_type I8272A = &device_creator; +const device_type UPD72065 = &device_creator; +const device_type SMC37C78 = &device_creator; +const device_type N82077AA = &device_creator; +const device_type PC_FDC_SUPERIO = &device_creator; + +DEVICE_ADDRESS_MAP_START(map, 8, upd765a_device) + AM_RANGE(0x0, 0x0) AM_READ(msr_r) + AM_RANGE(0x1, 0x1) AM_READWRITE(fifo_r, fifo_w) +ADDRESS_MAP_END + +DEVICE_ADDRESS_MAP_START(map, 8, upd765b_device) + AM_RANGE(0x0, 0x0) AM_READ(msr_r) + AM_RANGE(0x1, 0x1) AM_READWRITE(fifo_r, fifo_w) +ADDRESS_MAP_END + +DEVICE_ADDRESS_MAP_START(map, 8, i8272a_device) + AM_RANGE(0x0, 0x0) AM_READ(msr_r) + AM_RANGE(0x1, 0x1) AM_READWRITE(fifo_r, fifo_w) +ADDRESS_MAP_END + +DEVICE_ADDRESS_MAP_START(map, 8, upd72065_device) + AM_RANGE(0x0, 0x0) AM_READ(msr_r) + AM_RANGE(0x1, 0x1) AM_READWRITE(fifo_r, fifo_w) +ADDRESS_MAP_END + +DEVICE_ADDRESS_MAP_START(map, 8, smc37c78_device) + AM_RANGE(0x2, 0x2) AM_READWRITE(dor_r, dor_w) + AM_RANGE(0x3, 0x3) AM_READWRITE(tdr_r, tdr_w) + AM_RANGE(0x4, 0x4) AM_READWRITE(msr_r, dsr_w) + AM_RANGE(0x5, 0x5) AM_READWRITE(fifo_r, fifo_w) + AM_RANGE(0x7, 0x7) AM_READWRITE(dir_r, ccr_w) +ADDRESS_MAP_END + +DEVICE_ADDRESS_MAP_START(map, 8, n82077aa_device) + AM_RANGE(0x0, 0x0) AM_READ(sra_r) + AM_RANGE(0x1, 0x1) AM_READ(srb_r) + AM_RANGE(0x2, 0x2) AM_READWRITE(dor_r, dor_w) + AM_RANGE(0x3, 0x3) AM_READWRITE(tdr_r, tdr_w) + AM_RANGE(0x4, 0x4) AM_READWRITE(msr_r, dsr_w) + AM_RANGE(0x5, 0x5) AM_READWRITE(fifo_r, fifo_w) + AM_RANGE(0x7, 0x7) AM_READWRITE(dir_r, ccr_w) +ADDRESS_MAP_END + +DEVICE_ADDRESS_MAP_START(map, 8, pc_fdc_superio_device) + AM_RANGE(0x0, 0x0) AM_READ(sra_r) + AM_RANGE(0x1, 0x1) AM_READ(srb_r) + AM_RANGE(0x2, 0x2) AM_READWRITE(dor_r, dor_w) + AM_RANGE(0x3, 0x3) AM_READWRITE(tdr_r, tdr_w) + AM_RANGE(0x4, 0x4) AM_READWRITE(msr_r, dsr_w) + AM_RANGE(0x5, 0x5) AM_READWRITE(fifo_r, fifo_w) + AM_RANGE(0x7, 0x7) AM_READWRITE(dir_r, ccr_w) +ADDRESS_MAP_END + + +int upd765_family_device::rates[4] = { 500000, 300000, 250000, 1000000 }; + +upd765_family_device::upd765_family_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock) : pc_fdc_interface(mconfig, type, name, tag, owner, clock) +{ + ready_polled = true; + ready_connected = true; + select_connected = true; + external_ready = true; + dor_reset = 0x00; +} + +void upd765_family_device::set_ready_line_connected(bool _ready) +{ + ready_connected = _ready; +} + +void upd765_family_device::set_select_lines_connected(bool _select) +{ + select_connected = _select; +} + +void upd765_family_device::set_mode(int _mode) +{ + // TODO +} + +void upd765_family_device::setup_intrq_cb(line_cb cb) +{ + intrq_cb = cb; +} + +void upd765_family_device::setup_drq_cb(line_cb cb) +{ + drq_cb = cb; +} + +void upd765_family_device::device_start() +{ + for(int i=0; i != 4; i++) { + char name[2]; + flopi[i].tm = timer_alloc(i); + flopi[i].id = i; + if(select_connected) { + name[0] = '0'+i; + name[1] = 0; + floppy_connector *con = subdevice(name); + if(con) { + flopi[i].dev = con->get_device(); + flopi[i].dev->setup_index_pulse_cb(floppy_image_device::index_pulse_cb(FUNC(upd765_family_device::index_callback), this)); + } else + flopi[i].dev = NULL; + } else + flopi[i].dev = NULL; + } + cur_rate = 250000; + tc = false; + + // reset at upper levels may cause a write to tc ending up with + // live_sync, which will crash if the live structure isn't + // initialized enough + + cur_live.tm = attotime::never; + cur_live.state = IDLE; + cur_live.next_state = -1; + cur_live.fi = NULL; + + if(ready_polled) { + poll_timer = timer_alloc(TIMER_DRIVE_READY_POLLING); + poll_timer->adjust(attotime::from_usec(1024), 0, attotime::from_usec(1024)); + } else + poll_timer = NULL; + + cur_irq = false; + locked = false; +} + +void upd765_family_device::device_reset() +{ + dor = dor_reset; + locked = false; + soft_reset(); +} + +void upd765_family_device::soft_reset() +{ + main_phase = PHASE_CMD; + for(int i=0; i<4; i++) { + flopi[i].main_state = IDLE; + flopi[i].sub_state = IDLE; + flopi[i].live = false; + flopi[i].ready = !ready_polled; + flopi[i].irq = floppy_info::IRQ_NONE; + } + data_irq = false; + polled_irq = false; + internal_drq = false; + fifo_pos = 0; + command_pos = 0; + result_pos = 0; + if(!locked) + fifocfg = FIF_DIS; + cur_live.fi = 0; + drq = false; + cur_live.tm = attotime::never; + cur_live.state = IDLE; + cur_live.next_state = -1; + cur_live.fi = NULL; + tc_done = false; + st0 = st1 = st2 = st3 = 0x00; + + check_irq(); + if(ready_polled) + poll_timer->adjust(attotime::from_usec(1024), 0, attotime::from_usec(1024)); +} + +void upd765_family_device::tc_w(bool _tc) +{ + logerror("%s: tc=%d\n", tag(), _tc); + if(tc != _tc && _tc) { + live_sync(); + tc_done = true; + tc = _tc; + if(cur_live.fi) + general_continue(*cur_live.fi); + } else + tc = _tc; +} + +void upd765_family_device::ready_w(bool _ready) +{ + external_ready = _ready; +} + +bool upd765_family_device::get_ready(int fid) +{ + if(ready_connected) + return flopi[fid].dev ? !flopi[fid].dev->ready_r() : false; + return external_ready; +} + +void upd765_family_device::set_floppy(floppy_image_device *flop) +{ + for(int fid=0; fid<4; fid++) { + if(flopi[fid].dev) + flopi[fid].dev->setup_index_pulse_cb(floppy_image_device::index_pulse_cb()); + flopi[fid].dev = flop; + } + if(flop) + flop->setup_index_pulse_cb(floppy_image_device::index_pulse_cb(FUNC(upd765_family_device::index_callback), this)); +} + +READ8_MEMBER(upd765_family_device::sra_r) +{ + UINT8 sra = 0; + int fid = dor & 3; + floppy_info &fi = flopi[fid]; + if(fi.dir) + sra |= 0x01; + if(fi.index) + sra |= 0x04; + if(cur_rate >= 500000) + sra |= 0x08; + if(fi.dev && fi.dev->trk00_r()) + sra |= 0x10; + if(fi.main_state == SEEK_WAIT_STEP_SIGNAL_TIME) + sra |= 0x20; + sra |= 0x40; + if(cur_irq) + sra |= 0x80; + if(mode == MODE_M30) + sra ^= 0x1f; + return sra; +} + +READ8_MEMBER(upd765_family_device::srb_r) +{ + return 0; +} + +READ8_MEMBER(upd765_family_device::dor_r) +{ + return dor; +} + +WRITE8_MEMBER(upd765_family_device::dor_w) +{ + logerror("%s: dor = %02x\n", tag(), data); + UINT8 diff = dor ^ data; + dor = data; + if(diff & 4) + soft_reset(); + + for(int i=0; i<4; i++) { + floppy_info &fi = flopi[i]; + if(fi.dev) + fi.dev->mon_w(!(dor & (0x10 << i))); + } + check_irq(); +} + +READ8_MEMBER(upd765_family_device::tdr_r) +{ + return 0; +} + +WRITE8_MEMBER(upd765_family_device::tdr_w) +{ +} + +READ8_MEMBER(upd765_family_device::msr_r) +{ + UINT32 msr = 0; + switch(main_phase) { + case PHASE_CMD: + msr |= MSR_RQM; + if(command_pos) + msr |= MSR_CB; + break; + case PHASE_EXEC: + msr |= MSR_CB; + if(spec & SPEC_ND) + msr |= MSR_EXM; + if(internal_drq) { + msr |= MSR_RQM; + if(!fifo_write) + msr |= MSR_DIO; + } + break; + + case PHASE_RESULT: + msr |= MSR_RQM|MSR_DIO|MSR_CB; + break; + } + for(int i=0; i<4; i++) + if(flopi[i].main_state == RECALIBRATE || flopi[i].main_state == SEEK) { + msr |= 1<dskchg_r() ? 0x00 : 0x80; + return 0x00; +} + +READ8_MEMBER(upd765_family_device::dir_r) +{ + return do_dir_r(); +} + +WRITE8_MEMBER(upd765_family_device::ccr_w) +{ + dsr = (dsr & 0xfc) | (data & 3); + cur_rate = rates[data & 3]; +} + +void upd765_family_device::set_drq(bool state) +{ + if(state != drq) { + drq = state; + if(!drq_cb.isnull()) + drq_cb(drq); + } +} + +bool upd765_family_device::get_drq() const +{ + return drq; +} + +void upd765_family_device::enable_transfer() +{ + if(spec & SPEC_ND) { + // PIO + if(!internal_drq) { + internal_drq = true; + check_irq(); + } + + } else { + // DMA + if(!drq) + set_drq(true); + } +} + +void upd765_family_device::disable_transfer() +{ + if(spec & SPEC_ND) { + internal_drq = false; + check_irq(); + } else + set_drq(false); +} + +void upd765_family_device::fifo_push(UINT8 data, bool internal) +{ + if(fifo_pos == 16) { + if(internal) { + if(!(st1 & ST1_OR)) + logerror("%s: Fifo overrun\n", tag()); + st1 |= ST1_OR; + } + return; + } + fifo[fifo_pos++] = data; + fifo_expected--; + + int thr = (fifocfg & FIF_THR)+1; + if(!fifo_write && (!fifo_expected || fifo_pos >= thr || (fifocfg & FIF_DIS))) + enable_transfer(); + if(fifo_write && (fifo_pos == 16 || !fifo_expected)) + disable_transfer(); +} + + +UINT8 upd765_family_device::fifo_pop(bool internal) +{ + if(!fifo_pos) { + if(internal) { + if(!(st1 & ST1_OR)) + logerror("%s: Fifo underrun\n", tag()); + st1 |= ST1_OR; + } + return 0; + } + UINT8 r = fifo[0]; + fifo_pos--; + memmove(fifo, fifo+1, fifo_pos); + if(!fifo_write && !fifo_pos) + disable_transfer(); + int thr = fifocfg & 15; + if(fifo_write && fifo_expected && (fifo_pos <= thr || (fifocfg & 0x20))) + enable_transfer(); + return r; +} + +void upd765_family_device::fifo_expect(int size, bool write) +{ + fifo_expected = size; + fifo_write = write; + if(fifo_write) + enable_transfer(); +} + +READ8_MEMBER(upd765_family_device::mdma_r) +{ + return dma_r(); +} + +WRITE8_MEMBER(upd765_family_device::mdma_w) +{ + dma_w(data); +} + +UINT8 upd765_family_device::dma_r() +{ + return fifo_pop(false); +} + +void upd765_family_device::dma_w(UINT8 data) +{ + fifo_push(data, false); +} + +void upd765_family_device::live_start(floppy_info &fi, int state) +{ + cur_live.tm = machine().time(); + cur_live.state = state; + cur_live.next_state = -1; + cur_live.fi = &fi; + cur_live.shift_reg = 0; + cur_live.crc = 0xffff; + cur_live.bit_counter = 0; + cur_live.data_separator_phase = false; + cur_live.data_reg = 0; + cur_live.previous_type = live_info::PT_NONE; + cur_live.data_bit_context = false; + cur_live.byte_counter = 0; + cur_live.pll.reset(cur_live.tm); + cur_live.pll.set_clock(attotime::from_hz(mfm ? 2*cur_rate : cur_rate)); + checkpoint_live = cur_live; + fi.live = true; + + live_run(); +} + +void upd765_family_device::checkpoint() +{ + if(cur_live.fi) + cur_live.pll.commit(cur_live.fi->dev, cur_live.tm); + checkpoint_live = cur_live; +} + +void upd765_family_device::rollback() +{ + cur_live = checkpoint_live; +} + +void upd765_family_device::live_delay(int state) +{ + cur_live.next_state = state; + if(cur_live.tm != machine().time()) + cur_live.fi->tm->adjust(cur_live.tm - machine().time()); + else + live_sync(); +} + +void upd765_family_device::live_sync() +{ + if(!cur_live.tm.is_never()) { + if(cur_live.tm > machine().time()) { + rollback(); + live_run(machine().time()); + cur_live.pll.commit(cur_live.fi->dev, cur_live.tm); + } else { + cur_live.pll.commit(cur_live.fi->dev, 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) { + cur_live.pll.stop_writing(cur_live.fi->dev, cur_live.tm); + cur_live.tm = attotime::never; + cur_live.fi->live = false; + cur_live.fi = 0; + } + } + cur_live.next_state = -1; + checkpoint(); + } +} + +void upd765_family_device::live_abort() +{ + if(!cur_live.tm.is_never() && cur_live.tm > machine().time()) { + rollback(); + live_run(machine().time()); + } + + if(cur_live.fi) { + cur_live.pll.stop_writing(cur_live.fi->dev, cur_live.tm); + cur_live.fi->live = false; + cur_live.fi = 0; + } + + cur_live.tm = attotime::never; + cur_live.state = IDLE; + cur_live.next_state = -1; +} + +void upd765_family_device::live_run(attotime limit) +{ + if(cur_live.state == IDLE || cur_live.next_state != -1) + return; + + if(limit == attotime::never) { + if(cur_live.fi->dev) + limit = cur_live.fi->dev->time_next_index(); + if(limit == attotime::never) { + // Happens when there's no disk or if the fdc is not + // connected to a drive, hence no index pulse. Force a + // sync from time to time in that case, so that the main + // cpu timeout isn't too painful. Avoids looping into + // infinity looking for data too. + + limit = machine().time() + attotime::from_msec(1); + cur_live.fi->tm->adjust(attotime::from_msec(1)); + } + } + + for(;;) { + + switch(cur_live.state) { + case SEARCH_ADDRESS_MARK_HEADER: + if(read_one_bit(limit)) + return; +#if 0 + fprintf(stderr, "%s: shift = %04x data=%02x c=%d\n", tts(cur_live.tm).cstr(), cur_live.shift_reg, + (cur_live.shift_reg & 0x4000 ? 0x80 : 0x00) | + (cur_live.shift_reg & 0x1000 ? 0x40 : 0x00) | + (cur_live.shift_reg & 0x0400 ? 0x20 : 0x00) | + (cur_live.shift_reg & 0x0100 ? 0x10 : 0x00) | + (cur_live.shift_reg & 0x0040 ? 0x08 : 0x00) | + (cur_live.shift_reg & 0x0010 ? 0x04 : 0x00) | + (cur_live.shift_reg & 0x0004 ? 0x02 : 0x00) | + (cur_live.shift_reg & 0x0001 ? 0x01 : 0x00), + cur_live.bit_counter); +#endif + + if(mfm && cur_live.shift_reg == 0x4489) { + cur_live.crc = 0x443b; + cur_live.data_separator_phase = false; + cur_live.bit_counter = 0; + cur_live.state = READ_HEADER_BLOCK_HEADER; + } + + if(!mfm && cur_live.shift_reg == 0xf57e) { + cur_live.crc = 0xef21; + cur_live.data_separator_phase = false; + cur_live.bit_counter = 0; + cur_live.state = READ_ID_BLOCK; + } + break; + + case READ_HEADER_BLOCK_HEADER: { + if(read_one_bit(limit)) + return; +#if 0 + fprintf(stderr, "%s: shift = %04x data=%02x counter=%d\n", tts(cur_live.tm).cstr(), cur_live.shift_reg, + (cur_live.shift_reg & 0x4000 ? 0x80 : 0x00) | + (cur_live.shift_reg & 0x1000 ? 0x40 : 0x00) | + (cur_live.shift_reg & 0x0400 ? 0x20 : 0x00) | + (cur_live.shift_reg & 0x0100 ? 0x10 : 0x00) | + (cur_live.shift_reg & 0x0040 ? 0x08 : 0x00) | + (cur_live.shift_reg & 0x0010 ? 0x04 : 0x00) | + (cur_live.shift_reg & 0x0004 ? 0x02 : 0x00) | + (cur_live.shift_reg & 0x0001 ? 0x01 : 0x00), + cur_live.bit_counter); +#endif + if(cur_live.bit_counter & 15) + break; + + int slot = cur_live.bit_counter >> 4; + + if(slot < 3) { + if(cur_live.shift_reg != 0x4489) + cur_live.state = SEARCH_ADDRESS_MARK_HEADER; + break; + } + if(cur_live.data_reg != 0xfe) { + cur_live.state = SEARCH_ADDRESS_MARK_HEADER; + break; + } + + cur_live.bit_counter = 0; + cur_live.state = READ_ID_BLOCK; + + break; + } + + case READ_ID_BLOCK: { + if(read_one_bit(limit)) + return; + if(cur_live.bit_counter & 15) + break; + int slot = (cur_live.bit_counter >> 4)-1; + + if(0) + fprintf(stderr, "%s: slot=%d data=%02x crc=%04x\n", tts(cur_live.tm).cstr(), slot, cur_live.data_reg, cur_live.crc); + cur_live.idbuf[slot] = cur_live.data_reg; + if(slot == 5) { + live_delay(IDLE); + return; + } + break; + } + + case SEARCH_ADDRESS_MARK_DATA: + if(read_one_bit(limit)) + return; +#if 0 + fprintf(stderr, "%s: shift = %04x data=%02x c=%d.%x\n", tts(cur_live.tm).cstr(), cur_live.shift_reg, + (cur_live.shift_reg & 0x4000 ? 0x80 : 0x00) | + (cur_live.shift_reg & 0x1000 ? 0x40 : 0x00) | + (cur_live.shift_reg & 0x0400 ? 0x20 : 0x00) | + (cur_live.shift_reg & 0x0100 ? 0x10 : 0x00) | + (cur_live.shift_reg & 0x0040 ? 0x08 : 0x00) | + (cur_live.shift_reg & 0x0010 ? 0x04 : 0x00) | + (cur_live.shift_reg & 0x0004 ? 0x02 : 0x00) | + (cur_live.shift_reg & 0x0001 ? 0x01 : 0x00), + cur_live.bit_counter >> 4, cur_live.bit_counter & 15); +#endif + + if(mfm) { + // Large tolerance due to perpendicular recording at extended density + if(cur_live.bit_counter > 62*16) { + live_delay(SEARCH_ADDRESS_MARK_DATA_FAILED); + return; + } + + if(cur_live.bit_counter >= 28*16 && cur_live.shift_reg == 0x4489) { + cur_live.crc = 0x443b; + cur_live.data_separator_phase = false; + cur_live.bit_counter = 0; + cur_live.state = READ_DATA_BLOCK_HEADER; + } + + } else { + if(cur_live.bit_counter > 23*16) { + live_delay(SEARCH_ADDRESS_MARK_DATA_FAILED); + return; + } + + if(cur_live.bit_counter >= 11*16 && (cur_live.shift_reg == 0xf56a || cur_live.shift_reg == 0xf56f)) { + cur_live.crc = cur_live.shift_reg == 0xf56a ? 0x8fe7 : 0xbf84; + cur_live.data_separator_phase = false; + cur_live.bit_counter = 0; + cur_live.state = READ_SECTOR_DATA; + } + } + + break; + + case READ_DATA_BLOCK_HEADER: { + if(read_one_bit(limit)) + return; +#if 0 + fprintf(stderr, "%s: shift = %04x data=%02x counter=%d\n", tts(cur_live.tm).cstr(), cur_live.shift_reg, + (cur_live.shift_reg & 0x4000 ? 0x80 : 0x00) | + (cur_live.shift_reg & 0x1000 ? 0x40 : 0x00) | + (cur_live.shift_reg & 0x0400 ? 0x20 : 0x00) | + (cur_live.shift_reg & 0x0100 ? 0x10 : 0x00) | + (cur_live.shift_reg & 0x0040 ? 0x08 : 0x00) | + (cur_live.shift_reg & 0x0010 ? 0x04 : 0x00) | + (cur_live.shift_reg & 0x0004 ? 0x02 : 0x00) | + (cur_live.shift_reg & 0x0001 ? 0x01 : 0x00), + cur_live.bit_counter); +#endif + if(cur_live.bit_counter & 15) + break; + + int slot = cur_live.bit_counter >> 4; + + if(slot < 3) { + if(cur_live.shift_reg != 0x4489) { + live_delay(SEARCH_ADDRESS_MARK_DATA_FAILED); + return; + } + break; + } + if(cur_live.data_reg != 0xfb && cur_live.data_reg != 0xf8) { + live_delay(SEARCH_ADDRESS_MARK_DATA_FAILED); + return; + } + + cur_live.bit_counter = 0; + cur_live.state = READ_SECTOR_DATA; + break; + } + + case SEARCH_ADDRESS_MARK_DATA_FAILED: + st1 |= ST1_MA; + st2 |= ST2_MD; + cur_live.state = IDLE; + return; + + case READ_SECTOR_DATA: { + if(read_one_bit(limit)) + return; + if(cur_live.bit_counter & 15) + break; + int slot = (cur_live.bit_counter >> 4)-1; + if(slot < sector_size) { + // Sector data + live_delay(READ_SECTOR_DATA_BYTE); + return; + + } else if(slot < sector_size+2) { + // CRC + if(slot == sector_size+1) { + live_delay(IDLE); + return; + } + } + break; + } + + case READ_SECTOR_DATA_BYTE: + if(!tc_done) + fifo_push(cur_live.data_reg, true); + cur_live.state = READ_SECTOR_DATA; + checkpoint(); + break; + + case WRITE_SECTOR_SKIP_GAP2: + cur_live.bit_counter = 0; + cur_live.byte_counter = 0; + cur_live.state = WRITE_SECTOR_SKIP_GAP2_BYTE; + checkpoint(); + break; + + case WRITE_SECTOR_SKIP_GAP2_BYTE: + if(read_one_bit(limit)) + return; + if(mfm && cur_live.bit_counter != 22*16) + break; + if(!mfm && cur_live.bit_counter != 11*16) + break; + cur_live.bit_counter = 0; + cur_live.byte_counter = 0; + live_delay(WRITE_SECTOR_DATA); + return; + + case WRITE_SECTOR_DATA: + if(mfm) { + if(cur_live.byte_counter < 12) + live_write_mfm(0x00); + else if(cur_live.byte_counter < 15) + live_write_raw(0x4489); + else if(cur_live.byte_counter < 16) { + cur_live.crc = 0xcdb4; + live_write_mfm(command[0] & 0x08 ? 0xf8 : 0xfb); + } else if(cur_live.byte_counter < 16+sector_size) + live_write_mfm(tc_done && !fifo_pos? 0x00 : fifo_pop(true)); + else if(cur_live.byte_counter < 16+sector_size+2) + live_write_mfm(cur_live.crc >> 8); + else if(cur_live.byte_counter < 16+sector_size+2+command[7]) + live_write_mfm(0x4e); + else { + cur_live.pll.stop_writing(cur_live.fi->dev, cur_live.tm); + cur_live.state = IDLE; + return; + } + + } else { + if(cur_live.byte_counter < 6) + live_write_fm(0x00); + else if(cur_live.byte_counter < 7) { + cur_live.crc = 0xffff; + live_write_raw(command[0] & 0x08 ? 0xf56a : 0xf56f); + } else if(cur_live.byte_counter < 7+sector_size) + live_write_fm(tc_done && !fifo_pos? 0x00 : fifo_pop(true)); + else if(cur_live.byte_counter < 7+sector_size+2) + live_write_fm(cur_live.crc >> 8); + else if(cur_live.byte_counter < 7+sector_size+2+command[7]) + live_write_fm(0xff); + else { + cur_live.pll.stop_writing(cur_live.fi->dev, cur_live.tm); + cur_live.state = IDLE; + return; + } + } + cur_live.state = WRITE_SECTOR_DATA_BYTE; + cur_live.bit_counter = 16; + checkpoint(); + break; + + case WRITE_TRACK_PRE_SECTORS: + if(!cur_live.byte_counter && command[3]) + fifo_expect(4, true); + if(mfm) { + if(cur_live.byte_counter < 80) + live_write_mfm(0x4e); + else if(cur_live.byte_counter < 92) + live_write_mfm(0x00); + else if(cur_live.byte_counter < 95) + live_write_raw(0x5224); + else if(cur_live.byte_counter < 96) + live_write_mfm(0xfc); + else if(cur_live.byte_counter < 146) + live_write_mfm(0x4e); + else { + cur_live.state = WRITE_TRACK_SECTOR; + cur_live.byte_counter = 0; + break; + } + } else { + if(cur_live.byte_counter < 40) + live_write_fm(0xff); + else if(cur_live.byte_counter < 46) + live_write_fm(0x00); + else if(cur_live.byte_counter < 47) + live_write_raw(0xf77a); + else if(cur_live.byte_counter < 73) + live_write_fm(0xff); + else { + cur_live.state = WRITE_TRACK_SECTOR; + cur_live.byte_counter = 0; + break; + } + } + cur_live.state = WRITE_TRACK_PRE_SECTORS_BYTE; + cur_live.bit_counter = 16; + checkpoint(); + break; + + case WRITE_TRACK_SECTOR: + if(!cur_live.byte_counter) { + command[3]--; + if(command[3]) + fifo_expect(4, true); + } + if(mfm) { + if(cur_live.byte_counter < 12) + live_write_mfm(0x00); + else if(cur_live.byte_counter < 15) + live_write_raw(0x4489); + else if(cur_live.byte_counter < 16) { + cur_live.crc = 0xcdb4; + live_write_mfm(0xfe); + } else if(cur_live.byte_counter < 20) + live_write_mfm(fifo_pop(true)); + else if(cur_live.byte_counter < 22) + live_write_mfm(cur_live.crc >> 8); + else if(cur_live.byte_counter < 44) + live_write_mfm(0x4e); + else if(cur_live.byte_counter < 56) + live_write_mfm(0x00); + else if(cur_live.byte_counter < 59) + live_write_raw(0x4489); + else if(cur_live.byte_counter < 60) { + cur_live.crc = 0xcdb4; + live_write_mfm(0xfb); + } else if(cur_live.byte_counter < 60+sector_size) + live_write_mfm(command[5]); + else if(cur_live.byte_counter < 62+sector_size) + live_write_mfm(cur_live.crc >> 8); + else if(cur_live.byte_counter < 62+sector_size+command[4]) + live_write_mfm(0x4e); + else { + cur_live.byte_counter = 0; + cur_live.state = command[3] ? WRITE_TRACK_SECTOR : WRITE_TRACK_POST_SECTORS; + break; + } + + } else { + if(cur_live.byte_counter < 6) + live_write_fm(0x00); + else if(cur_live.byte_counter < 7) { + cur_live.crc = 0xffff; + live_write_raw(0xf57e); + } else if(cur_live.byte_counter < 11) + live_write_fm(fifo_pop(true)); + else if(cur_live.byte_counter < 13) + live_write_fm(cur_live.crc >> 8); + else if(cur_live.byte_counter < 24) + live_write_fm(0xff); + else if(cur_live.byte_counter < 30) + live_write_fm(0x00); + else if(cur_live.byte_counter < 31) { + cur_live.crc = 0xffff; + live_write_raw(0xf56f); + } else if(cur_live.byte_counter < 31+sector_size) + live_write_fm(command[5]); + else if(cur_live.byte_counter < 33+sector_size) + live_write_fm(cur_live.crc >> 8); + else if(cur_live.byte_counter < 33+sector_size+command[4]) + live_write_fm(0xff); + else { + cur_live.byte_counter = 0; + cur_live.state = command[3] ? WRITE_TRACK_SECTOR : WRITE_TRACK_POST_SECTORS; + break; + } + } + cur_live.state = WRITE_TRACK_SECTOR_BYTE; + cur_live.bit_counter = 16; + checkpoint(); + break; + + case WRITE_TRACK_POST_SECTORS: + if(mfm) + live_write_mfm(0x4e); + else + live_write_fm(0xff); + cur_live.state = WRITE_TRACK_POST_SECTORS_BYTE; + cur_live.bit_counter = 16; + checkpoint(); + break; + + case WRITE_TRACK_PRE_SECTORS_BYTE: + case WRITE_TRACK_SECTOR_BYTE: + case WRITE_TRACK_POST_SECTORS_BYTE: + case WRITE_SECTOR_DATA_BYTE: + if(write_one_bit(limit)) + return; + if(cur_live.bit_counter == 0) { + cur_live.byte_counter++; + live_delay(cur_live.state-1); + return; + } + break; + + default: + logerror("%s: Unknown live state %d\n", tts(cur_live.tm).cstr(), cur_live.state); + return; + } + } +} + +int upd765_family_device::check_command() +{ + // 0.000010 read track + // 00000011 specify + // 00000100 sense drive status + // ..000101 write data + // ...00110 read data + // 00000111 recalibrate + // 00001000 sense interrupt status + // ..001001 write deleted data + // 0.001010 read id + // ...01100 read deleted data + // 0.001101 format track + // 00001110 dumpreg + // 00101110 save + // 01001110 restore + // 10001110 drive specification command + // 00001111 seek + // 1.001111 relative seek + // 00010000 version + // ...10001 scan equal + // 00010010 perpendicular mode + // 00010011 configure + // 00110011 option + // .0010100 lock + // ...10110 verify + // 00010111 powerdown mode + // 00011000 part id + // ...11001 scan low or equal + // ...11101 scan high or equal + + // MSDOS 6.22 format uses 0xcd to format a track, which makes one + // think only the bottom 5 bits are decoded. + + switch(command[0] & 0x1f) { + case 0x02: + return command_pos == 9 ? C_READ_TRACK : C_INCOMPLETE; + + case 0x03: + return command_pos == 3 ? C_SPECIFY : C_INCOMPLETE; + + case 0x04: + return command_pos == 2 ? C_SENSE_DRIVE_STATUS : C_INCOMPLETE; + + case 0x05: + case 0x09: + return command_pos == 9 ? C_WRITE_DATA : C_INCOMPLETE; + + case 0x06: + case 0x0c: + return command_pos == 9 ? C_READ_DATA : C_INCOMPLETE; + + case 0x07: + return command_pos == 2 ? C_RECALIBRATE : C_INCOMPLETE; + + case 0x08: + return C_SENSE_INTERRUPT_STATUS; + + case 0x0a: + return command_pos == 2 ? C_READ_ID : C_INCOMPLETE; + + case 0x0d: + return command_pos == 6 ? C_FORMAT_TRACK : C_INCOMPLETE; + + case 0x0e: + return C_DUMP_REG; + + case 0x0f: + return command_pos == 3 ? C_SEEK : C_INCOMPLETE; + + case 0x12: + return command_pos == 2 ? C_PERPENDICULAR : C_INCOMPLETE; + + case 0x13: + return command_pos == 4 ? C_CONFIGURE : C_INCOMPLETE; + + case 0x14: + return C_LOCK; + + default: + return C_INVALID; + } +} + +void upd765_family_device::start_command(int cmd) +{ + command_pos = 0; + result_pos = 0; + main_phase = PHASE_EXEC; + tc_done = false; + switch(cmd) { + case C_CONFIGURE: + logerror("%s: command configure %02x %02x %02x\n", + tag(), + command[1], command[2], command[3]); + // byte 1 is ignored, byte 3 is precompensation-related + fifocfg = command[2]; + precomp = command[3]; + main_phase = PHASE_CMD; + break; + + case C_DUMP_REG: + logerror("%s: command dump regs\n", tag()); + main_phase = PHASE_RESULT; + result[0] = flopi[0].pcn; + result[1] = flopi[1].pcn; + result[2] = flopi[2].pcn; + result[3] = flopi[3].pcn; + result[4] = (spec & 0xff00) >> 8; + result[5] = (spec & 0x00ff); + result[6] = sector_size; + result[7] = locked ? 0x80 : 0x00; + result[7] |= (perpmode & 0x30); + result[8] = fifocfg; + result[9] = precomp; + result_pos = 10; + break; + + case C_FORMAT_TRACK: + format_track_start(flopi[command[1] & 3]); + break; + + case C_LOCK: + locked = command[0] & 0x80; + main_phase = PHASE_RESULT; + result[0] = locked ? 0x10 : 0x00; + result_pos = 1; + logerror("%s: command lock (%s)\n", tag(), locked ? "on" : "off"); + break; + + case C_PERPENDICULAR: + logerror("%s: command perpendicular\n", tag()); + perpmode = command[1]; + main_phase = PHASE_CMD; + break; + + case C_READ_DATA: + read_data_start(flopi[command[1] & 3]); + break; + + case C_READ_ID: + read_id_start(flopi[command[1] & 3]); + break; + + case C_READ_TRACK: + read_track_start(flopi[command[1] & 3]); + break; + + case C_RECALIBRATE: + recalibrate_start(flopi[command[1] & 3]); + main_phase = PHASE_CMD; + break; + + case C_SEEK: + seek_start(flopi[command[1] & 3]); + main_phase = PHASE_CMD; + break; + + case C_SENSE_DRIVE_STATUS: { + floppy_info &fi = flopi[command[1] & 3]; + main_phase = PHASE_RESULT; + result[0] = 0x08; + if(fi.ready) + result[0] |= 0x20; + if(fi.dev) + result[0] |= + (fi.dev->wpt_r() ? 0x40 : 0x00) | + (fi.dev->trk00_r() ? 0x00 : 0x10) | + (fi.dev->ss_r() ? 0x04 : 0x00) | + (command[1] & 3); + logerror("%s: command sense drive status (%02x)\n", tag(), result[0]); + result_pos = 1; + break; + } + + case C_SENSE_INTERRUPT_STATUS: { + main_phase = PHASE_RESULT; + + int fid; + for(fid=0; fid<4 && flopi[fid].irq == floppy_info::IRQ_NONE; fid++); + if(fid == 4) { + st0 = ST0_UNK; + result[0] = st0; + result_pos = 1; + logerror("%s: command sense interrupt status (%02x)\n", tag(), result[0]); + break; + } + floppy_info &fi = flopi[fid]; + if(fi.irq == floppy_info::IRQ_POLLED) { + // Documentation is somewhat contradictory w.r.t polling + // and irq. PC bios, especially 5150, requires that only + // one irq happens. That's also wait the ns82077a doc + // says it does. OTOH, a number of docs says you need to + // call SIS 4 times, once per drive... + // + // There's also the interaction with the seek irq. The + // somewhat borderline tf20 code seems to think that + // essentially ignoring the polling irq should work. + // + // So at that point the best bet seems to drop the + // "polled" irq as soon as a SIS happens, and override any + // polled-in-waiting information when a seek irq happens + // for a given floppy. + + st0 = ST0_ABRT | fid; + } + fi.irq = floppy_info::IRQ_NONE; + + polled_irq = false; + + result[0] = st0; + result[1] = fi.pcn; + logerror("%s: command sense interrupt status (fid=%d %02x %02x)\n", tag(), fid, result[0], result[1]); + result_pos = 2; + + check_irq(); + break; + } + + case C_SPECIFY: + logerror("%s: command specify %02x %02x\n", + tag(), + command[1], command[2]); + spec = (command[1] << 8) | command[2]; + main_phase = PHASE_CMD; + break; + + case C_WRITE_DATA: + write_data_start(flopi[command[1] & 3]); + break; + + default: + fprintf(stderr, "start command %d\n", cmd); + exit(1); + } +} + +void upd765_family_device::command_end(floppy_info &fi, bool data_completion) +{ + logerror("%s: command done (%s) -", tag(), data_completion ? "data" : "seek"); + for(int i=0; i != result_pos; i++) + logerror(" %02x", result[i]); + logerror("\n"); + fi.main_state = fi.sub_state = IDLE; + if(data_completion) + data_irq = true; + else + fi.irq = floppy_info::IRQ_SEEK; + check_irq(); +} + +void upd765_family_device::recalibrate_start(floppy_info &fi) +{ + logerror("%s: command recalibrate\n", tag()); + fi.main_state = RECALIBRATE; + fi.sub_state = SEEK_WAIT_STEP_TIME_DONE; + fi.dir = 1; + fi.counter = 77; + seek_continue(fi); +} + +void upd765_family_device::seek_start(floppy_info &fi) +{ + logerror("%s: command %sseek %d\n", tag(), command[0] & 0x80 ? "relative " : "", command[2]); + fi.main_state = SEEK; + fi.sub_state = SEEK_WAIT_STEP_TIME_DONE; + fi.dir = fi.pcn > command[2] ? 1 : 0; + seek_continue(fi); +} + +void upd765_family_device::delay_cycles(emu_timer *tm, int cycles) +{ + tm->adjust(attotime::from_double(double(cycles)/cur_rate)); +} + +void upd765_family_device::seek_continue(floppy_info &fi) +{ + for(;;) { + switch(fi.sub_state) { + case SEEK_MOVE: + if(fi.dev) { + fi.dev->dir_w(fi.dir); + fi.dev->stp_w(0); + } + fi.sub_state = SEEK_WAIT_STEP_SIGNAL_TIME; + fi.tm->adjust(attotime::from_nsec(2500)); + return; + + case SEEK_WAIT_STEP_SIGNAL_TIME: + return; + + case SEEK_WAIT_STEP_SIGNAL_TIME_DONE: + if(fi.dev) + fi.dev->stp_w(1); + + if(fi.main_state == SEEK) { + if(fi.pcn > command[2]) + fi.pcn--; + else + fi.pcn++; + } + fi.sub_state = SEEK_WAIT_STEP_TIME; + delay_cycles(fi.tm, 500*(16-(spec >> 12))); + return; + + case SEEK_WAIT_STEP_TIME: + return; + + case SEEK_WAIT_STEP_TIME_DONE: { + bool done = false; + switch(fi.main_state) { + case RECALIBRATE: + fi.counter--; + done = !fi.dev || !fi.dev->trk00_r(); + if(done) + fi.pcn = 0; + else if(!fi.counter) { + st0 = ST0_FAIL|ST0_SE|ST0_EC; + command_end(fi, false); + return; + } + break; + case SEEK: + done = fi.pcn == command[2]; + break; + } + if(done) { + st0 = ST0_SE; + command_end(fi, false); + return; + } + fi.sub_state = SEEK_MOVE; + break; + } + } + } +} + +void upd765_family_device::read_data_start(floppy_info &fi) +{ + fi.main_state = READ_DATA; + fi.sub_state = HEAD_LOAD_DONE; + mfm = command[0] & 0x40; + + logerror("%s: command read%s data%s%s%s%s cmd=%02x sel=%x chrn=(%d, %d, %d, %d) eot=%02x gpl=%02x dtl=%02x rate=%d\n", + tag(), + command[0] & 0x08 ? " deleted" : "", + command[0] & 0x80 ? " mt" : "", + command[0] & 0x40 ? " mfm" : "", + command[0] & 0x20 ? " sk" : "", + fifocfg & 0x40 ? " seek" : "", + command[0], + command[1], + command[2], + command[3], + command[4], + 128 << (command[5] & 7), + command[6], + command[7], + command[8], + cur_rate); + + st0 = command[1] & 7; + st1 = ST1_MA; + st2 = 0x00; + + if(fi.dev) + fi.dev->ss_w(command[1] & 4 ? 1 : 0); + read_data_continue(fi); +} + +void upd765_family_device::read_data_continue(floppy_info &fi) +{ + for(;;) { + switch(fi.sub_state) { + case HEAD_LOAD_DONE: + if(fi.pcn == command[2] || !(fifocfg & 0x40)) { + fi.sub_state = SEEK_DONE; + break; + } + st0 |= ST0_SE; + if(fi.dev) { + fi.dev->dir_w(fi.pcn > command[2] ? 1 : 0); + fi.dev->stp_w(0); + } + fi.sub_state = SEEK_WAIT_STEP_SIGNAL_TIME; + fi.tm->adjust(attotime::from_nsec(2500)); + return; + + case SEEK_WAIT_STEP_SIGNAL_TIME: + return; + + case SEEK_WAIT_STEP_SIGNAL_TIME_DONE: + if(fi.dev) + fi.dev->stp_w(1); + + fi.sub_state = SEEK_WAIT_STEP_TIME; + delay_cycles(fi.tm, 500*(16-(spec >> 12))); + return; + + case SEEK_WAIT_STEP_TIME: + return; + + case SEEK_WAIT_STEP_TIME_DONE: + if(fi.pcn > command[2]) + fi.pcn--; + else + fi.pcn++; + fi.sub_state = HEAD_LOAD_DONE; + break; + + case SEEK_DONE: + fi.counter = 0; + fi.sub_state = SCAN_ID; + live_start(fi, SEARCH_ADDRESS_MARK_HEADER); + return; + + case SCAN_ID: + if(cur_live.crc) { + st0 |= ST0_FAIL; + st1 |= ST1_DE|ST1_ND; + fi.sub_state = COMMAND_DONE; + break; + } + st1 &= ~ST1_MA; + if(!sector_matches()) { + if(cur_live.idbuf[0] != command[2]) { + if(cur_live.idbuf[0] == 0xff) + st2 |= ST2_WC|ST2_BC; + else + st2 |= ST2_WC; + st0 |= ST0_FAIL; + fi.sub_state = COMMAND_DONE; + break; + } + live_start(fi, SEARCH_ADDRESS_MARK_HEADER); + return; + } + logerror("%s: reading sector %02x %02x %02x %02x\n", + tag(), + cur_live.idbuf[0], + cur_live.idbuf[1], + cur_live.idbuf[2], + cur_live.idbuf[3]); + sector_size = calc_sector_size(cur_live.idbuf[3]); + fifo_expect(sector_size, false); + fi.sub_state = SECTOR_READ; + live_start(fi, SEARCH_ADDRESS_MARK_DATA); + return; + + case SCAN_ID_FAILED: + st0 |= ST0_FAIL; + st1 |= ST1_ND; + fi.sub_state = COMMAND_DONE; + break; + + case SECTOR_READ: { + if(st2 & ST2_MD) { + st0 |= ST0_FAIL; + fi.sub_state = COMMAND_DONE; + break; + } + if(cur_live.crc) { + st0 |= ST0_FAIL; + st1 |= ST1_DE; + st2 |= ST2_CM; + fi.sub_state = COMMAND_DONE; + break; + } + bool done = tc_done; + command[4]++; + if(command[4] > command[6]) { + command[4] = 1; + if(command[0] & 0x80) { + command[3] = command[3] ^ 1; + if(fi.dev) + fi.dev->ss_w(command[3] & 1); + } + if(!(command[0] & 0x80) || !(command[3] & 1)) { + command[2]++; + if(!tc_done) { + st0 |= ST0_FAIL; + st1 |= ST1_EN; + } + done = true; + } + } + if(!done) { + fi.sub_state = SEEK_DONE; + break; + } + fi.sub_state = COMMAND_DONE; + break; + } + + case COMMAND_DONE: + main_phase = PHASE_RESULT; + result[0] = st0; + result[1] = st1; + result[2] = st2; + result[3] = command[2]; + result[4] = command[3]; + result[5] = command[4]; + result[6] = command[5]; + result_pos = 7; + command_end(fi, true); + return; + + default: + logerror("%s: read sector unknown sub-state %d\n", ttsn().cstr(), fi.sub_state); + return; + } + } +} + +void upd765_family_device::write_data_start(floppy_info &fi) +{ + fi.main_state = WRITE_DATA; + fi.sub_state = HEAD_LOAD_DONE; + mfm = command[0] & 0x40; + logerror("%s: command write%s data%s%s cmd=%02x sel=%x chrn=(%d, %d, %d, %d) eot=%02x gpl=%02x dtl=%02x rate=%d\n", + tag(), + command[0] & 0x08 ? " deleted" : "", + command[0] & 0x80 ? " mt" : "", + command[0] & 0x40 ? " mfm" : "", + command[0], + command[1], + command[2], + command[3], + command[4], + 128 << (command[5] & 7), + command[6], + command[7], + command[8], + cur_rate); + + if(fi.dev) + fi.dev->ss_w(command[1] & 4 ? 1 : 0); + + st0 = command[1] & 7; + st1 = ST1_MA; + st2 = 0x00; + + write_data_continue(fi); +} + +void upd765_family_device::write_data_continue(floppy_info &fi) +{ + for(;;) { + switch(fi.sub_state) { + case HEAD_LOAD_DONE: + fi.counter = 0; + fi.sub_state = SCAN_ID; + live_start(fi, SEARCH_ADDRESS_MARK_HEADER); + return; + + case SCAN_ID: + if(!sector_matches()) { + live_start(fi, SEARCH_ADDRESS_MARK_HEADER); + return; + } + if(cur_live.crc) { + st0 |= ST0_FAIL; + st1 |= ST1_DE|ST1_ND; + fi.sub_state = COMMAND_DONE; + break; + } + st1 &= ~ST1_MA; + sector_size = calc_sector_size(cur_live.idbuf[3]); + fifo_expect(sector_size, true); + fi.sub_state = SECTOR_WRITTEN; + live_start(fi, WRITE_SECTOR_SKIP_GAP2); + return; + + case SCAN_ID_FAILED: + st0 |= ST0_FAIL; + st1 |= ST1_ND; + fi.sub_state = COMMAND_DONE; + break; + + case SECTOR_WRITTEN: { + bool done = tc_done; + command[4]++; + if(command[4] > command[6]) { + command[4] = 1; + if(command[0] & 0x80) { + command[3] = command[3] ^ 1; + if(fi.dev) + fi.dev->ss_w(command[3] & 1); + } + if(!(command[0] & 0x80) || !(command[3] & 1)) { + command[2]++; + if(!tc_done) { + st0 |= ST0_FAIL; + st1 |= ST1_EN; + } + done = true; + } + } + if(!done) { + fi.sub_state = HEAD_LOAD_DONE; + break; + } + fi.sub_state = COMMAND_DONE; + break; + } + + case COMMAND_DONE: + main_phase = PHASE_RESULT; + result[0] = st0; + result[1] = st1; + result[2] = st2; + result[3] = command[2]; + result[4] = command[3]; + result[5] = command[4]; + result[6] = command[5]; + result_pos = 7; + command_end(fi, true); + return; + + default: + logerror("%s: write sector unknown sub-state %d\n", ttsn().cstr(), fi.sub_state); + return; + } + } +} + +void upd765_family_device::read_track_start(floppy_info &fi) +{ + fi.main_state = READ_TRACK; + fi.sub_state = HEAD_LOAD_DONE; + mfm = command[0] & 0x40; + + logerror("%s: command read track%s cmd=%02x sel=%x chrn=(%d, %d, %d, %d) eot=%02x gpl=%02x dtl=%02x rate=%d\n", + tag(), + command[0] & 0x40 ? " mfm" : "", + command[0], + command[1], + command[2], + command[3], + command[4], + 128 << (command[5] & 7), + command[6], + command[7], + command[8], + cur_rate); + + if(fi.dev) + fi.dev->ss_w(command[1] & 4 ? 1 : 0); + read_track_continue(fi); +} + +void upd765_family_device::read_track_continue(floppy_info &fi) +{ + for(;;) { + switch(fi.sub_state) { + case HEAD_LOAD_DONE: + if(fi.pcn == command[2] || !(fifocfg & 0x40)) { + fi.sub_state = SEEK_DONE; + break; + } + if(fi.dev) { + fi.dev->dir_w(fi.pcn > command[2] ? 1 : 0); + fi.dev->stp_w(0); + } + fi.sub_state = SEEK_WAIT_STEP_SIGNAL_TIME; + fi.tm->adjust(attotime::from_nsec(2500)); + return; + + case SEEK_WAIT_STEP_SIGNAL_TIME: + return; + + case SEEK_WAIT_STEP_SIGNAL_TIME_DONE: + if(fi.dev) + fi.dev->stp_w(1); + + fi.sub_state = SEEK_WAIT_STEP_TIME; + delay_cycles(fi.tm, 500*(16-(spec >> 12))); + return; + + case SEEK_WAIT_STEP_TIME: + return; + + case SEEK_WAIT_STEP_TIME_DONE: + if(fi.pcn > command[2]) + fi.pcn--; + else + fi.pcn++; + fi.sub_state = HEAD_LOAD_DONE; + break; + + case SEEK_DONE: + fi.counter = 0; + fi.sub_state = SCAN_ID; + live_start(fi, SEARCH_ADDRESS_MARK_HEADER); + return; + + case SCAN_ID: + if(cur_live.crc) { + fprintf(stderr, "Header CRC error\n"); + live_start(fi, SEARCH_ADDRESS_MARK_HEADER); + return; + } + sector_size = calc_sector_size(cur_live.idbuf[3]); + fifo_expect(sector_size, false); + fi.sub_state = SECTOR_READ; + live_start(fi, SEARCH_ADDRESS_MARK_DATA); + return; + + case SCAN_ID_FAILED: + fprintf(stderr, "RNF\n"); + // command_end(fi, true, 1); + return; + + case SECTOR_READ: + if(cur_live.crc) { + fprintf(stderr, "CRC error\n"); + } + if(command[4] < command[6]) { + command[4]++; + fi.sub_state = HEAD_LOAD_DONE; + break; + } + + main_phase = PHASE_RESULT; + result[0] = 0x40 | (fi.dev->ss_r() << 2) | fi.id; + result[1] = 0; + result[2] = 0; + result[3] = command[2]; + result[4] = command[3]; + result[5] = command[4]; + result[6] = command[5]; + result_pos = 7; + // command_end(fi, true, 0); + return; + + default: + logerror("%s: read track unknown sub-state %d\n", ttsn().cstr(), fi.sub_state); + return; + } + } +} + +int upd765_family_device::calc_sector_size(UINT8 size) +{ + return size > 7 ? 16384 : 128 << size; +} + +void upd765_family_device::format_track_start(floppy_info &fi) +{ + fi.main_state = FORMAT_TRACK; + fi.sub_state = HEAD_LOAD_DONE; + mfm = command[0] & 0x40; + + logerror("%s: command format track %s h=%02x n=%02x sc=%02x gpl=%02x d=%02x\n", + tag(), + command[0] & 0x40 ? "mfm" : "fm", + command[1], command[2], command[3], command[4], command[5]); + + if(fi.dev) + fi.dev->ss_w(command[1] & 4 ? 1 : 0); + sector_size = calc_sector_size(command[2]); + + format_track_continue(fi); +} + +void upd765_family_device::format_track_continue(floppy_info &fi) +{ + for(;;) { + switch(fi.sub_state) { + case HEAD_LOAD_DONE: + fi.sub_state = WAIT_INDEX; + break; + + case WAIT_INDEX: + return; + + case WAIT_INDEX_DONE: + logerror("%s: index found, writing track\n", tag()); + fi.sub_state = TRACK_DONE; + cur_live.pll.start_writing(machine().time()); + live_start(fi, WRITE_TRACK_PRE_SECTORS); + return; + + case TRACK_DONE: + main_phase = PHASE_RESULT; + result[0] = (fi.dev->ss_r() << 2) | fi.id; + result[1] = 0; + result[2] = 0; + result[3] = 0; + result[4] = 0; + result[5] = 0; + result[6] = 0; + result_pos = 7; + command_end(fi, true); + return; + + default: + logerror("%s: format track unknown sub-state %d\n", ttsn().cstr(), fi.sub_state); + return; + } + } +} + +void upd765_family_device::read_id_start(floppy_info &fi) +{ + fi.main_state = READ_ID; + fi.sub_state = HEAD_LOAD_DONE; + mfm = command[0] & 0x40; + + logerror("%s: command read id%s, rate=%d\n", + tag(), + command[0] & 0x40 ? " mfm" : "", + cur_rate); + + if(fi.dev) + fi.dev->ss_w(command[1] & 4 ? 1 : 0); + + st0 = command[1] & 7; + st1 = 0x00; + st2 = 0x00; + + for(int i=0; i<4; i++) + cur_live.idbuf[i] = 0x00; + + read_id_continue(fi); +} + +void upd765_family_device::read_id_continue(floppy_info &fi) +{ + for(;;) { + switch(fi.sub_state) { + case HEAD_LOAD_DONE: + fi.counter = 0; + fi.sub_state = SCAN_ID; + live_start(fi, SEARCH_ADDRESS_MARK_HEADER); + return; + + case SCAN_ID: + if(cur_live.crc) { + st0 |= ST0_FAIL; + st1 |= ST1_MA|ST1_DE|ST1_ND; + } + fi.sub_state = COMMAND_DONE; + break; + + case SCAN_ID_FAILED: + st0 |= ST0_FAIL; + st1 |= ST1_ND|ST1_MA; + fi.sub_state = COMMAND_DONE; + break; + + case COMMAND_DONE: + main_phase = PHASE_RESULT; + result[0] = st0; + result[1] = st1; + result[2] = st2; + result[3] = cur_live.idbuf[0]; + result[4] = cur_live.idbuf[1]; + result[5] = cur_live.idbuf[2]; + result[6] = cur_live.idbuf[3]; + result_pos = 7; + command_end(fi, true); + return; + + default: + logerror("%s: read id unknown sub-state %d\n", ttsn().cstr(), fi.sub_state); + return; + } + } +} + +void upd765_family_device::check_irq() +{ + bool old_irq = cur_irq; + cur_irq = data_irq || polled_irq || internal_drq; + for(int i=0; i<4; i++) + cur_irq = cur_irq || flopi[i].irq == floppy_info::IRQ_SEEK; + cur_irq = cur_irq && (dor & 4) && (dor & 8); + if(cur_irq != old_irq && !intrq_cb.isnull()) { + logerror("%s: irq = %d\n", tag(), cur_irq); + intrq_cb(cur_irq); + } +} + +bool upd765_family_device::get_irq() const +{ + return cur_irq; +} + +astring upd765_family_device::tts(attotime t) +{ + char buf[256]; + const char *sign = ""; + if(t.seconds < 0) { + t = attotime::zero-t; + sign = "-"; + } + int nsec = t.attoseconds / ATTOSECONDS_PER_NANOSECOND; + sprintf(buf, "%s%04d.%03d,%03d,%03d", sign, int(t.seconds), nsec/1000000, (nsec/1000)%1000, nsec % 1000); + return buf; +} + +astring upd765_family_device::ttsn() +{ + return tts(machine().time()); +} + +void upd765_family_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if(id == TIMER_DRIVE_READY_POLLING) { + run_drive_ready_polling(); + return; + } + + live_sync(); + + floppy_info &fi = flopi[id]; + switch(fi.sub_state) { + case SEEK_WAIT_STEP_SIGNAL_TIME: + fi.sub_state = SEEK_WAIT_STEP_SIGNAL_TIME_DONE; + break; + case SEEK_WAIT_STEP_TIME: + fi.sub_state = SEEK_WAIT_STEP_TIME_DONE; + break; + } + + general_continue(fi); +} + +void upd765_family_device::run_drive_ready_polling() +{ + if(main_phase != PHASE_CMD || (fifocfg & FIF_POLL)) + return; + + bool changed = false; + for(int fid=0; fid<4; fid++) { + bool ready = get_ready(fid); + if(ready != flopi[fid].ready) { + logerror("%s: polled %d : %d -> %d\n", tag(), fid, flopi[fid].ready, ready); + flopi[fid].ready = ready; + if(flopi[fid].irq == floppy_info::IRQ_NONE) { + flopi[fid].irq = floppy_info::IRQ_POLLED; + polled_irq = true; + changed = true; + } + } + } + if(changed) + check_irq(); +} + +void upd765_family_device::index_callback(floppy_image_device *floppy, int state) +{ + for(int fid=0; fid<4; fid++) { + floppy_info &fi = flopi[fid]; + if(fi.dev != floppy) + continue; + + if(fi.live) + live_sync(); + fi.index = state; + + if(!state) { + general_continue(fi); + continue; + } + + switch(fi.sub_state) { + case IDLE: + case SEEK_MOVE: + case SEEK_WAIT_STEP_SIGNAL_TIME: + case SEEK_WAIT_STEP_SIGNAL_TIME_DONE: + case SEEK_WAIT_STEP_TIME: + case SEEK_WAIT_STEP_TIME_DONE: + case HEAD_LOAD_DONE: + case SCAN_ID_FAILED: + case SECTOR_READ: + break; + + case WAIT_INDEX: + fi.sub_state = WAIT_INDEX_DONE; + break; + + case SCAN_ID: + fi.counter++; + if(fi.counter == 2) { + fi.sub_state = SCAN_ID_FAILED; + live_abort(); + } + break; + + case TRACK_DONE: + live_abort(); + break; + + default: + logerror("%s: Index pulse on unknown sub-state %d\n", ttsn().cstr(), fi.sub_state); + break; + } + + general_continue(fi); + } +} + + +void upd765_family_device::general_continue(floppy_info &fi) +{ + if(fi.live && cur_live.state != IDLE) { + live_run(); + if(cur_live.state != IDLE) + return; + } + + switch(fi.main_state) { + case IDLE: + break; + + case RECALIBRATE: + case SEEK: + seek_continue(fi); + break; + + case READ_DATA: + read_data_continue(fi); + break; + + case WRITE_DATA: + write_data_continue(fi); + break; + + case READ_TRACK: + read_track_continue(fi); + break; + + case FORMAT_TRACK: + format_track_continue(fi); + break; + + case READ_ID: + read_id_continue(fi); + break; + + default: + logerror("%s: general_continue on unknown main-state %d\n", ttsn().cstr(), fi.main_state); + break; + } +} + +bool upd765_family_device::read_one_bit(attotime limit) +{ + int bit = cur_live.pll.get_next_bit(cur_live.tm, cur_live.fi->dev, limit); + if(bit < 0) + return true; + cur_live.shift_reg = (cur_live.shift_reg << 1) | bit; + cur_live.bit_counter++; + if(cur_live.data_separator_phase) { + cur_live.data_reg = (cur_live.data_reg << 1) | bit; + if((cur_live.crc ^ (bit ? 0x8000 : 0x0000)) & 0x8000) + cur_live.crc = (cur_live.crc << 1) ^ 0x1021; + else + cur_live.crc = cur_live.crc << 1; + } + cur_live.data_separator_phase = !cur_live.data_separator_phase; + return false; +} + +bool upd765_family_device::write_one_bit(attotime limit) +{ + bool bit = cur_live.shift_reg & 0x8000; + if(cur_live.pll.write_next_bit(bit, cur_live.tm, cur_live.fi->dev, limit)) + return true; + if(cur_live.bit_counter & 1) { + if((cur_live.crc ^ (bit ? 0x8000 : 0x0000)) & 0x8000) + cur_live.crc = (cur_live.crc << 1) ^ 0x1021; + else + cur_live.crc = cur_live.crc << 1; + } + cur_live.shift_reg = cur_live.shift_reg << 1; + cur_live.bit_counter--; + return false; +} + +void upd765_family_device::live_write_raw(UINT16 raw) +{ + // logerror("write %04x %04x\n", raw, cur_live.crc); + cur_live.shift_reg = raw; + cur_live.data_bit_context = raw & 1; +} + +void upd765_family_device::live_write_mfm(UINT8 mfm) +{ + bool context = cur_live.data_bit_context; + UINT16 raw = 0; + for(int i=0; i<8; i++) { + bool bit = mfm & (0x80 >> i); + if(!(bit || context)) + raw |= 0x8000 >> (2*i); + if(bit) + raw |= 0x4000 >> (2*i); + context = bit; + } + cur_live.data_reg = mfm; + cur_live.shift_reg = raw; + cur_live.data_bit_context = context; + // logerror("write %02x %04x %04x\n", mfm, cur_live.crc, raw); +} + +void upd765_family_device::live_write_fm(UINT8 fm) +{ + UINT16 raw = 0xaaaa; + for(int i=0; i<8; i++) + if(fm & (0x80 >> i)) + raw |= 0x4000 >> (2*i); + cur_live.data_reg = fm; + cur_live.shift_reg = raw; + cur_live.data_bit_context = fm & 1; + // logerror("write %02x %04x %04x\n", fm, cur_live.crc, raw); +} + +bool upd765_family_device::sector_matches() const +{ + if(0) + logerror("%s: matching %02x %02x %02x %02x - %02x %02x %02x %02x\n", tag(), + cur_live.idbuf[0], cur_live.idbuf[1], cur_live.idbuf[2], cur_live.idbuf[3], + command[2], command[3], command[4], command[5]); + return + cur_live.idbuf[0] == command[2] && + cur_live.idbuf[1] == command[3] && + cur_live.idbuf[2] == command[4] && + cur_live.idbuf[3] == command[5]; +} + +void upd765_family_device::pll_t::set_clock(attotime _period) +{ + period = _period; + period_adjust_base = period * 0.05; + min_period = period * 0.75; + max_period = period * 1.25; +} + +void upd765_family_device::pll_t::reset(attotime when) +{ + ctime = when; + phase_adjust = attotime::zero; + freq_hist = 0; + write_position = 0; + write_start_time = attotime::never; +} + +void upd765_family_device::pll_t::start_writing(attotime tm) +{ + write_start_time = tm; + write_position = 0; +} + +void upd765_family_device::pll_t::stop_writing(floppy_image_device *floppy, attotime tm) +{ + commit(floppy, tm); + write_start_time = attotime::never; +} + +void upd765_family_device::pll_t::commit(floppy_image_device *floppy, attotime tm) +{ + if(write_start_time.is_never() || tm == write_start_time) + return; + + if(floppy) + floppy->write_flux(write_start_time, tm, write_position, write_buffer); + write_start_time = tm; + write_position = 0; +} + +int upd765_family_device::pll_t::get_next_bit(attotime &tm, floppy_image_device *floppy, attotime limit) +{ + attotime edge = floppy ? floppy->get_next_transition(ctime) : attotime::never; + + attotime next = ctime + period + phase_adjust; + +#if 0 + if(!edge.is_never()) + fprintf(stderr, "ctime=%s, transition_time=%s, next=%s, pha=%s\n", tts(ctime).cstr(), tts(edge).cstr(), tts(next).cstr(), tts(phase_adjust).cstr()); +#endif + + if(next > limit) + return -1; + + ctime = next; + tm = next; + + if(edge.is_never() || edge >= next) { + // No transition in the window means 0 and pll in free run mode + phase_adjust = attotime::zero; + return 0; + } + + // Transition in the window means 1, and the pll is adjusted + + attotime delta = edge - (next - period/2); + + if(delta.seconds < 0) + phase_adjust = attotime::zero - ((attotime::zero - delta)*65)/100; + else + phase_adjust = (delta*65)/100; + + if(delta < attotime::zero) { + if(freq_hist < 0) + freq_hist--; + else + freq_hist = -1; + } else if(delta > attotime::zero) { + if(freq_hist > 0) + freq_hist++; + else + freq_hist = 1; + } else + freq_hist = 0; + + if(freq_hist) { + int afh = freq_hist < 0 ? -freq_hist : freq_hist; + if(afh > 1) { + attotime aper = attotime::from_double(period_adjust_base.as_double()*delta.as_double()/period.as_double()); + period += aper; + + if(period < min_period) + period = min_period; + else if(period > max_period) + period = max_period; + } + } + + return 1; +} + +bool upd765_family_device::pll_t::write_next_bit(bool bit, attotime &tm, floppy_image_device *floppy, attotime limit) +{ + if(write_start_time.is_never()) { + write_start_time = ctime; + write_position = 0; + } + + attotime etime = ctime + period; + if(etime > limit) + return true; + + if(bit && write_position < ARRAY_LENGTH(write_buffer)) + write_buffer[write_position++] = ctime + period/2; + + tm = etime; + ctime = etime; + return false; +} + +upd765a_device::upd765a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : upd765_family_device(mconfig, UPD765A, "UPD765A", tag, owner, clock) +{ + m_shortname = "upd765a"; + dor_reset = 0x0c; +} + +upd765b_device::upd765b_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : upd765_family_device(mconfig, UPD765B, "UPD765B", tag, owner, clock) +{ + m_shortname = "upd765b"; + dor_reset = 0x0c; +} + +i8272a_device::i8272a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : upd765_family_device(mconfig, I8272A, "I8272A", tag, owner, clock) +{ + m_shortname = "i8272a"; + dor_reset = 0x0c; +} + +upd72065_device::upd72065_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : upd765_family_device(mconfig, UPD72065, "UPD72065", tag, owner, clock) +{ + m_shortname = "upd72065"; + dor_reset = 0x0c; +} + +smc37c78_device::smc37c78_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : upd765_family_device(mconfig, SMC37C78, "SMC37C78", tag, owner, clock) +{ + m_shortname = "smc37c78"; + ready_connected = false; + select_connected = true; +} + +n82077aa_device::n82077aa_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : upd765_family_device(mconfig, N82077AA, "N82077AA", tag, owner, clock) +{ + m_shortname = "n82077aa"; + ready_connected = false; + select_connected = true; +} + +pc_fdc_superio_device::pc_fdc_superio_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : upd765_family_device(mconfig, PC_FDC_SUPERIO, "PC FDC SUPERIO", tag, owner, clock) +{ + m_shortname = "pc_fdc_superio"; + ready_polled = false; + ready_connected = false; + select_connected = true; +} diff --git a/src/emu/machine/upd765.h b/src/emu/machine/upd765.h index e69de29bb2d..22f00f18394 100644 --- a/src/emu/machine/upd765.h +++ b/src/emu/machine/upd765.h @@ -0,0 +1,441 @@ +#ifndef __UPD765_F_H__ +#define __UPD765_F_H__ + +#include "emu.h" +#include "imagedev/floppy.h" + +/* + * ready = true if the ready line is physically connected to the floppy drive + * select = true if the fdc controls the floppy drive selection + * mode = MODE_AT, MODE_PS2 or MODE_M30 for the fdcs that have reset-time selection + */ + +#define MCFG_UPD765A_ADD(_tag, _ready, _select) \ + MCFG_DEVICE_ADD(_tag, UPD765A, 0) \ + downcast(device)->set_ready_line_connected(_ready); \ + downcast(device)->set_select_lines_connected(_select); + +#define MCFG_UPD765B_ADD(_tag, _ready, _select) \ + MCFG_DEVICE_ADD(_tag, UPD765B, 0) \ + downcast(device)->set_ready_line_connected(_ready); \ + downcast(device)->set_select_lines_connected(_select); + +#define MCFG_I8272A_ADD(_tag, _ready) \ + MCFG_DEVICE_ADD(_tag, I8272A, 0) \ + downcast(device)->set_ready_line_connected(_ready); + +#define MCFG_UPD72065_ADD(_tag, _ready, _select) \ + MCFG_DEVICE_ADD(_tag, UPD72065, 0) \ + downcast(device)->set_ready_line_connected(_ready); \ + downcast(device)->set_select_lines_connected(_select); + +#define MCFG_SMC37C78_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, SMC37C78, 0) + +#define MCFG_N82077AA_ADD(_tag, _mode) \ + MCFG_DEVICE_ADD(_tag, N82077AA, 0) \ + downcast(device)->set_mode(_mode); + +#define MCFG_PC_FDC_SUPERIO_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, PC_FDC_SUPERIO, 0) + +/* Interface required for PC ISA wrapping */ +class pc_fdc_interface : public device_t { +public: + typedef delegate line_cb; + typedef delegate byte_read_cb; + typedef delegate byte_write_cb; + + pc_fdc_interface(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock) : device_t(mconfig, type, name, tag, owner, clock) {} + + virtual void setup_intrq_cb(line_cb cb) = 0; + virtual void setup_drq_cb(line_cb cb) = 0; + + /* Note that the address map must cover and handle the whole 0-7 + * range. The upd765, while conforming to the rest of the + * interface, is not eligible as a result. + */ + + virtual DECLARE_ADDRESS_MAP(map, 8) = 0; + + virtual UINT8 dma_r() = 0; + virtual void dma_w(UINT8 data) = 0; + + virtual void tc_w(bool val) = 0; + virtual UINT8 do_dir_r() = 0; +}; + +class upd765_family_device : public pc_fdc_interface { +public: + enum { MODE_AT, MODE_PS2, MODE_M30 }; + + upd765_family_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock); + + void setup_intrq_cb(line_cb cb); + void setup_drq_cb(line_cb cb); + + virtual DECLARE_ADDRESS_MAP(map, 8) = 0; + + DECLARE_READ8_MEMBER (sra_r); + DECLARE_READ8_MEMBER (srb_r); + DECLARE_READ8_MEMBER (dor_r); + DECLARE_WRITE8_MEMBER(dor_w); + DECLARE_READ8_MEMBER (tdr_r); + DECLARE_WRITE8_MEMBER(tdr_w); + DECLARE_READ8_MEMBER (msr_r); + DECLARE_WRITE8_MEMBER(dsr_w); + DECLARE_READ8_MEMBER (fifo_r); + DECLARE_WRITE8_MEMBER(fifo_w); + DECLARE_READ8_MEMBER (dir_r); + DECLARE_WRITE8_MEMBER(ccr_w); + + virtual UINT8 do_dir_r(); + + UINT8 dma_r(); + void dma_w(UINT8 data); + + // Same as the previous ones, but as memory-mappable members + DECLARE_READ8_MEMBER(mdma_r); + DECLARE_WRITE8_MEMBER(mdma_w); + + bool get_irq() const; + bool get_drq() const; + void tc_w(bool val); + void ready_w(bool val); + + void set_rate(int rate); // rate in bps, to be used when the fdc is externally frequency-controlled + + void set_mode(int mode); + void set_ready_line_connected(bool ready); + void set_select_lines_connected(bool select); + void set_floppy(floppy_image_device *image); + +protected: + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + enum { + TIMER_DRIVE_READY_POLLING = 4 + }; + + enum { + PHASE_CMD, PHASE_EXEC, PHASE_RESULT + }; + + enum { + MSR_DB = 0x0f, + MSR_CB = 0x10, + MSR_EXM = 0x20, + MSR_DIO = 0x40, + MSR_RQM = 0x80, + + ST0_UNIT = 0x07, + ST0_NR = 0x08, + ST0_EC = 0x10, + ST0_SE = 0x20, + ST0_FAIL = 0x40, + ST0_UNK = 0x80, + ST0_ABRT = 0xc0, + + ST1_MA = 0x01, + ST1_NW = 0x02, + ST1_ND = 0x04, + ST1_OR = 0x10, + ST1_DE = 0x20, + ST1_EN = 0x80, + + ST2_MD = 0x01, + ST2_BC = 0x02, + ST2_SN = 0x04, + ST2_SH = 0x08, + ST2_WC = 0x10, + ST2_DD = 0x20, + ST2_CM = 0x40, + + ST3_UNIT = 0x07, + ST3_TS = 0x08, + ST3_T0 = 0x10, + ST3_RY = 0x20, + ST3_WP = 0x40, + ST3_FT = 0x80, + + FIF_THR = 0x0f, + FIF_POLL = 0x10, + FIF_DIS = 0x20, + FIF_EIS = 0x40, + + SPEC_ND = 0x0001, + }; + + + enum { + // General "doing nothing" state + IDLE, + + // Main states + RECALIBRATE, + SEEK, + READ_DATA, + WRITE_DATA, + READ_TRACK, + FORMAT_TRACK, + READ_ID, + + // Sub-states + COMMAND_DONE, + + SEEK_MOVE, + SEEK_WAIT_STEP_SIGNAL_TIME, + SEEK_WAIT_STEP_SIGNAL_TIME_DONE, + SEEK_WAIT_STEP_TIME, + SEEK_WAIT_STEP_TIME_DONE, + SEEK_DONE, + + HEAD_LOAD_DONE, + + WAIT_INDEX, + WAIT_INDEX_DONE, + + SCAN_ID, + SCAN_ID_FAILED, + + SECTOR_READ, + SECTOR_WRITTEN, + TC_DONE, + + TRACK_DONE, + + // Live states + SEARCH_ADDRESS_MARK_HEADER, + READ_HEADER_BLOCK_HEADER, + READ_DATA_BLOCK_HEADER, + READ_ID_BLOCK, + SEARCH_ADDRESS_MARK_DATA, + SEARCH_ADDRESS_MARK_DATA_FAILED, + READ_SECTOR_DATA, + READ_SECTOR_DATA_BYTE, + + WRITE_SECTOR_SKIP_GAP2, + WRITE_SECTOR_SKIP_GAP2_BYTE, + WRITE_SECTOR_DATA, + WRITE_SECTOR_DATA_BYTE, + + WRITE_TRACK_PRE_SECTORS, + WRITE_TRACK_PRE_SECTORS_BYTE, + + WRITE_TRACK_SECTOR, + WRITE_TRACK_SECTOR_BYTE, + + WRITE_TRACK_POST_SECTORS, + WRITE_TRACK_POST_SECTORS_BYTE, + }; + + struct pll_t { + attotime ctime, period, min_period, max_period, period_adjust_base, phase_adjust; + + attotime write_start_time; + attotime write_buffer[32]; + int write_position; + int freq_hist; + + void set_clock(attotime period); + void reset(attotime when); + int get_next_bit(attotime &tm, floppy_image_device *floppy, attotime limit); + bool write_next_bit(bool bit, attotime &tm, floppy_image_device *floppy, attotime limit); + void start_writing(attotime tm); + void commit(floppy_image_device *floppy, attotime tm); + void stop_writing(floppy_image_device *floppy, attotime tm); + }; + + struct floppy_info { + enum { IRQ_NONE, IRQ_SEEK, IRQ_POLLED }; + emu_timer *tm; + floppy_image_device *dev; + int id; + int main_state, sub_state; + int dir, counter; + UINT8 pcn; + int irq; + bool live, index, ready; + }; + + struct live_info { + enum { PT_NONE, PT_CRC_1, PT_CRC_2 }; + + attotime tm; + int state, next_state; + floppy_info *fi; + UINT16 shift_reg; + UINT16 crc; + int bit_counter, byte_counter, previous_type; + bool data_separator_phase, data_bit_context; + UINT8 data_reg; + UINT8 idbuf[6]; + pll_t pll; + }; + + static int rates[4]; + + bool ready_connected, ready_polled, select_connected; + + bool external_ready; + + int mode; + int main_phase; + + live_info cur_live, checkpoint_live; + line_cb intrq_cb, drq_cb; + bool cur_irq, polled_irq, data_irq, drq, internal_drq, tc, tc_done, locked, mfm; + floppy_info flopi[4]; + + int fifo_pos, fifo_expected, command_pos, result_pos; + bool fifo_write; + UINT8 dor, dsr, msr, fifo[16], command[16], result[16]; + UINT8 st0, st1, st2, st3; + UINT8 fifocfg, dor_reset; + UINT8 precomp, perpmode; + UINT16 spec; + int sector_size; + int cur_rate; + + emu_timer *poll_timer; + + static astring tts(attotime t); + astring ttsn(); + + enum { + C_CONFIGURE, + C_DUMP_REG, + C_FORMAT_TRACK, + C_LOCK, + C_PERPENDICULAR, + C_READ_DATA, + C_READ_ID, + C_READ_TRACK, + C_RECALIBRATE, + C_SEEK, + C_SENSE_DRIVE_STATUS, + C_SENSE_INTERRUPT_STATUS, + C_SPECIFY, + C_WRITE_DATA, + + C_INVALID, + C_INCOMPLETE, + }; + + void delay_cycles(emu_timer *tm, int cycles); + void check_irq(); + void soft_reset(); + void fifo_expect(int size, bool write); + void fifo_push(UINT8 data, bool internal); + UINT8 fifo_pop(bool internal); + void set_drq(bool state); + bool get_ready(int fid); + + void enable_transfer(); + void disable_transfer(); + int calc_sector_size(UINT8 size); + + void run_drive_ready_polling(); + + int check_command(); + void start_command(int cmd); + void command_end(floppy_info &fi, bool data_completion); + + void recalibrate_start(floppy_info &fi); + void seek_start(floppy_info &fi); + void seek_continue(floppy_info &fi); + + void read_data_start(floppy_info &fi); + void read_data_continue(floppy_info &fi); + + void write_data_start(floppy_info &fi); + void write_data_continue(floppy_info &fi); + + void read_track_start(floppy_info &fi); + void read_track_continue(floppy_info &fi); + + void format_track_start(floppy_info &fi); + void format_track_continue(floppy_info &fi); + + void read_id_start(floppy_info &fi); + void read_id_continue(floppy_info &fi); + + void general_continue(floppy_info &fi); + void index_callback(floppy_image_device *floppy, int state); + bool sector_matches() const; + + void live_start(floppy_info &fi, int live_state); + void live_abort(); + void checkpoint(); + void rollback(); + void live_delay(int state); + void live_sync(); + void live_run(attotime limit = attotime::never); + void live_write_raw(UINT16 raw); + void live_write_fm(UINT8 fm); + void live_write_mfm(UINT8 mfm); + + bool read_one_bit(attotime limit); + bool write_one_bit(attotime limit); +}; + +class upd765a_device : public upd765_family_device { +public: + upd765a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual DECLARE_ADDRESS_MAP(map, 8); +}; + +class upd765b_device : public upd765_family_device { +public: + upd765b_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual DECLARE_ADDRESS_MAP(map, 8); +}; + +class i8272a_device : public upd765_family_device { +public: + i8272a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual DECLARE_ADDRESS_MAP(map, 8); +}; + +class smc37c78_device : public upd765_family_device { +public: + smc37c78_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual DECLARE_ADDRESS_MAP(map, 8); +}; + +class upd72065_device : public upd765_family_device { +public: + upd72065_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual DECLARE_ADDRESS_MAP(map, 8); +}; + +class n82077aa_device : public upd765_family_device { +public: + n82077aa_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual DECLARE_ADDRESS_MAP(map, 8); +}; + +class pc_fdc_superio_device : public upd765_family_device { +public: + pc_fdc_superio_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual DECLARE_ADDRESS_MAP(map, 8); +}; + +extern const device_type UPD765A; +extern const device_type UPD765B; +extern const device_type I8272A; +extern const device_type UPD72065; +extern const device_type SMC37C78; +extern const device_type N82077AA; +extern const device_type PC_FDC_SUPERIO; + +#endif diff --git a/src/emu/machine/wd1772.c b/src/emu/machine/wd1772.c index e69de29bb2d..3b29bfcce38 100644 --- a/src/emu/machine/wd1772.c +++ b/src/emu/machine/wd1772.c @@ -0,0 +1,1907 @@ +/*************************************************************************** + + Copyright Olivier Galibert + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + * Neither the name 'MAME' nor the names of its contributors may be + used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + +****************************************************************************/ + +#include "wd1772.h" + +#include "debugger.h" + +const device_type FD1771x = &device_creator; +const device_type FD1793x = &device_creator; +const device_type FD1797x = &device_creator; +const device_type WD2793x = &device_creator; +const device_type WD2797x = &device_creator; +const device_type WD1770x = &device_creator; +const device_type WD1772x = &device_creator; +const device_type WD1773x = &device_creator; + +wd177x_t::wd177x_t(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, type, name, tag, owner, clock) +{ +} + +void wd177x_t::device_start() +{ + t_gen = timer_alloc(TM_GEN); + t_cmd = timer_alloc(TM_CMD); + t_track = timer_alloc(TM_TRACK); + t_sector = timer_alloc(TM_SECTOR); + dden = false; + floppy = 0; + + save_item(NAME(status)); + save_item(NAME(command)); + save_item(NAME(main_state)); + save_item(NAME(sub_state)); + save_item(NAME(track)); + save_item(NAME(sector)); + save_item(NAME(intrq_cond)); + save_item(NAME(cmd_buffer)); + save_item(NAME(track_buffer)); + save_item(NAME(sector_buffer)); + save_item(NAME(counter)); + save_item(NAME(status_type_1)); + save_item(NAME(last_dir)); +} + +void wd177x_t::device_reset() +{ + command = 0x00; + main_state = IDLE; + sub_state = IDLE; + cur_live.state = IDLE; + track = 0x00; + sector = 0x00; + status = 0x00; + data = 0x00; + cmd_buffer = track_buffer = sector_buffer = -1; + counter = 0; + status_type_1 = true; + last_dir = 1; + intrq = false; + drq = false; + hld = false; + live_abort(); +} + +void wd177x_t::set_floppy(floppy_image_device *_floppy) +{ + if(floppy == _floppy) + return; + + if(floppy) { + floppy->mon_w(1); + floppy->setup_index_pulse_cb(floppy_image_device::index_pulse_cb()); + } + + floppy = _floppy; + + if(floppy) { + if(has_motor()) + floppy->mon_w(status & S_MON ? 0 : 1); + floppy->setup_index_pulse_cb(floppy_image_device::index_pulse_cb(FUNC(wd177x_t::index_callback), this)); + } +} + +void wd177x_t::setup_intrq_cb(line_cb cb) +{ + intrq_cb = cb; +} + +void wd177x_t::setup_drq_cb(line_cb cb) +{ + drq_cb = cb; +} + +void wd177x_t::setup_hld_cb(line_cb cb) +{ + hld_cb = cb; +} + +void wd177x_t::setup_enp_cb(line_cb cb) +{ + enp_cb = cb; +} + +void wd177x_t::dden_w(bool _dden) +{ + dden = _dden; +} + +astring wd177x_t::tts(attotime t) +{ + char buf[256]; + int nsec = t.attoseconds / ATTOSECONDS_PER_NANOSECOND; + sprintf(buf, "%4d.%03d,%03d,%03d", int(t.seconds), nsec/1000000, (nsec/1000)%1000, nsec % 1000); + return buf; +} + +astring wd177x_t::ttsn() +{ + return tts(machine().time()); +} + +void wd177x_t::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + live_sync(); + + switch(id) { + case TM_GEN: do_generic(); break; + case TM_CMD: do_cmd_w(); break; + case TM_TRACK: do_track_w(); break; + case TM_SECTOR: do_sector_w(); break; + } + + general_continue(); +} + +void wd177x_t::command_end() +{ + main_state = sub_state = IDLE; + status &= ~S_BUSY; + intrq = true; + motor_timeout = 0; + if(!intrq_cb.isnull()) + intrq_cb(intrq); +} + +void wd177x_t::seek_start(int state) +{ + main_state = state; + status = (status & ~(S_CRC|S_RNF|S_SPIN)) | S_BUSY; + if(has_head_load()) { + // TODO get value from HLT callback + if (command & 8) + status |= S_HLD; + else + status &= ~S_HLD; + } + sub_state = has_motor() && !has_head_load() ? SPINUP : SPINUP_DONE; + status_type_1 = true; + seek_continue(); +} + +void wd177x_t::seek_continue() +{ + for(;;) { + switch(sub_state) { + case SPINUP: + if(!(status & S_MON)) { + spinup(); + return; + } + if(!(command & 0x08)) + status |= S_SPIN; + sub_state = SPINUP_DONE; + break; + + case SPINUP_WAIT: + return; + + case SPINUP_DONE: + if(main_state == RESTORE && floppy && !floppy->trk00_r()) + sub_state = SEEK_DONE; + + if(main_state == SEEK && track == data) + sub_state = SEEK_DONE; + + if(sub_state == SPINUP_DONE) { + counter = 0; + sub_state = SEEK_MOVE; + } + break; + + case SEEK_MOVE: + if(floppy) { + floppy->dir_w(last_dir); + floppy->stp_w(0); + floppy->stp_w(1); + } + // When stepping with update, the track register is updated before seeking. + // Important for the sam coupe format code. + if(main_state == STEP && (command & 0x10)) + track += last_dir ? -1 : 1; + counter++; + sub_state = SEEK_WAIT_STEP_TIME; + delay_cycles(t_gen, step_time(command & 3)); + return; + + case SEEK_WAIT_STEP_TIME: + return; + + case SEEK_WAIT_STEP_TIME_DONE: { + bool done = false; + switch(main_state) { + case RESTORE: + done = !floppy || !floppy->trk00_r(); + break; + case SEEK: + track += last_dir ? -1 : 1; + done = track == data; + break; + case STEP: + done = true; + break; + } + + if(done || counter == 255) { + if(main_state == RESTORE) + track = 0; + + if(command & 0x04) { + sub_state = SEEK_WAIT_STABILIZATION_TIME; + delay_cycles(t_gen, 120000); + return; + } else + sub_state = SEEK_DONE; + + } else + sub_state = SEEK_MOVE; + + break; + } + + case SEEK_WAIT_STABILIZATION_TIME: + return; + + case SEEK_WAIT_STABILIZATION_TIME_DONE: + sub_state = SEEK_DONE; + break; + + case SEEK_DONE: + if(command & 0x04) { + if(has_ready() && !is_ready()) { + status |= S_RNF; + command_end(); + return; + } + sub_state = SCAN_ID; + counter = 0; + live_start(SEARCH_ADDRESS_MARK_HEADER); + return; + } + command_end(); + return; + + case SCAN_ID: + if(cur_live.idbuf[0] != track) { + live_start(SEARCH_ADDRESS_MARK_HEADER); + return; + } + if(cur_live.crc) { + status |= S_CRC; + live_start(SEARCH_ADDRESS_MARK_HEADER); + return; + } + command_end(); + return; + + case SCAN_ID_FAILED: + status |= S_RNF; + command_end(); + return; + + default: + logerror("%s: seek unknown sub-state %d\n", ttsn().cstr(), sub_state); + return; + } + } +} + +bool wd177x_t::sector_matches() const +{ + if(cur_live.idbuf[0] != track || cur_live.idbuf[2] != sector) + return false; + if(!has_side_check() || (command & 2)) + return true; + if(command & 8) + return cur_live.idbuf[1] & 1; + else + return !(cur_live.idbuf[1] & 1); +} + +bool wd177x_t::is_ready() +{ + return (floppy && !floppy->ready_r()); +} + +void wd177x_t::read_sector_start() +{ + if(has_ready() && !is_ready()) + command_end(); + + main_state = READ_SECTOR; + status = (status & ~(S_CRC|S_LOST|S_RNF|S_WP|S_DDM)) | S_BUSY; + drop_drq(); + if (has_side_select() && floppy) + floppy->ss_w(BIT(command, 1)); + sub_state = has_motor() && !has_head_load() ? SPINUP : SPINUP_DONE; + status_type_1 = false; + read_sector_continue(); +} + +void wd177x_t::read_sector_continue() +{ + for(;;) { + switch(sub_state) { + case SPINUP: + if(!(status & S_MON)) { + spinup(); + return; + } + sub_state = SPINUP_DONE; + break; + + case SPINUP_WAIT: + return; + + case SPINUP_DONE: + if(command & 4) { + sub_state = SETTLE_WAIT; + delay_cycles(t_gen, settle_time()); + return; + } else { + sub_state = SETTLE_DONE; + break; + } + + case SETTLE_WAIT: + return; + + case SETTLE_DONE: + sub_state = SCAN_ID; + counter = 0; + live_start(SEARCH_ADDRESS_MARK_HEADER); + return; + + case SCAN_ID: + if(!sector_matches()) { + live_start(SEARCH_ADDRESS_MARK_HEADER); + return; + } + if(cur_live.crc) { + status |= S_CRC; + live_start(SEARCH_ADDRESS_MARK_HEADER); + return; + } + // TODO WD2795/7 alternate sector size + sector_size = 128 << (cur_live.idbuf[3] & 3); + sub_state = SECTOR_READ; + live_start(SEARCH_ADDRESS_MARK_DATA); + return; + + case SCAN_ID_FAILED: + status |= S_RNF; + command_end(); + return; + + case SECTOR_READ: + if(cur_live.crc) + status |= S_CRC; + + if(command & 0x10 && !(status & S_RNF)) { + sector++; + sub_state = SETTLE_DONE; + } else { + command_end(); + return; + } + break; + + default: + logerror("%s: read sector unknown sub-state %d\n", ttsn().cstr(), sub_state); + return; + } + } +} + +void wd177x_t::read_track_start() +{ + if(has_ready() && !is_ready()) + command_end(); + + main_state = READ_TRACK; + status = (status & ~(S_LOST|S_RNF)) | S_BUSY; + drop_drq(); + if (has_side_select() && floppy) + floppy->ss_w(BIT(command, 1)); + sub_state = has_motor() && !has_head_load() ? SPINUP : SPINUP_DONE; + status_type_1 = false; + read_track_continue(); +} + +void wd177x_t::read_track_continue() +{ + for(;;) { + switch(sub_state) { + case SPINUP: + if(!(status & S_MON)) { + spinup(); + return; + } + sub_state = SPINUP_DONE; + break; + + case SPINUP_WAIT: + return; + + case SPINUP_DONE: + if(command & 4) { + sub_state = SETTLE_WAIT; + delay_cycles(t_gen, settle_time()); + return; + + } else { + sub_state = SETTLE_DONE; + break; + } + + case SETTLE_WAIT: + return; + + case SETTLE_DONE: + sub_state = WAIT_INDEX; + return; + + case WAIT_INDEX: + return; + + case WAIT_INDEX_DONE: + sub_state = TRACK_DONE; + live_start(READ_TRACK_DATA); + return; + + case TRACK_DONE: + command_end(); + return; + + default: + logerror("%s: read track unknown sub-state %d\n", ttsn().cstr(), sub_state); + return; + } + } +} + +void wd177x_t::read_id_start() +{ + if(has_ready() && !is_ready()) + command_end(); + + main_state = READ_ID; + status = (status & ~(S_WP|S_DDM|S_LOST|S_RNF)) | S_BUSY; + drop_drq(); + if (has_side_select() && floppy) + floppy->ss_w(BIT(command, 1)); + sub_state = has_motor() && !has_head_load() ? SPINUP : SPINUP_DONE; + status_type_1 = false; + read_id_continue(); +} + +void wd177x_t::read_id_continue() +{ + for(;;) { + switch(sub_state) { + case SPINUP: + if(!(status & S_MON)) { + spinup(); + return; + } + sub_state = SPINUP_DONE; + break; + + case SPINUP_WAIT: + return; + + case SPINUP_DONE: + if(command & 4) { + sub_state = SETTLE_WAIT; + delay_cycles(t_gen, settle_time()); + return; + } else { + sub_state = SETTLE_DONE; + break; + } + + case SETTLE_WAIT: + return; + + case SETTLE_DONE: + sub_state = SCAN_ID; + counter = 0; + live_start(SEARCH_ADDRESS_MARK_HEADER); + return; + + case SCAN_ID: + command_end(); + return; + + case SCAN_ID_FAILED: + status |= S_RNF; + command_end(); + return; + + default: + logerror("%s: read id unknown sub-state %d\n", ttsn().cstr(), sub_state); + return; + } + } +} + +void wd177x_t::write_track_start() +{ + if(has_ready() && !is_ready()) + command_end(); + + main_state = WRITE_TRACK; + status = (status & ~(S_WP|S_DDM|S_LOST|S_RNF)) | S_BUSY; + drop_drq(); + if (has_side_select() && floppy) + floppy->ss_w(BIT(command, 1)); + sub_state = has_motor() && !has_head_load() ? SPINUP : SPINUP_DONE; + status_type_1 = false; + write_track_continue(); +} + +void wd177x_t::write_track_continue() +{ + for(;;) { + switch(sub_state) { + case SPINUP: + if(!(status & S_MON)) { + spinup(); + return; + } + sub_state = SPINUP_DONE; + break; + + case SPINUP_WAIT: + return; + + case SPINUP_DONE: + if(command & 4) { + sub_state = SETTLE_WAIT; + delay_cycles(t_gen, settle_time()); + return; + } else { + sub_state = SETTLE_DONE; + break; + } + + case SETTLE_WAIT: + return; + + case SETTLE_DONE: + set_drq(); + sub_state = DATA_LOAD_WAIT; + delay_cycles(t_gen, 768); + return; + + case DATA_LOAD_WAIT: + return; + + case DATA_LOAD_WAIT_DONE: + if(drq) { + status |= S_LOST; + command_end(); + return; + } + sub_state = WAIT_INDEX; + break; + + case WAIT_INDEX: + return; + + case WAIT_INDEX_DONE: + sub_state = TRACK_DONE; + live_start(WRITE_TRACK_DATA); + cur_live.pll.start_writing(machine().time()); + return; + + case TRACK_DONE: + command_end(); + return; + + default: + logerror("%s: write track unknown sub-state %d\n", ttsn().cstr(), sub_state); + return; + } + } +} + + +void wd177x_t::write_sector_start() +{ + if(has_ready() && !is_ready()) + command_end(); + + main_state = WRITE_SECTOR; + status = (status & ~(S_CRC|S_LOST|S_RNF|S_WP|S_DDM)) | S_BUSY; + drop_drq(); + if (has_side_select() && floppy) + floppy->ss_w(BIT(command, 1)); + sub_state = has_motor() && !has_head_load() ? SPINUP : SPINUP_DONE; + status_type_1 = false; + write_sector_continue(); +} + +void wd177x_t::write_sector_continue() +{ + for(;;) { + switch(sub_state) { + case SPINUP: + if(!(status & S_MON)) { + spinup(); + return; + } + sub_state = SPINUP_DONE; + break; + + case SPINUP_WAIT: + return; + + case SPINUP_DONE: + if(command & 4) { + sub_state = SETTLE_WAIT; + delay_cycles(t_gen, settle_time()); + return; + } else { + sub_state = SETTLE_DONE; + break; + } + + case SETTLE_WAIT: + return; + + case SETTLE_DONE: + sub_state = SCAN_ID; + counter = 0; + live_start(SEARCH_ADDRESS_MARK_HEADER); + return; + + case SCAN_ID: + if(!sector_matches()) { + live_start(SEARCH_ADDRESS_MARK_HEADER); + return; + } + if(cur_live.crc) { + status |= S_CRC; + live_start(SEARCH_ADDRESS_MARK_HEADER); + return; + } + // TODO WD2795/7 alternate sector size + sector_size = 128 << (cur_live.idbuf[3] & 3); + sub_state = SECTOR_WRITE; + live_start(WRITE_SECTOR_PRE); + return; + + case SCAN_ID_FAILED: + status |= S_RNF; + command_end(); + return; + + case SECTOR_WRITE: + if(command & 0x10) { + sector++; + sub_state = SPINUP_DONE; + } else { + command_end(); + return; + } + break; + + default: + logerror("%s: write sector unknown sub-state %d\n", ttsn().cstr(), sub_state); + return; + } + } +} + +void wd177x_t::interrupt_start() +{ + if(status & S_BUSY) { + main_state = sub_state = cur_live.state = IDLE; + cur_live.tm = attotime::never; + status &= ~S_BUSY; + drop_drq(); + motor_timeout = 0; + } + + if(!(command & 0x0f)) { + intrq_cond = 0; + } else { + intrq_cond = (intrq_cond & I_IMM) | (command & 0x07); + } + + if(intrq_cond & I_IMM) { + intrq = true; + if(!intrq_cb.isnull()) + intrq_cb(intrq); + } + + if(command & 0x03) { + logerror("%s: unhandled interrupt generation (%02x)\n", ttsn().cstr(), command); + } +} + +void wd177x_t::general_continue() +{ + if(cur_live.state != IDLE) { + live_run(); + if(cur_live.state != IDLE) + return; + } + + switch(main_state) { + case IDLE: + break; + case RESTORE: case SEEK: case STEP: + seek_continue(); + break; + case READ_SECTOR: + read_sector_continue(); + break; + case READ_TRACK: + read_track_continue(); + break; + case READ_ID: + read_id_continue(); + break; + case WRITE_TRACK: + write_track_continue(); + break; + case WRITE_SECTOR: + write_sector_continue(); + break; + default: + logerror("%s: general_continue on unknown main-state %d\n", ttsn().cstr(), main_state); + break; + } +} + +void wd177x_t::do_generic() +{ + switch(sub_state) { + case IDLE: + case SCAN_ID: + case SECTOR_READ: + break; + + case SETTLE_WAIT: + sub_state = SETTLE_DONE; + break; + + case SEEK_WAIT_STEP_TIME: + sub_state = SEEK_WAIT_STEP_TIME_DONE; + break; + + case SEEK_WAIT_STABILIZATION_TIME: + sub_state = SEEK_WAIT_STABILIZATION_TIME_DONE; + break; + + case DATA_LOAD_WAIT: + sub_state = DATA_LOAD_WAIT_DONE; + break; + + default: + if(cur_live.tm.is_never()) + logerror("%s: do_generic on unknown sub-state %d\n", ttsn().cstr(), sub_state); + break; + } +} + +void wd177x_t::do_cmd_w() +{ + // fprintf(stderr, "%s: command %02x\n", ttsn().cstr(), cmd_buffer); + + // Only available command when busy is interrupt + if(main_state != IDLE && (cmd_buffer & 0xf0) != 0xd0) { + cmd_buffer = -1; + return; + } + command = cmd_buffer; + cmd_buffer = -1; + + switch(command & 0xf0) { + case 0x00: logerror("wd1772: restore\n"); last_dir = 1; seek_start(RESTORE); break; + case 0x10: logerror("wd1772: seek %d\n", data); last_dir = data > track ? 0 : 1; seek_start(SEEK); break; + case 0x20: case 0x30: logerror("wd1772: step\n"); seek_start(STEP); break; + case 0x40: case 0x50: logerror("wd1772: step +\n"); last_dir = 0; seek_start(STEP); break; + case 0x60: case 0x70: logerror("wd1772: step -\n"); last_dir = 1; seek_start(STEP); break; + case 0x80: case 0x90: logerror("wd1772: read sector%s %d, %d\n", command & 0x10 ? " multiple" : "", track, sector); read_sector_start(); break; + case 0xa0: case 0xb0: logerror("wd1772: write sector%s %d, %d\n", command & 0x10 ? " multiple" : "", track, sector); write_sector_start(); break; + case 0xc0: logerror("wd1772: read id\n"); read_id_start(); break; + case 0xd0: logerror("wd1772: interrupt\n"); interrupt_start(); break; + case 0xe0: logerror("wd1772: read track %d\n", track); read_track_start(); break; + case 0xf0: logerror("wd1772: write track %d\n", track); write_track_start(); break; + } +} + +void wd177x_t::cmd_w(UINT8 val) +{ + logerror("wd1772 cmd: %02x\n", val); + + if(intrq && !(intrq_cond & I_IMM)) { + intrq = false; + if(!intrq_cb.isnull()) + intrq_cb(intrq); + } + + // No more than one write in flight + if(cmd_buffer != -1) + return; + + cmd_buffer = val; + + delay_cycles(t_cmd, dden ? 384 : 184); +} + +UINT8 wd177x_t::status_r() +{ + if(intrq && !(intrq_cond & I_IMM)) { + intrq = false; + if(!intrq_cb.isnull()) + intrq_cb(intrq); + } + + if(main_state == IDLE || status_type_1) { + if(floppy && floppy->idx_r()) + status |= S_IP; + else + status &= ~S_IP; + } else { + if(drq) + status |= S_DRQ; + else + status &= ~S_DRQ; + } + + if(status_type_1) { + status &= ~(S_TR00|S_WP); + if(floppy) { + if(floppy->wpt_r()) + status |= S_WP; + if(!floppy->trk00_r()) + status |= S_TR00; + } + } + + if(has_ready()) { + if(!is_ready()) + status |= S_NRDY; + else + status &= ~S_NRDY; + } + + return status; +} + +void wd177x_t::do_track_w() +{ + track = track_buffer; + track_buffer = -1; +} + +void wd177x_t::track_w(UINT8 val) +{ + // No more than one write in flight + if(track_buffer != -1) + return; + + track_buffer = val; + delay_cycles(t_track, dden ? 256 : 128); +} + +UINT8 wd177x_t::track_r() +{ + return track; +} + +void wd177x_t::do_sector_w() +{ + sector = sector_buffer; + sector_buffer = -1; +} + +void wd177x_t::sector_w(UINT8 val) +{ + // No more than one write in flight + if(sector_buffer != -1) + return; + + sector_buffer = val; + delay_cycles(t_sector, dden ? 256 : 128); +} + +UINT8 wd177x_t::sector_r() +{ + return sector; +} + +void wd177x_t::data_w(UINT8 val) +{ + data = val; + drop_drq(); +} + +UINT8 wd177x_t::data_r() +{ + drop_drq(); + return data; +} + +void wd177x_t::gen_w(int reg, UINT8 val) +{ + switch(reg) { + case 0: cmd_w(val); break; + case 1: track_w(val); break; + case 2: sector_w(val); break; + case 3: data_w(val); break; + } +} + +UINT8 wd177x_t::gen_r(int reg) +{ + switch(reg) { + case 0: return status_r(); break; + case 1: return track_r(); break; + case 2: return sector_r(); break; + case 3: return data_r(); break; + } + return 0xff; +} + +void wd177x_t::delay_cycles(emu_timer *tm, int cycles) +{ + tm->adjust(clocks_to_attotime(cycles)); +} + +void wd177x_t::spinup() +{ + if(command & 0x08) + sub_state = SPINUP_DONE; + else { + sub_state = SPINUP_WAIT; + counter = 0; + } + + status |= S_MON; + if(floppy) + floppy->mon_w(0); + +} + +void wd177x_t::index_callback(floppy_image_device *floppy, int state) +{ + live_sync(); + + if(!state) { + general_continue(); + return; + } + + if(intrq_cond & I_IDX) { + intrq = true; + if(!intrq_cb.isnull()) + intrq_cb(intrq); + } + + switch(sub_state) { + case IDLE: + if(has_motor()) { + motor_timeout ++; + if(motor_timeout >= 5) { + status &= ~S_MON; + if(floppy) + floppy->mon_w(1); + } + } + break; + + case SPINUP: + break; + + case SPINUP_WAIT: + counter++; + if(counter == 6) { + sub_state = SPINUP_DONE; + if(status_type_1) + status |= S_SPIN; + } + break; + + case SPINUP_DONE: + case SETTLE_WAIT: + case SETTLE_DONE: + case DATA_LOAD_WAIT: + case DATA_LOAD_WAIT_DONE: + case SEEK_MOVE: + case SEEK_WAIT_STEP_TIME: + case SEEK_WAIT_STEP_TIME_DONE: + case SEEK_WAIT_STABILIZATION_TIME: + case SEEK_WAIT_STABILIZATION_TIME_DONE: + case SEEK_DONE: + case WAIT_INDEX_DONE: + case SCAN_ID_FAILED: + case SECTOR_READ: + case SECTOR_WRITE: + break; + + case SCAN_ID: + counter++; + if(counter == 5) { + sub_state = SCAN_ID_FAILED; + live_abort(); + } + break; + + case WAIT_INDEX: + sub_state = WAIT_INDEX_DONE; + break; + + case TRACK_DONE: + live_abort(); + break; + + default: + logerror("%s: Index pulse on unknown sub-state %d\n", ttsn().cstr(), sub_state); + break; + } + + general_continue(); +} + +bool wd177x_t::intrq_r() +{ + return intrq; +} + +bool wd177x_t::drq_r() +{ + return drq; +} + +bool wd177x_t::hld_r() +{ + return hld; +} + +void wd177x_t::hlt_w(bool state) +{ + hlt = state; +} + +bool wd177x_t::enp_r() +{ + return enp; +} + +void wd177x_t::live_start(int state) +{ + cur_live.tm = machine().time(); + cur_live.state = state; + cur_live.next_state = -1; + cur_live.shift_reg = 0; + cur_live.crc = 0xffff; + cur_live.bit_counter = 0; + cur_live.data_separator_phase = false; + cur_live.data_reg = 0; + cur_live.previous_type = live_info::PT_NONE; + cur_live.data_bit_context = false; + cur_live.byte_counter = 0; + cur_live.pll.reset(cur_live.tm); + cur_live.pll.set_clock(clocks_to_attotime(1)); + checkpoint_live = cur_live; + + live_run(); +} + +void wd177x_t::checkpoint() +{ + cur_live.pll.commit(floppy, cur_live.tm); + checkpoint_live = cur_live; +} + +void wd177x_t::rollback() +{ + cur_live = checkpoint_live; +} + +void wd177x_t::live_delay(int state) +{ + cur_live.next_state = state; + t_gen->adjust(cur_live.tm - machine().time()); +} + +void wd177x_t::live_sync() +{ + if(!cur_live.tm.is_never()) { + if(cur_live.tm > machine().time()) { + // fprintf(stderr, "%s: Rolling back and replaying (%s)\n", ttsn().cstr(), tts(cur_live.tm).cstr()); + rollback(); + live_run(machine().time()); + cur_live.pll.commit(floppy, cur_live.tm); + } else { + // fprintf(stderr, "%s: Committing (%s)\n", ttsn().cstr(), tts(cur_live.tm).cstr()); + cur_live.pll.commit(floppy, 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) { + cur_live.pll.stop_writing(floppy, cur_live.tm); + cur_live.tm = attotime::never; + } + } + cur_live.next_state = -1; + checkpoint(); + } +} + +void wd177x_t::live_abort() +{ + if(!cur_live.tm.is_never() && cur_live.tm > machine().time()) { + rollback(); + live_run(machine().time()); + } + + cur_live.pll.stop_writing(floppy, cur_live.tm); + cur_live.tm = attotime::never; + cur_live.state = IDLE; + cur_live.next_state = -1; +} + +bool wd177x_t::read_one_bit(attotime limit) +{ + int bit = cur_live.pll.get_next_bit(cur_live.tm, floppy, limit); + if(bit < 0) + return true; + cur_live.shift_reg = (cur_live.shift_reg << 1) | bit; + cur_live.bit_counter++; + if(cur_live.data_separator_phase) { + cur_live.data_reg = (cur_live.data_reg << 1) | bit; + if((cur_live.crc ^ (bit ? 0x8000 : 0x0000)) & 0x8000) + cur_live.crc = (cur_live.crc << 1) ^ 0x1021; + else + cur_live.crc = cur_live.crc << 1; + } + cur_live.data_separator_phase = !cur_live.data_separator_phase; + return false; +} + +bool wd177x_t::write_one_bit(attotime limit) +{ + bool bit = cur_live.shift_reg & 0x8000; + if(cur_live.pll.write_next_bit(bit, cur_live.tm, floppy, limit)) + return true; + if(cur_live.bit_counter & 1) { + if((cur_live.crc ^ (bit ? 0x8000 : 0x0000)) & 0x8000) + cur_live.crc = (cur_live.crc << 1) ^ 0x1021; + else + cur_live.crc = cur_live.crc << 1; + } + cur_live.shift_reg = cur_live.shift_reg << 1; + cur_live.bit_counter--; + return false; +} + +void wd177x_t::live_write_raw(UINT16 raw) +{ + // logerror("write %04x %04x\n", raw, cur_live.crc); + cur_live.shift_reg = raw; + cur_live.data_bit_context = raw & 1; +} + +void wd177x_t::live_write_mfm(UINT8 mfm) +{ + bool context = cur_live.data_bit_context; + UINT16 raw = 0; + for(int i=0; i<8; i++) { + bool bit = mfm & (0x80 >> i); + if(!(bit || context)) + raw |= 0x8000 >> (2*i); + if(bit) + raw |= 0x4000 >> (2*i); + context = bit; + } + cur_live.shift_reg = raw; + cur_live.data_bit_context = context; + // logerror("write %02x %04x %04x\n", mfm, cur_live.crc, raw); +} + +void wd177x_t::live_run(attotime limit) +{ + if(cur_live.state == IDLE || cur_live.next_state != -1) + return; + + if(limit == attotime::never) { + if(floppy) + limit = floppy->time_next_index(); + if(limit == attotime::never) { + // Happens when there's no disk or if the wd is not + // connected to a drive, hence no index pulse. Force a + // sync from time to time in that case, so that the main + // cpu timeout isn't too painful. Avoids looping into + // infinity looking for data too. + + limit = machine().time() + attotime::from_msec(1); + t_gen->adjust(attotime::from_msec(1)); + } + } + + // fprintf(stderr, "%s: live_run(%s)\n", ttsn().cstr(), tts(limit).cstr()); + + for(;;) { + switch(cur_live.state) { + case SEARCH_ADDRESS_MARK_HEADER: + if(read_one_bit(limit)) + return; +#if 0 + fprintf(stderr, "%s: shift = %04x data=%02x c=%d\n", tts(cur_live.tm).cstr(), cur_live.shift_reg, + (cur_live.shift_reg & 0x4000 ? 0x80 : 0x00) | + (cur_live.shift_reg & 0x1000 ? 0x40 : 0x00) | + (cur_live.shift_reg & 0x0400 ? 0x20 : 0x00) | + (cur_live.shift_reg & 0x0100 ? 0x10 : 0x00) | + (cur_live.shift_reg & 0x0040 ? 0x08 : 0x00) | + (cur_live.shift_reg & 0x0010 ? 0x04 : 0x00) | + (cur_live.shift_reg & 0x0004 ? 0x02 : 0x00) | + (cur_live.shift_reg & 0x0001 ? 0x01 : 0x00), + cur_live.bit_counter); +#endif + + if(cur_live.shift_reg == 0x4489) { + cur_live.crc = 0x443b; + cur_live.data_separator_phase = false; + cur_live.bit_counter = 0; + cur_live.state = READ_HEADER_BLOCK_HEADER; + } + break; + + case READ_HEADER_BLOCK_HEADER: { + if(read_one_bit(limit)) + return; +#if 0 + fprintf(stderr, "%s: shift = %04x data=%02x counter=%d\n", tts(cur_live.tm).cstr(), cur_live.shift_reg, + (cur_live.shift_reg & 0x4000 ? 0x80 : 0x00) | + (cur_live.shift_reg & 0x1000 ? 0x40 : 0x00) | + (cur_live.shift_reg & 0x0400 ? 0x20 : 0x00) | + (cur_live.shift_reg & 0x0100 ? 0x10 : 0x00) | + (cur_live.shift_reg & 0x0040 ? 0x08 : 0x00) | + (cur_live.shift_reg & 0x0010 ? 0x04 : 0x00) | + (cur_live.shift_reg & 0x0004 ? 0x02 : 0x00) | + (cur_live.shift_reg & 0x0001 ? 0x01 : 0x00), + cur_live.bit_counter); +#endif + if(cur_live.bit_counter & 15) + break; + + int slot = cur_live.bit_counter >> 4; + + if(slot < 3) { + if(cur_live.shift_reg != 0x4489) + cur_live.state = SEARCH_ADDRESS_MARK_HEADER; + break; + } + if(cur_live.data_reg != 0xfe && cur_live.data_reg != 0xff) { + cur_live.state = SEARCH_ADDRESS_MARK_HEADER; + break; + } + + cur_live.bit_counter = 0; + + if(main_state == READ_ID) + cur_live.state = READ_ID_BLOCK_TO_DMA; + else + cur_live.state = READ_ID_BLOCK_TO_LOCAL; + + break; + } + + case READ_ID_BLOCK_TO_LOCAL: { + if(read_one_bit(limit)) + return; + if(cur_live.bit_counter & 15) + break; + int slot = (cur_live.bit_counter >> 4)-1; + cur_live.idbuf[slot] = cur_live.data_reg; + if(slot == 5) { + live_delay(IDLE); + return; + } + break; + } + + case READ_ID_BLOCK_TO_DMA: { + if(read_one_bit(limit)) + return; + if(cur_live.bit_counter & 15) + break; + live_delay(READ_ID_BLOCK_TO_DMA_BYTE); + return; + } + + case READ_ID_BLOCK_TO_DMA_BYTE: + data = cur_live.data_reg; + if(cur_live.bit_counter == 16) + sector = data; + set_drq(); + + if(cur_live.bit_counter == 16*6) { + // Already synchronous + cur_live.state = IDLE; + return; + } + + cur_live.state = READ_ID_BLOCK_TO_DMA; + checkpoint(); + break; + + case SEARCH_ADDRESS_MARK_DATA: + if(read_one_bit(limit)) + return; +#if 0 + fprintf(stderr, "%s: shift = %04x data=%02x c=%d.%x\n", tts(cur_live.tm).cstr(), cur_live.shift_reg, + (cur_live.shift_reg & 0x4000 ? 0x80 : 0x00) | + (cur_live.shift_reg & 0x1000 ? 0x40 : 0x00) | + (cur_live.shift_reg & 0x0400 ? 0x20 : 0x00) | + (cur_live.shift_reg & 0x0100 ? 0x10 : 0x00) | + (cur_live.shift_reg & 0x0040 ? 0x08 : 0x00) | + (cur_live.shift_reg & 0x0010 ? 0x04 : 0x00) | + (cur_live.shift_reg & 0x0004 ? 0x02 : 0x00) | + (cur_live.shift_reg & 0x0001 ? 0x01 : 0x00), + cur_live.bit_counter >> 4, cur_live.bit_counter & 15); +#endif + if(cur_live.bit_counter > 43*16) { + live_delay(SEARCH_ADDRESS_MARK_DATA_FAILED); + return; + } + + if(cur_live.bit_counter >= 28*16 && cur_live.shift_reg == 0x4489) { + cur_live.crc = 0x443b; + cur_live.data_separator_phase = false; + cur_live.bit_counter = 0; + cur_live.state = READ_DATA_BLOCK_HEADER; + } + break; + + case READ_DATA_BLOCK_HEADER: { + if(read_one_bit(limit)) + return; +#if 0 + fprintf(stderr, "%s: shift = %04x data=%02x counter=%d\n", tts(cur_live.tm).cstr(), cur_live.shift_reg, + (cur_live.shift_reg & 0x4000 ? 0x80 : 0x00) | + (cur_live.shift_reg & 0x1000 ? 0x40 : 0x00) | + (cur_live.shift_reg & 0x0400 ? 0x20 : 0x00) | + (cur_live.shift_reg & 0x0100 ? 0x10 : 0x00) | + (cur_live.shift_reg & 0x0040 ? 0x08 : 0x00) | + (cur_live.shift_reg & 0x0010 ? 0x04 : 0x00) | + (cur_live.shift_reg & 0x0004 ? 0x02 : 0x00) | + (cur_live.shift_reg & 0x0001 ? 0x01 : 0x00), + cur_live.bit_counter); +#endif + if(cur_live.bit_counter & 15) + break; + + int slot = cur_live.bit_counter >> 4; + + if(slot < 3) { + if(cur_live.shift_reg != 0x4489) { + live_delay(SEARCH_ADDRESS_MARK_DATA_FAILED); + return; + } + break; + } + if((cur_live.data_reg & 0xfe) != 0xfa && (cur_live.data_reg & 0xfe) != 0xfc) { + live_delay(SEARCH_ADDRESS_MARK_DATA_FAILED); + return; + } + + cur_live.bit_counter = 0; + cur_live.state = READ_SECTOR_DATA; + break; + } + + case SEARCH_ADDRESS_MARK_DATA_FAILED: + status |= S_RNF; + cur_live.state = IDLE; + return; + + case READ_SECTOR_DATA: { + if(read_one_bit(limit)) + return; + if(cur_live.bit_counter & 15) + break; + int slot = (cur_live.bit_counter >> 4)-1; + if(slot < sector_size) { + // Sector data + live_delay(READ_SECTOR_DATA_BYTE); + return; + + } else if(slot < sector_size+2) { + // CRC + if(slot == sector_size+1) { + live_delay(IDLE); + return; + } + } + + break; + } + + case READ_SECTOR_DATA_BYTE: + data = cur_live.data_reg; + set_drq(); + cur_live.state = READ_SECTOR_DATA; + checkpoint(); + break; + + case READ_TRACK_DATA: { + if(read_one_bit(limit)) + return; + if(cur_live.bit_counter != 16 + && cur_live.shift_reg != 0x4489 + && cur_live.shift_reg != 0x5224) + break; + + // Incorrect, hmmm + // Probably >2 + not just after a sync if <16 + + // Transitions 00..00 -> 4489.4489.4489 at varied syncs: + // 0: 00.00.14.a1 1: ff.fe.c2.a1 2: 00.01.14.a1 3: ff.fc.c2.a1 + // 4: 00.02.14.a1 5: ff.f8.c2.a1 6: 00.05.14.a1 7: ff.f0.c2.a1 + // 8: 00.00.0a.a1 9: ff.ff.e1.a1 10: 00.00.14.a1 11: ff.ff.ce.a1 + // 12: 00.00.14.a1 13: ff.ff.c2.a1 14: 00.00.14.a1 15: ff.ff.c2.a1 + + bool output_byte = cur_live.bit_counter > 5; + + cur_live.data_separator_phase = false; + cur_live.bit_counter = 0; + + if(output_byte) { + live_delay(READ_TRACK_DATA_BYTE); + return; + } + + break; + } + + case READ_TRACK_DATA_BYTE: + data = cur_live.data_reg; + set_drq(); + cur_live.state = READ_TRACK_DATA; + checkpoint(); + break; + + case WRITE_TRACK_DATA: + if(drq) { + status |= S_LOST; + data = 0; + } + + switch(data) { + case 0xf5: + live_write_raw(0x4489); + cur_live.crc = 0x968b; // Ensures that the crc is cdb4 after writing the byte + cur_live.previous_type = live_info::PT_NONE; + break; + case 0xf6: + cur_live.previous_type = live_info::PT_NONE; + live_write_raw(0x5224); + break; + case 0xf7: + if(cur_live.previous_type == live_info::PT_CRC_2) { + cur_live.previous_type = live_info::PT_NONE; + live_write_mfm(0xf7); + } else { + cur_live.previous_type = live_info::PT_CRC_1; + live_write_mfm(cur_live.crc >> 8); + } + break; + default: + cur_live.previous_type = live_info::PT_NONE; + live_write_mfm(data); + break; + } + set_drq(); + cur_live.state = WRITE_BYTE; + cur_live.bit_counter = 16; + checkpoint(); + break; + + case WRITE_BYTE: + if(write_one_bit(limit)) + return; + if(cur_live.bit_counter == 0) { + live_delay(WRITE_BYTE_DONE); + return; + } + break; + + case WRITE_BYTE_DONE: + switch(sub_state) { + case TRACK_DONE: + if(cur_live.previous_type == live_info::PT_CRC_1) { + cur_live.previous_type = live_info::PT_CRC_2; + live_write_mfm(cur_live.crc >> 8); + cur_live.state = WRITE_BYTE; + cur_live.bit_counter = 16; + checkpoint(); + } else + cur_live.state = WRITE_TRACK_DATA; + break; + + case SECTOR_WRITE: + cur_live.state = WRITE_BYTE; + cur_live.bit_counter = 16; + cur_live.byte_counter++; + if(cur_live.byte_counter <= 11) + live_write_mfm(0x00); + else if(cur_live.byte_counter == 12) { + cur_live.crc = 0xffff; + live_write_raw(0x4489); + } else if(cur_live.byte_counter <= 14) + live_write_raw(0x4489); + else if(cur_live.byte_counter == 15) + live_write_mfm(command & 1 ? 0xf8 : 0xfb); + else if(cur_live.byte_counter <= sector_size + 16-2) { + if(drq) { + status |= S_LOST; + data = 0; + } + live_write_mfm(data); + set_drq(); + } else if(cur_live.byte_counter == sector_size + 16-1) { + if(drq) { + status |= S_LOST; + data = 0; + } + live_write_mfm(data); + } else if(cur_live.byte_counter <= sector_size + 16+1) + live_write_mfm(cur_live.crc >> 8); + else if(cur_live.byte_counter == sector_size + 16+2) + // Is that correct? It seems required (try ST formatting) + live_write_mfm(0xff); + else { + cur_live.pll.stop_writing(floppy, cur_live.tm); + cur_live.state = IDLE; + return; + } + + checkpoint(); + break; + + default: + logerror("%s: Unknown sub state %d in WRITE_BYTE_DONE\n", tts(cur_live.tm).cstr(), sub_state); + live_abort(); + return; + } + break; + + case WRITE_SECTOR_PRE: + if(read_one_bit(limit)) + return; + if(cur_live.bit_counter != 16) + break; + live_delay(WRITE_SECTOR_PRE_BYTE); + return; + + case WRITE_SECTOR_PRE_BYTE: + cur_live.state = WRITE_SECTOR_PRE; + cur_live.byte_counter++; + cur_live.bit_counter = 0; + switch(cur_live.byte_counter) { + case 2: + set_drq(); + checkpoint(); + break; + case 11: + if(drq) { + status |= S_LOST; + cur_live.state = IDLE; + return; + } + break; + case 22: + cur_live.state = WRITE_BYTE; + cur_live.bit_counter = 16; + cur_live.byte_counter = 0; + cur_live.data_bit_context = cur_live.data_reg & 1; + cur_live.pll.start_writing(cur_live.tm); + live_write_mfm(0x00); + break; + } + break; + + default: + logerror("%s: Unknown live state %d\n", tts(cur_live.tm).cstr(), cur_live.state); + return; + } + } +} + +void wd177x_t::set_drq() +{ + if(drq) + status |= S_LOST; + else { + drq = true; + if(!drq_cb.isnull()) + drq_cb(true); + } +} + +void wd177x_t::drop_drq() +{ + if(drq) { + drq = false; + if(!drq_cb.isnull()) + drq_cb(false); + } +} + +void wd177x_t::pll_t::set_clock(attotime period) +{ + for(int i=0; i<42; i++) + delays[i] = period*(i+1); +} + +void wd177x_t::pll_t::reset(attotime when) +{ + counter = 0; + increment = 128; + transition_time = 0xffff; + history = 0x80; + slot = 0; + ctime = when; + phase_add = 0x00; + phase_sub = 0x00; + freq_add = 0x00; + freq_sub = 0x00; + write_position = 0; + write_start_time = attotime::never; +} + +int wd177x_t::pll_t::get_next_bit(attotime &tm, floppy_image_device *floppy, attotime limit) +{ + attotime when = floppy ? floppy->get_next_transition(ctime) : attotime::never; +#if 0 + if(!when.is_never()) + fprintf(stderr, "transition_time=%s\n", tts(when).cstr()); +#endif + + for(;;) { + // fprintf(stderr, "slot=%2d, counter=%03x\n", slot, counter); + attotime etime = ctime+delays[slot]; + // fprintf(stderr, "etime=%s\n", tts(etime).cstr()); + if(etime > limit) + return -1; + if(transition_time == 0xffff && !when.is_never() && etime >= when) + transition_time = counter; + if(slot < 8) { + UINT8 mask = 1 << slot; + if(phase_add & mask) + counter += 226; + else if(phase_sub & mask) + counter += 30; + else + counter += increment; + + if((freq_add & mask) && increment < 140) + increment++; + else if((freq_sub & mask) && increment > 117) + increment--; + } else + counter += increment; + + slot++; + tm = etime; + if(counter & 0x800) + break; + } + // fprintf(stderr, "first transition, time=%03x, inc=%3d\n", transition_time, increment); + int bit = transition_time != 0xffff; + + if(transition_time != 0xffff) { + static const UINT8 pha[8] = { 0xf, 0x7, 0x3, 0x1, 0, 0, 0, 0 }; + static const UINT8 phs[8] = { 0, 0, 0, 0, 0x1, 0x3, 0x7, 0xf }; + static const UINT8 freqa[4][8] = { + { 0xf, 0x7, 0x3, 0x1, 0, 0, 0, 0 }, + { 0x7, 0x3, 0x1, 0, 0, 0, 0, 0 }, + { 0x7, 0x3, 0x1, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0 } + }; + static const UINT8 freqs[4][8] = { + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0x1, 0x3, 0x7 }, + { 0, 0, 0, 0, 0, 0x1, 0x3, 0x7 }, + { 0, 0, 0, 0, 0x1, 0x3, 0x7, 0xf }, + }; + + int cslot = transition_time >> 8; + phase_add = pha[cslot]; + phase_sub = phs[cslot]; + int way = transition_time & 0x400 ? 1 : 0; + if(history & 0x80) + history = way ? 0x80 : 0x83; + else if(history & 0x40) + history = way ? history & 2 : (history & 2) | 1; + freq_add = freqa[history & 3][cslot]; + freq_sub = freqs[history & 3][cslot]; + history = way ? (history >> 1) | 2 : history >> 1; + + } else + phase_add = phase_sub = freq_add = freq_sub = 0; + + counter &= 0x7ff; + + ctime = tm; + transition_time = 0xffff; + slot = 0; + + return bit; +} + +void wd177x_t::pll_t::start_writing(attotime tm) +{ + write_start_time = tm; + write_position = 0; +} + +void wd177x_t::pll_t::stop_writing(floppy_image_device *floppy, attotime tm) +{ + commit(floppy, tm); + write_start_time = attotime::never; +} + +bool wd177x_t::pll_t::write_next_bit(bool bit, attotime &tm, floppy_image_device *floppy, attotime limit) +{ + if(write_start_time.is_never()) { + write_start_time = ctime; + write_position = 0; + } + + for(;;) { + attotime etime = ctime+delays[slot]; + if(etime > limit) + return true; + UINT16 pre_counter = counter; + counter += increment; + if(bit && !(pre_counter & 0x400) && (counter & 0x400)) + if(write_position < ARRAY_LENGTH(write_buffer)) + write_buffer[write_position++] = etime; + slot++; + tm = etime; + if(counter & 0x800) + break; + } + + counter &= 0x7ff; + + ctime = tm; + slot = 0; + + return false; +} + +void wd177x_t::pll_t::commit(floppy_image_device *floppy, attotime tm) +{ + if(write_start_time.is_never() || tm == write_start_time) + return; + + if(floppy) + floppy->write_flux(write_start_time, tm, write_position, write_buffer); + write_start_time = tm; + write_position = 0; +} + +int wd177x_t::step_time(int mode) const +{ + const static int step_times[4] = { 48000, 96000, 160000, 240000 }; + return step_times[mode]; +} + +int wd177x_t::settle_time() const +{ + return 240000; +} + +bool wd177x_t::has_ready() const +{ + return false; +} + +bool wd177x_t::has_head_load() const +{ + return false; +} + +bool wd177x_t::has_side_check() const +{ + return false; +} + +bool wd177x_t::has_side_select() const +{ + return false; +} + +bool wd177x_t::has_sector_length_select() const +{ + return false; +} + +bool wd177x_t::has_precompensation() const +{ + return false; +} + +fd1771_t::fd1771_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : wd177x_t(mconfig, FD1771x, "FD1771", tag, owner, clock) +{ +} + +fd1793_t::fd1793_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : wd177x_t(mconfig, FD1793x, "FD1793", tag, owner, clock) +{ +} + +fd1797_t::fd1797_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : wd177x_t(mconfig, FD1797x, "FD1797", tag, owner, clock) +{ +} + +wd2793_t::wd2793_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : wd177x_t(mconfig, WD2793x, "WD2793", tag, owner, clock) +{ +} + +wd2797_t::wd2797_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : wd177x_t(mconfig, WD2797x, "WD2797", tag, owner, clock) +{ +} + +wd1770_t::wd1770_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : wd177x_t(mconfig, WD1770x, "WD1770", tag, owner, clock) +{ +} + +wd1772_t::wd1772_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : wd177x_t(mconfig, WD1772x, "WD1772", tag, owner, clock) +{ +} + +int wd1772_t::step_time(int mode) const +{ + const static int step_times[4] = { 48000, 96000, 16000, 24000 }; + return step_times[mode]; +} + +int wd1772_t::settle_time() const +{ + return 120000; +} + +wd1773_t::wd1773_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : wd177x_t(mconfig, WD1773x, "WD1773", tag, owner, clock) +{ +} diff --git a/src/emu/machine/wd1772.h b/src/emu/machine/wd1772.h index e69de29bb2d..22803f6ad39 100644 --- a/src/emu/machine/wd1772.h +++ b/src/emu/machine/wd1772.h @@ -0,0 +1,431 @@ +#ifndef WD1772_H +#define WD1772_H + +#include "emu.h" +#include "imagedev/floppy.h" + +#define MCFG_FD1771x_ADD(_tag, _clock) \ + MCFG_DEVICE_ADD(_tag, FD1771x, _clock) + +#define MCFG_FD1793x_ADD(_tag, _clock) \ + MCFG_DEVICE_ADD(_tag, FD1793x, _clock) + +#define MCFG_FD1797x_ADD(_tag, _clock) \ + MCFG_DEVICE_ADD(_tag, FD1797x, _clock) + +#define MCFG_WD2793x_ADD(_tag, _clock) \ + MCFG_DEVICE_ADD(_tag, WD2793x, _clock) + +#define MCFG_WD2797x_ADD(_tag, _clock) \ + MCFG_DEVICE_ADD(_tag, WD2797x, _clock) + +#define MCFG_WD1770x_ADD(_tag, _clock) \ + MCFG_DEVICE_ADD(_tag, WD1770x, _clock) + +#define MCFG_WD1772x_ADD(_tag, _clock) \ + MCFG_DEVICE_ADD(_tag, WD1772x, _clock) + +#define MCFG_WD1773x_ADD(_tag, _clock) \ + MCFG_DEVICE_ADD(_tag, WD1773x, _clock) + +class wd177x_t : public device_t { +public: + typedef delegate line_cb; + + wd177x_t(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock); + + void dden_w(bool dden); + void set_floppy(floppy_image_device *floppy); + void setup_intrq_cb(line_cb cb); + void setup_drq_cb(line_cb cb); + void setup_hld_cb(line_cb cb); + void setup_enp_cb(line_cb cb); + + void cmd_w(UINT8 val); + UINT8 status_r(); + DECLARE_READ8_MEMBER( status_r ) { return status_r(); } + DECLARE_WRITE8_MEMBER( cmd_w ) { cmd_w(data); } + + void track_w(UINT8 val); + UINT8 track_r(); + DECLARE_READ8_MEMBER( track_r ) { return track_r(); } + DECLARE_WRITE8_MEMBER( track_w ) { track_w(data); } + + void sector_w(UINT8 val); + UINT8 sector_r(); + DECLARE_READ8_MEMBER( sector_r ) { return sector_r(); } + DECLARE_WRITE8_MEMBER( sector_w ) { sector_w(data); } + + void data_w(UINT8 val); + UINT8 data_r(); + DECLARE_READ8_MEMBER( data_r ) { return data_r(); } + DECLARE_WRITE8_MEMBER( data_w ) { data_w(data); } + + void gen_w(int reg, UINT8 val); + UINT8 gen_r(int reg); + DECLARE_READ8_MEMBER( read ) { return gen_r(offset);} + DECLARE_WRITE8_MEMBER( write ) { gen_w(offset,data); } + + bool intrq_r(); + bool drq_r(); + + bool hld_r(); + void hlt_w(bool state); + + bool enp_r(); + +protected: + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + virtual bool has_ready() const; + virtual bool has_motor() const = 0; + virtual bool has_head_load() const; + virtual bool has_side_check() const; + virtual bool has_side_select() const; + virtual bool has_sector_length_select() const; + virtual bool has_precompensation() const; + virtual int step_time(int mode) const; + virtual int settle_time() const; + +private: + enum { TM_GEN, TM_CMD, TM_TRACK, TM_SECTOR }; + + // State machine general behaviour: + // + // There are three levels of state. + // + // Main state is associated to (groups of) commands. They're set + // by a *_start() function below, and the associated _continue() + // function can then be called at pretty much any time. + // + // Sub state is the state of execution within a command. The + // principle is that the *_start() function selects the initial + // substate, then the *_continue() function decides what to do, + // possibly changing state. Eventually it can: + // - decide to wait for an event (timer, index) + // - end the command with command_end() + // - start a live state (see below) + // + // In the first case, it must first switch to a waiting + // sub-state, then return. The waiting sub-state must just + // return immediatly when *_continue is called. Eventually the + // event handler function will advance the state machine to + // another sub-state, and things will continue synchronously. + // + // On command end it's also supposed to return immediatly. + // + // The last option is to switch to the next sub-state, start a + // live state with live_start() then return. The next sub-state + // will only be called once the live state is finished. + // + // Live states change continually depending on the disk contents + // until the next externally discernable event is found. They + // are checkpointing, run until an event is found, then they wait + // for it. When an event eventually happen the the changes are + // either committed or replayed until the sync event time. + // + // The transition to IDLE is only done on a synced event. Some + // other transitions, such as activating drq, are also done after + // syncing without exiting live mode. Syncing in live mode is + // done by calling live_delay() with the state to change to after + // syncing. + + enum { + // General "doing nothing" state + IDLE, + + // Main states - the commands + RESTORE, + SEEK, + STEP, + READ_SECTOR, + READ_TRACK, + READ_ID, + WRITE_TRACK, + WRITE_SECTOR, + + // Sub states + + SPINUP, + SPINUP_WAIT, + SPINUP_DONE, + + SETTLE_WAIT, + SETTLE_DONE, + + DATA_LOAD_WAIT, + DATA_LOAD_WAIT_DONE, + + SEEK_MOVE, + SEEK_WAIT_STEP_TIME, + SEEK_WAIT_STEP_TIME_DONE, + SEEK_WAIT_STABILIZATION_TIME, + SEEK_WAIT_STABILIZATION_TIME_DONE, + SEEK_DONE, + + WAIT_INDEX, + WAIT_INDEX_DONE, + + SCAN_ID, + SCAN_ID_FAILED, + + SECTOR_READ, + SECTOR_WRITE, + TRACK_DONE, + + // Live states + + SEARCH_ADDRESS_MARK_HEADER, + READ_HEADER_BLOCK_HEADER, + READ_DATA_BLOCK_HEADER, + READ_ID_BLOCK_TO_LOCAL, + READ_ID_BLOCK_TO_DMA, + READ_ID_BLOCK_TO_DMA_BYTE, + SEARCH_ADDRESS_MARK_DATA, + SEARCH_ADDRESS_MARK_DATA_FAILED, + READ_SECTOR_DATA, + READ_SECTOR_DATA_BYTE, + READ_TRACK_DATA, + READ_TRACK_DATA_BYTE, + WRITE_TRACK_DATA, + WRITE_BYTE, + WRITE_BYTE_DONE, + WRITE_SECTOR_PRE, + WRITE_SECTOR_PRE_BYTE, + }; + + struct pll_t { + UINT16 counter; + UINT16 increment; + UINT16 transition_time; + UINT8 history; + UINT8 slot; + UINT8 phase_add, phase_sub, freq_add, freq_sub; + attotime ctime; + + attotime delays[42]; + + attotime write_start_time; + attotime write_buffer[32]; + int write_position; + + void set_clock(attotime period); + void reset(attotime when); + int get_next_bit(attotime &tm, floppy_image_device *floppy, attotime limit); + bool write_next_bit(bool bit, attotime &tm, floppy_image_device *floppy, attotime limit); + void start_writing(attotime tm); + void commit(floppy_image_device *floppy, attotime tm); + void stop_writing(floppy_image_device *floppy, attotime tm); + }; + + struct live_info { + enum { PT_NONE, PT_CRC_1, PT_CRC_2 }; + + attotime tm; + int state, next_state; + UINT16 shift_reg; + UINT16 crc; + int bit_counter, byte_counter, previous_type; + bool data_separator_phase, data_bit_context; + UINT8 data_reg; + UINT8 idbuf[6]; + pll_t pll; + }; + + enum { + S_BUSY = 0x01, + S_DRQ = 0x02, + S_IP = 0x02, + S_TR00 = 0x04, + S_LOST = 0x04, + S_CRC = 0x08, + S_RNF = 0x10, + S_HLD = 0x20, + S_SPIN = 0x20, // WD1770, WD1772 + S_DDM = 0x20, + S_WF = 0x20, // WD1773 + S_WP = 0x40, + S_NRDY = 0x80, + S_MON = 0x80 // WD1770, WD1772 + }; + + enum { + I_RDY = 0x01, + I_NRDY = 0x02, + I_IDX = 0x04, + I_IMM = 0x08 + }; + + floppy_image_device *floppy; + + emu_timer *t_gen, *t_cmd, *t_track, *t_sector; + + bool dden, status_type_1, intrq, drq, hld, hlt, enp; + int main_state, sub_state; + UINT8 command, track, sector, data, status, intrq_cond; + int last_dir; + + int counter, motor_timeout, sector_size; + + int cmd_buffer, track_buffer, sector_buffer; + + live_info cur_live, checkpoint_live; + line_cb intrq_cb, drq_cb, hld_cb, enp_cb; + + static astring tts(attotime t); + astring ttsn(); + + void delay_cycles(emu_timer *tm, int cycles); + + // Device timer subfunctions + void do_cmd_w(); + void do_track_w(); + void do_sector_w(); + void do_generic(); + + + // Main-state handling functions + void seek_start(int state); + void seek_continue(); + + void read_sector_start(); + void read_sector_continue(); + + void read_track_start(); + void read_track_continue(); + + void read_id_start(); + void read_id_continue(); + + void write_track_start(); + void write_track_continue(); + + void write_sector_start(); + void write_sector_continue(); + + void interrupt_start(); + + void general_continue(); + void command_end(); + + void spinup(); + void index_callback(floppy_image_device *floppy, int state); + bool sector_matches() const; + bool is_ready(); + + void live_start(int live_state); + void live_abort(); + void checkpoint(); + void rollback(); + void live_delay(int state); + void live_sync(); + void live_run(attotime limit = attotime::never); + bool read_one_bit(attotime limit); + bool write_one_bit(attotime limit); + + void live_write_raw(UINT16 raw); + void live_write_mfm(UINT8 mfm); + + void drop_drq(); + void set_drq(); +}; + +class fd1771_t : public wd177x_t { +public: + fd1771_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual bool has_ready() const { return true; } + virtual bool has_motor() const { return false; } + virtual bool has_head_load() const { return true; } + virtual bool has_side_check() const { return true; } +}; + +class fd1793_t : public wd177x_t { +public: + fd1793_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual bool has_ready() const { return true; } + virtual bool has_motor() const { return false; } + virtual bool has_head_load() const { return true; } + virtual bool has_side_check() const { return true; } +}; + +class fd1797_t : public wd177x_t { +public: + fd1797_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual bool has_ready() const { return true; } + virtual bool has_motor() const { return false; } + virtual bool has_head_load() const { return true; } + virtual bool has_side_select() const { return true; } + virtual bool has_sector_length_select() const { return true; } +}; + +class wd2793_t : public wd177x_t { +public: + wd2793_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual bool has_ready() const { return true; } + virtual bool has_motor() const { return false; } + virtual bool has_head_load() const { return true; } + virtual bool has_side_check() const { return true; } +}; + +class wd2797_t : public wd177x_t { +public: + wd2797_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual bool has_ready() const { return true; } + virtual bool has_motor() const { return false; } + virtual bool has_head_load() const { return true; } + virtual bool has_side_select() const { return true; } + virtual bool has_sector_length_select() const { return true; } +}; + +class wd1770_t : public wd177x_t { +public: + wd1770_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual bool has_motor() const { return true; } + virtual bool has_precompensation() const { return true; } +}; + +class wd1772_t : public wd177x_t { +public: + wd1772_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual bool has_motor() const { return true; } + virtual bool has_precompensation() const { return true; } + virtual int step_time(int mode) const; + virtual int settle_time() const; +}; + +class wd1773_t : public wd177x_t { +public: + wd1773_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual bool has_motor() const { return false; } + virtual bool has_head_load() const { return true; } + virtual bool has_side_check() const { return true; } +}; + +extern const device_type FD1771x; +extern const device_type FD1793x; +extern const device_type FD1797x; +extern const device_type WD2793x; +extern const device_type WD2797x; +extern const device_type WD1770x; +extern const device_type WD1772x; +extern const device_type WD1773x; + +#endif diff --git a/src/mess/machine/pc_fdc.h b/src/mess/machine/pc_fdc.h index e812b5ac6a2..e80fd82e8e1 100644 --- a/src/mess/machine/pc_fdc.h +++ b/src/mess/machine/pc_fdc.h @@ -9,7 +9,7 @@ #include "emu.h" #include "imagedev/floppy.h" -#include "upd765.h" +#include "machine/upd765.h" #define MCFG_PC_FDC_XT_ADD(_tag) \ MCFG_DEVICE_ADD(_tag, PC_FDC_XT, 0) diff --git a/src/mess/machine/upd765.c b/src/mess/machine/upd765.c deleted file mode 100644 index d994406a9d2..00000000000 --- a/src/mess/machine/upd765.c +++ /dev/null @@ -1,2320 +0,0 @@ -#include "debugger.h" - -#include "upd765.h" - -const device_type UPD765A = &device_creator; -const device_type UPD765B = &device_creator; -const device_type I8272A = &device_creator; -const device_type UPD72065 = &device_creator; -const device_type SMC37C78 = &device_creator; -const device_type N82077AA = &device_creator; -const device_type PC_FDC_SUPERIO = &device_creator; - -DEVICE_ADDRESS_MAP_START(map, 8, upd765a_device) - AM_RANGE(0x0, 0x0) AM_READ(msr_r) - AM_RANGE(0x1, 0x1) AM_READWRITE(fifo_r, fifo_w) -ADDRESS_MAP_END - -DEVICE_ADDRESS_MAP_START(map, 8, upd765b_device) - AM_RANGE(0x0, 0x0) AM_READ(msr_r) - AM_RANGE(0x1, 0x1) AM_READWRITE(fifo_r, fifo_w) -ADDRESS_MAP_END - -DEVICE_ADDRESS_MAP_START(map, 8, i8272a_device) - AM_RANGE(0x0, 0x0) AM_READ(msr_r) - AM_RANGE(0x1, 0x1) AM_READWRITE(fifo_r, fifo_w) -ADDRESS_MAP_END - -DEVICE_ADDRESS_MAP_START(map, 8, upd72065_device) - AM_RANGE(0x0, 0x0) AM_READ(msr_r) - AM_RANGE(0x1, 0x1) AM_READWRITE(fifo_r, fifo_w) -ADDRESS_MAP_END - -DEVICE_ADDRESS_MAP_START(map, 8, smc37c78_device) - AM_RANGE(0x2, 0x2) AM_READWRITE(dor_r, dor_w) - AM_RANGE(0x3, 0x3) AM_READWRITE(tdr_r, tdr_w) - AM_RANGE(0x4, 0x4) AM_READWRITE(msr_r, dsr_w) - AM_RANGE(0x5, 0x5) AM_READWRITE(fifo_r, fifo_w) - AM_RANGE(0x7, 0x7) AM_READWRITE(dir_r, ccr_w) -ADDRESS_MAP_END - -DEVICE_ADDRESS_MAP_START(map, 8, n82077aa_device) - AM_RANGE(0x0, 0x0) AM_READ(sra_r) - AM_RANGE(0x1, 0x1) AM_READ(srb_r) - AM_RANGE(0x2, 0x2) AM_READWRITE(dor_r, dor_w) - AM_RANGE(0x3, 0x3) AM_READWRITE(tdr_r, tdr_w) - AM_RANGE(0x4, 0x4) AM_READWRITE(msr_r, dsr_w) - AM_RANGE(0x5, 0x5) AM_READWRITE(fifo_r, fifo_w) - AM_RANGE(0x7, 0x7) AM_READWRITE(dir_r, ccr_w) -ADDRESS_MAP_END - -DEVICE_ADDRESS_MAP_START(map, 8, pc_fdc_superio_device) - AM_RANGE(0x0, 0x0) AM_READ(sra_r) - AM_RANGE(0x1, 0x1) AM_READ(srb_r) - AM_RANGE(0x2, 0x2) AM_READWRITE(dor_r, dor_w) - AM_RANGE(0x3, 0x3) AM_READWRITE(tdr_r, tdr_w) - AM_RANGE(0x4, 0x4) AM_READWRITE(msr_r, dsr_w) - AM_RANGE(0x5, 0x5) AM_READWRITE(fifo_r, fifo_w) - AM_RANGE(0x7, 0x7) AM_READWRITE(dir_r, ccr_w) -ADDRESS_MAP_END - - -int upd765_family_device::rates[4] = { 500000, 300000, 250000, 1000000 }; - -upd765_family_device::upd765_family_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock) : pc_fdc_interface(mconfig, type, name, tag, owner, clock) -{ - ready_polled = true; - ready_connected = true; - select_connected = true; - external_ready = true; - dor_reset = 0x00; -} - -void upd765_family_device::set_ready_line_connected(bool _ready) -{ - ready_connected = _ready; -} - -void upd765_family_device::set_select_lines_connected(bool _select) -{ - select_connected = _select; -} - -void upd765_family_device::set_mode(int _mode) -{ - // TODO -} - -void upd765_family_device::setup_intrq_cb(line_cb cb) -{ - intrq_cb = cb; -} - -void upd765_family_device::setup_drq_cb(line_cb cb) -{ - drq_cb = cb; -} - -void upd765_family_device::device_start() -{ - for(int i=0; i != 4; i++) { - char name[2]; - flopi[i].tm = timer_alloc(i); - flopi[i].id = i; - if(select_connected) { - name[0] = '0'+i; - name[1] = 0; - floppy_connector *con = subdevice(name); - if(con) { - flopi[i].dev = con->get_device(); - flopi[i].dev->setup_index_pulse_cb(floppy_image_device::index_pulse_cb(FUNC(upd765_family_device::index_callback), this)); - } else - flopi[i].dev = NULL; - } else - flopi[i].dev = NULL; - } - cur_rate = 250000; - tc = false; - - // reset at upper levels may cause a write to tc ending up with - // live_sync, which will crash if the live structure isn't - // initialized enough - - cur_live.tm = attotime::never; - cur_live.state = IDLE; - cur_live.next_state = -1; - cur_live.fi = NULL; - - if(ready_polled) { - poll_timer = timer_alloc(TIMER_DRIVE_READY_POLLING); - poll_timer->adjust(attotime::from_usec(1024), 0, attotime::from_usec(1024)); - } else - poll_timer = NULL; - - cur_irq = false; - locked = false; -} - -void upd765_family_device::device_reset() -{ - dor = dor_reset; - locked = false; - soft_reset(); -} - -void upd765_family_device::soft_reset() -{ - main_phase = PHASE_CMD; - for(int i=0; i<4; i++) { - flopi[i].main_state = IDLE; - flopi[i].sub_state = IDLE; - flopi[i].live = false; - flopi[i].ready = !ready_polled; - flopi[i].irq = floppy_info::IRQ_NONE; - } - data_irq = false; - polled_irq = false; - internal_drq = false; - fifo_pos = 0; - command_pos = 0; - result_pos = 0; - if(!locked) - fifocfg = FIF_DIS; - cur_live.fi = 0; - drq = false; - cur_live.tm = attotime::never; - cur_live.state = IDLE; - cur_live.next_state = -1; - cur_live.fi = NULL; - tc_done = false; - st0 = st1 = st2 = st3 = 0x00; - - check_irq(); - if(ready_polled) - poll_timer->adjust(attotime::from_usec(1024), 0, attotime::from_usec(1024)); -} - -void upd765_family_device::tc_w(bool _tc) -{ - logerror("%s: tc=%d\n", tag(), _tc); - if(tc != _tc && _tc) { - live_sync(); - tc_done = true; - tc = _tc; - if(cur_live.fi) - general_continue(*cur_live.fi); - } else - tc = _tc; -} - -void upd765_family_device::ready_w(bool _ready) -{ - external_ready = _ready; -} - -bool upd765_family_device::get_ready(int fid) -{ - if(ready_connected) - return flopi[fid].dev ? !flopi[fid].dev->ready_r() : false; - return external_ready; -} - -void upd765_family_device::set_floppy(floppy_image_device *flop) -{ - for(int fid=0; fid<4; fid++) { - if(flopi[fid].dev) - flopi[fid].dev->setup_index_pulse_cb(floppy_image_device::index_pulse_cb()); - flopi[fid].dev = flop; - } - if(flop) - flop->setup_index_pulse_cb(floppy_image_device::index_pulse_cb(FUNC(upd765_family_device::index_callback), this)); -} - -READ8_MEMBER(upd765_family_device::sra_r) -{ - UINT8 sra = 0; - int fid = dor & 3; - floppy_info &fi = flopi[fid]; - if(fi.dir) - sra |= 0x01; - if(fi.index) - sra |= 0x04; - if(cur_rate >= 500000) - sra |= 0x08; - if(fi.dev && fi.dev->trk00_r()) - sra |= 0x10; - if(fi.main_state == SEEK_WAIT_STEP_SIGNAL_TIME) - sra |= 0x20; - sra |= 0x40; - if(cur_irq) - sra |= 0x80; - if(mode == MODE_M30) - sra ^= 0x1f; - return sra; -} - -READ8_MEMBER(upd765_family_device::srb_r) -{ - return 0; -} - -READ8_MEMBER(upd765_family_device::dor_r) -{ - return dor; -} - -WRITE8_MEMBER(upd765_family_device::dor_w) -{ - logerror("%s: dor = %02x\n", tag(), data); - UINT8 diff = dor ^ data; - dor = data; - if(diff & 4) - soft_reset(); - - for(int i=0; i<4; i++) { - floppy_info &fi = flopi[i]; - if(fi.dev) - fi.dev->mon_w(!(dor & (0x10 << i))); - } - check_irq(); -} - -READ8_MEMBER(upd765_family_device::tdr_r) -{ - return 0; -} - -WRITE8_MEMBER(upd765_family_device::tdr_w) -{ -} - -READ8_MEMBER(upd765_family_device::msr_r) -{ - UINT32 msr = 0; - switch(main_phase) { - case PHASE_CMD: - msr |= MSR_RQM; - if(command_pos) - msr |= MSR_CB; - break; - case PHASE_EXEC: - msr |= MSR_CB; - if(spec & SPEC_ND) - msr |= MSR_EXM; - if(internal_drq) { - msr |= MSR_RQM; - if(!fifo_write) - msr |= MSR_DIO; - } - break; - - case PHASE_RESULT: - msr |= MSR_RQM|MSR_DIO|MSR_CB; - break; - } - for(int i=0; i<4; i++) - if(flopi[i].main_state == RECALIBRATE || flopi[i].main_state == SEEK) { - msr |= 1<dskchg_r() ? 0x00 : 0x80; - return 0x00; -} - -READ8_MEMBER(upd765_family_device::dir_r) -{ - return do_dir_r(); -} - -WRITE8_MEMBER(upd765_family_device::ccr_w) -{ - dsr = (dsr & 0xfc) | (data & 3); - cur_rate = rates[data & 3]; -} - -void upd765_family_device::set_drq(bool state) -{ - if(state != drq) { - drq = state; - if(!drq_cb.isnull()) - drq_cb(drq); - } -} - -bool upd765_family_device::get_drq() const -{ - return drq; -} - -void upd765_family_device::enable_transfer() -{ - if(spec & SPEC_ND) { - // PIO - if(!internal_drq) { - internal_drq = true; - check_irq(); - } - - } else { - // DMA - if(!drq) - set_drq(true); - } -} - -void upd765_family_device::disable_transfer() -{ - if(spec & SPEC_ND) { - internal_drq = false; - check_irq(); - } else - set_drq(false); -} - -void upd765_family_device::fifo_push(UINT8 data, bool internal) -{ - if(fifo_pos == 16) { - if(internal) { - if(!(st1 & ST1_OR)) - logerror("%s: Fifo overrun\n", tag()); - st1 |= ST1_OR; - } - return; - } - fifo[fifo_pos++] = data; - fifo_expected--; - - int thr = (fifocfg & FIF_THR)+1; - if(!fifo_write && (!fifo_expected || fifo_pos >= thr || (fifocfg & FIF_DIS))) - enable_transfer(); - if(fifo_write && (fifo_pos == 16 || !fifo_expected)) - disable_transfer(); -} - - -UINT8 upd765_family_device::fifo_pop(bool internal) -{ - if(!fifo_pos) { - if(internal) { - if(!(st1 & ST1_OR)) - logerror("%s: Fifo underrun\n", tag()); - st1 |= ST1_OR; - } - return 0; - } - UINT8 r = fifo[0]; - fifo_pos--; - memmove(fifo, fifo+1, fifo_pos); - if(!fifo_write && !fifo_pos) - disable_transfer(); - int thr = fifocfg & 15; - if(fifo_write && fifo_expected && (fifo_pos <= thr || (fifocfg & 0x20))) - enable_transfer(); - return r; -} - -void upd765_family_device::fifo_expect(int size, bool write) -{ - fifo_expected = size; - fifo_write = write; - if(fifo_write) - enable_transfer(); -} - -READ8_MEMBER(upd765_family_device::mdma_r) -{ - return dma_r(); -} - -WRITE8_MEMBER(upd765_family_device::mdma_w) -{ - dma_w(data); -} - -UINT8 upd765_family_device::dma_r() -{ - return fifo_pop(false); -} - -void upd765_family_device::dma_w(UINT8 data) -{ - fifo_push(data, false); -} - -void upd765_family_device::live_start(floppy_info &fi, int state) -{ - cur_live.tm = machine().time(); - cur_live.state = state; - cur_live.next_state = -1; - cur_live.fi = &fi; - cur_live.shift_reg = 0; - cur_live.crc = 0xffff; - cur_live.bit_counter = 0; - cur_live.data_separator_phase = false; - cur_live.data_reg = 0; - cur_live.previous_type = live_info::PT_NONE; - cur_live.data_bit_context = false; - cur_live.byte_counter = 0; - cur_live.pll.reset(cur_live.tm); - cur_live.pll.set_clock(attotime::from_hz(mfm ? 2*cur_rate : cur_rate)); - checkpoint_live = cur_live; - fi.live = true; - - live_run(); -} - -void upd765_family_device::checkpoint() -{ - if(cur_live.fi) - cur_live.pll.commit(cur_live.fi->dev, cur_live.tm); - checkpoint_live = cur_live; -} - -void upd765_family_device::rollback() -{ - cur_live = checkpoint_live; -} - -void upd765_family_device::live_delay(int state) -{ - cur_live.next_state = state; - if(cur_live.tm != machine().time()) - cur_live.fi->tm->adjust(cur_live.tm - machine().time()); - else - live_sync(); -} - -void upd765_family_device::live_sync() -{ - if(!cur_live.tm.is_never()) { - if(cur_live.tm > machine().time()) { - rollback(); - live_run(machine().time()); - cur_live.pll.commit(cur_live.fi->dev, cur_live.tm); - } else { - cur_live.pll.commit(cur_live.fi->dev, 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) { - cur_live.pll.stop_writing(cur_live.fi->dev, cur_live.tm); - cur_live.tm = attotime::never; - cur_live.fi->live = false; - cur_live.fi = 0; - } - } - cur_live.next_state = -1; - checkpoint(); - } -} - -void upd765_family_device::live_abort() -{ - if(!cur_live.tm.is_never() && cur_live.tm > machine().time()) { - rollback(); - live_run(machine().time()); - } - - if(cur_live.fi) { - cur_live.pll.stop_writing(cur_live.fi->dev, cur_live.tm); - cur_live.fi->live = false; - cur_live.fi = 0; - } - - cur_live.tm = attotime::never; - cur_live.state = IDLE; - cur_live.next_state = -1; -} - -void upd765_family_device::live_run(attotime limit) -{ - if(cur_live.state == IDLE || cur_live.next_state != -1) - return; - - if(limit == attotime::never) { - if(cur_live.fi->dev) - limit = cur_live.fi->dev->time_next_index(); - if(limit == attotime::never) { - // Happens when there's no disk or if the fdc is not - // connected to a drive, hence no index pulse. Force a - // sync from time to time in that case, so that the main - // cpu timeout isn't too painful. Avoids looping into - // infinity looking for data too. - - limit = machine().time() + attotime::from_msec(1); - cur_live.fi->tm->adjust(attotime::from_msec(1)); - } - } - - for(;;) { - - switch(cur_live.state) { - case SEARCH_ADDRESS_MARK_HEADER: - if(read_one_bit(limit)) - return; -#if 0 - fprintf(stderr, "%s: shift = %04x data=%02x c=%d\n", tts(cur_live.tm).cstr(), cur_live.shift_reg, - (cur_live.shift_reg & 0x4000 ? 0x80 : 0x00) | - (cur_live.shift_reg & 0x1000 ? 0x40 : 0x00) | - (cur_live.shift_reg & 0x0400 ? 0x20 : 0x00) | - (cur_live.shift_reg & 0x0100 ? 0x10 : 0x00) | - (cur_live.shift_reg & 0x0040 ? 0x08 : 0x00) | - (cur_live.shift_reg & 0x0010 ? 0x04 : 0x00) | - (cur_live.shift_reg & 0x0004 ? 0x02 : 0x00) | - (cur_live.shift_reg & 0x0001 ? 0x01 : 0x00), - cur_live.bit_counter); -#endif - - if(mfm && cur_live.shift_reg == 0x4489) { - cur_live.crc = 0x443b; - cur_live.data_separator_phase = false; - cur_live.bit_counter = 0; - cur_live.state = READ_HEADER_BLOCK_HEADER; - } - - if(!mfm && cur_live.shift_reg == 0xf57e) { - cur_live.crc = 0xef21; - cur_live.data_separator_phase = false; - cur_live.bit_counter = 0; - cur_live.state = READ_ID_BLOCK; - } - break; - - case READ_HEADER_BLOCK_HEADER: { - if(read_one_bit(limit)) - return; -#if 0 - fprintf(stderr, "%s: shift = %04x data=%02x counter=%d\n", tts(cur_live.tm).cstr(), cur_live.shift_reg, - (cur_live.shift_reg & 0x4000 ? 0x80 : 0x00) | - (cur_live.shift_reg & 0x1000 ? 0x40 : 0x00) | - (cur_live.shift_reg & 0x0400 ? 0x20 : 0x00) | - (cur_live.shift_reg & 0x0100 ? 0x10 : 0x00) | - (cur_live.shift_reg & 0x0040 ? 0x08 : 0x00) | - (cur_live.shift_reg & 0x0010 ? 0x04 : 0x00) | - (cur_live.shift_reg & 0x0004 ? 0x02 : 0x00) | - (cur_live.shift_reg & 0x0001 ? 0x01 : 0x00), - cur_live.bit_counter); -#endif - if(cur_live.bit_counter & 15) - break; - - int slot = cur_live.bit_counter >> 4; - - if(slot < 3) { - if(cur_live.shift_reg != 0x4489) - cur_live.state = SEARCH_ADDRESS_MARK_HEADER; - break; - } - if(cur_live.data_reg != 0xfe) { - cur_live.state = SEARCH_ADDRESS_MARK_HEADER; - break; - } - - cur_live.bit_counter = 0; - cur_live.state = READ_ID_BLOCK; - - break; - } - - case READ_ID_BLOCK: { - if(read_one_bit(limit)) - return; - if(cur_live.bit_counter & 15) - break; - int slot = (cur_live.bit_counter >> 4)-1; - - if(0) - fprintf(stderr, "%s: slot=%d data=%02x crc=%04x\n", tts(cur_live.tm).cstr(), slot, cur_live.data_reg, cur_live.crc); - cur_live.idbuf[slot] = cur_live.data_reg; - if(slot == 5) { - live_delay(IDLE); - return; - } - break; - } - - case SEARCH_ADDRESS_MARK_DATA: - if(read_one_bit(limit)) - return; -#if 0 - fprintf(stderr, "%s: shift = %04x data=%02x c=%d.%x\n", tts(cur_live.tm).cstr(), cur_live.shift_reg, - (cur_live.shift_reg & 0x4000 ? 0x80 : 0x00) | - (cur_live.shift_reg & 0x1000 ? 0x40 : 0x00) | - (cur_live.shift_reg & 0x0400 ? 0x20 : 0x00) | - (cur_live.shift_reg & 0x0100 ? 0x10 : 0x00) | - (cur_live.shift_reg & 0x0040 ? 0x08 : 0x00) | - (cur_live.shift_reg & 0x0010 ? 0x04 : 0x00) | - (cur_live.shift_reg & 0x0004 ? 0x02 : 0x00) | - (cur_live.shift_reg & 0x0001 ? 0x01 : 0x00), - cur_live.bit_counter >> 4, cur_live.bit_counter & 15); -#endif - - if(mfm) { - // Large tolerance due to perpendicular recording at extended density - if(cur_live.bit_counter > 62*16) { - live_delay(SEARCH_ADDRESS_MARK_DATA_FAILED); - return; - } - - if(cur_live.bit_counter >= 28*16 && cur_live.shift_reg == 0x4489) { - cur_live.crc = 0x443b; - cur_live.data_separator_phase = false; - cur_live.bit_counter = 0; - cur_live.state = READ_DATA_BLOCK_HEADER; - } - - } else { - if(cur_live.bit_counter > 23*16) { - live_delay(SEARCH_ADDRESS_MARK_DATA_FAILED); - return; - } - - if(cur_live.bit_counter >= 11*16 && (cur_live.shift_reg == 0xf56a || cur_live.shift_reg == 0xf56f)) { - cur_live.crc = cur_live.shift_reg == 0xf56a ? 0x8fe7 : 0xbf84; - cur_live.data_separator_phase = false; - cur_live.bit_counter = 0; - cur_live.state = READ_SECTOR_DATA; - } - } - - break; - - case READ_DATA_BLOCK_HEADER: { - if(read_one_bit(limit)) - return; -#if 0 - fprintf(stderr, "%s: shift = %04x data=%02x counter=%d\n", tts(cur_live.tm).cstr(), cur_live.shift_reg, - (cur_live.shift_reg & 0x4000 ? 0x80 : 0x00) | - (cur_live.shift_reg & 0x1000 ? 0x40 : 0x00) | - (cur_live.shift_reg & 0x0400 ? 0x20 : 0x00) | - (cur_live.shift_reg & 0x0100 ? 0x10 : 0x00) | - (cur_live.shift_reg & 0x0040 ? 0x08 : 0x00) | - (cur_live.shift_reg & 0x0010 ? 0x04 : 0x00) | - (cur_live.shift_reg & 0x0004 ? 0x02 : 0x00) | - (cur_live.shift_reg & 0x0001 ? 0x01 : 0x00), - cur_live.bit_counter); -#endif - if(cur_live.bit_counter & 15) - break; - - int slot = cur_live.bit_counter >> 4; - - if(slot < 3) { - if(cur_live.shift_reg != 0x4489) { - live_delay(SEARCH_ADDRESS_MARK_DATA_FAILED); - return; - } - break; - } - if(cur_live.data_reg != 0xfb && cur_live.data_reg != 0xf8) { - live_delay(SEARCH_ADDRESS_MARK_DATA_FAILED); - return; - } - - cur_live.bit_counter = 0; - cur_live.state = READ_SECTOR_DATA; - break; - } - - case SEARCH_ADDRESS_MARK_DATA_FAILED: - st1 |= ST1_MA; - st2 |= ST2_MD; - cur_live.state = IDLE; - return; - - case READ_SECTOR_DATA: { - if(read_one_bit(limit)) - return; - if(cur_live.bit_counter & 15) - break; - int slot = (cur_live.bit_counter >> 4)-1; - if(slot < sector_size) { - // Sector data - live_delay(READ_SECTOR_DATA_BYTE); - return; - - } else if(slot < sector_size+2) { - // CRC - if(slot == sector_size+1) { - live_delay(IDLE); - return; - } - } - break; - } - - case READ_SECTOR_DATA_BYTE: - if(!tc_done) - fifo_push(cur_live.data_reg, true); - cur_live.state = READ_SECTOR_DATA; - checkpoint(); - break; - - case WRITE_SECTOR_SKIP_GAP2: - cur_live.bit_counter = 0; - cur_live.byte_counter = 0; - cur_live.state = WRITE_SECTOR_SKIP_GAP2_BYTE; - checkpoint(); - break; - - case WRITE_SECTOR_SKIP_GAP2_BYTE: - if(read_one_bit(limit)) - return; - if(mfm && cur_live.bit_counter != 22*16) - break; - if(!mfm && cur_live.bit_counter != 11*16) - break; - cur_live.bit_counter = 0; - cur_live.byte_counter = 0; - live_delay(WRITE_SECTOR_DATA); - return; - - case WRITE_SECTOR_DATA: - if(mfm) { - if(cur_live.byte_counter < 12) - live_write_mfm(0x00); - else if(cur_live.byte_counter < 15) - live_write_raw(0x4489); - else if(cur_live.byte_counter < 16) { - cur_live.crc = 0xcdb4; - live_write_mfm(command[0] & 0x08 ? 0xf8 : 0xfb); - } else if(cur_live.byte_counter < 16+sector_size) - live_write_mfm(tc_done && !fifo_pos? 0x00 : fifo_pop(true)); - else if(cur_live.byte_counter < 16+sector_size+2) - live_write_mfm(cur_live.crc >> 8); - else if(cur_live.byte_counter < 16+sector_size+2+command[7]) - live_write_mfm(0x4e); - else { - cur_live.pll.stop_writing(cur_live.fi->dev, cur_live.tm); - cur_live.state = IDLE; - return; - } - - } else { - if(cur_live.byte_counter < 6) - live_write_fm(0x00); - else if(cur_live.byte_counter < 7) { - cur_live.crc = 0xffff; - live_write_raw(command[0] & 0x08 ? 0xf56a : 0xf56f); - } else if(cur_live.byte_counter < 7+sector_size) - live_write_fm(tc_done && !fifo_pos? 0x00 : fifo_pop(true)); - else if(cur_live.byte_counter < 7+sector_size+2) - live_write_fm(cur_live.crc >> 8); - else if(cur_live.byte_counter < 7+sector_size+2+command[7]) - live_write_fm(0xff); - else { - cur_live.pll.stop_writing(cur_live.fi->dev, cur_live.tm); - cur_live.state = IDLE; - return; - } - } - cur_live.state = WRITE_SECTOR_DATA_BYTE; - cur_live.bit_counter = 16; - checkpoint(); - break; - - case WRITE_TRACK_PRE_SECTORS: - if(!cur_live.byte_counter && command[3]) - fifo_expect(4, true); - if(mfm) { - if(cur_live.byte_counter < 80) - live_write_mfm(0x4e); - else if(cur_live.byte_counter < 92) - live_write_mfm(0x00); - else if(cur_live.byte_counter < 95) - live_write_raw(0x5224); - else if(cur_live.byte_counter < 96) - live_write_mfm(0xfc); - else if(cur_live.byte_counter < 146) - live_write_mfm(0x4e); - else { - cur_live.state = WRITE_TRACK_SECTOR; - cur_live.byte_counter = 0; - break; - } - } else { - if(cur_live.byte_counter < 40) - live_write_fm(0xff); - else if(cur_live.byte_counter < 46) - live_write_fm(0x00); - else if(cur_live.byte_counter < 47) - live_write_raw(0xf77a); - else if(cur_live.byte_counter < 73) - live_write_fm(0xff); - else { - cur_live.state = WRITE_TRACK_SECTOR; - cur_live.byte_counter = 0; - break; - } - } - cur_live.state = WRITE_TRACK_PRE_SECTORS_BYTE; - cur_live.bit_counter = 16; - checkpoint(); - break; - - case WRITE_TRACK_SECTOR: - if(!cur_live.byte_counter) { - command[3]--; - if(command[3]) - fifo_expect(4, true); - } - if(mfm) { - if(cur_live.byte_counter < 12) - live_write_mfm(0x00); - else if(cur_live.byte_counter < 15) - live_write_raw(0x4489); - else if(cur_live.byte_counter < 16) { - cur_live.crc = 0xcdb4; - live_write_mfm(0xfe); - } else if(cur_live.byte_counter < 20) - live_write_mfm(fifo_pop(true)); - else if(cur_live.byte_counter < 22) - live_write_mfm(cur_live.crc >> 8); - else if(cur_live.byte_counter < 44) - live_write_mfm(0x4e); - else if(cur_live.byte_counter < 56) - live_write_mfm(0x00); - else if(cur_live.byte_counter < 59) - live_write_raw(0x4489); - else if(cur_live.byte_counter < 60) { - cur_live.crc = 0xcdb4; - live_write_mfm(0xfb); - } else if(cur_live.byte_counter < 60+sector_size) - live_write_mfm(command[5]); - else if(cur_live.byte_counter < 62+sector_size) - live_write_mfm(cur_live.crc >> 8); - else if(cur_live.byte_counter < 62+sector_size+command[4]) - live_write_mfm(0x4e); - else { - cur_live.byte_counter = 0; - cur_live.state = command[3] ? WRITE_TRACK_SECTOR : WRITE_TRACK_POST_SECTORS; - break; - } - - } else { - if(cur_live.byte_counter < 6) - live_write_fm(0x00); - else if(cur_live.byte_counter < 7) { - cur_live.crc = 0xffff; - live_write_raw(0xf57e); - } else if(cur_live.byte_counter < 11) - live_write_fm(fifo_pop(true)); - else if(cur_live.byte_counter < 13) - live_write_fm(cur_live.crc >> 8); - else if(cur_live.byte_counter < 24) - live_write_fm(0xff); - else if(cur_live.byte_counter < 30) - live_write_fm(0x00); - else if(cur_live.byte_counter < 31) { - cur_live.crc = 0xffff; - live_write_raw(0xf56f); - } else if(cur_live.byte_counter < 31+sector_size) - live_write_fm(command[5]); - else if(cur_live.byte_counter < 33+sector_size) - live_write_fm(cur_live.crc >> 8); - else if(cur_live.byte_counter < 33+sector_size+command[4]) - live_write_fm(0xff); - else { - cur_live.byte_counter = 0; - cur_live.state = command[3] ? WRITE_TRACK_SECTOR : WRITE_TRACK_POST_SECTORS; - break; - } - } - cur_live.state = WRITE_TRACK_SECTOR_BYTE; - cur_live.bit_counter = 16; - checkpoint(); - break; - - case WRITE_TRACK_POST_SECTORS: - if(mfm) - live_write_mfm(0x4e); - else - live_write_fm(0xff); - cur_live.state = WRITE_TRACK_POST_SECTORS_BYTE; - cur_live.bit_counter = 16; - checkpoint(); - break; - - case WRITE_TRACK_PRE_SECTORS_BYTE: - case WRITE_TRACK_SECTOR_BYTE: - case WRITE_TRACK_POST_SECTORS_BYTE: - case WRITE_SECTOR_DATA_BYTE: - if(write_one_bit(limit)) - return; - if(cur_live.bit_counter == 0) { - cur_live.byte_counter++; - live_delay(cur_live.state-1); - return; - } - break; - - default: - logerror("%s: Unknown live state %d\n", tts(cur_live.tm).cstr(), cur_live.state); - return; - } - } -} - -int upd765_family_device::check_command() -{ - // 0.000010 read track - // 00000011 specify - // 00000100 sense drive status - // ..000101 write data - // ...00110 read data - // 00000111 recalibrate - // 00001000 sense interrupt status - // ..001001 write deleted data - // 0.001010 read id - // ...01100 read deleted data - // 0.001101 format track - // 00001110 dumpreg - // 00101110 save - // 01001110 restore - // 10001110 drive specification command - // 00001111 seek - // 1.001111 relative seek - // 00010000 version - // ...10001 scan equal - // 00010010 perpendicular mode - // 00010011 configure - // 00110011 option - // .0010100 lock - // ...10110 verify - // 00010111 powerdown mode - // 00011000 part id - // ...11001 scan low or equal - // ...11101 scan high or equal - - // MSDOS 6.22 format uses 0xcd to format a track, which makes one - // think only the bottom 5 bits are decoded. - - switch(command[0] & 0x1f) { - case 0x02: - return command_pos == 9 ? C_READ_TRACK : C_INCOMPLETE; - - case 0x03: - return command_pos == 3 ? C_SPECIFY : C_INCOMPLETE; - - case 0x04: - return command_pos == 2 ? C_SENSE_DRIVE_STATUS : C_INCOMPLETE; - - case 0x05: - case 0x09: - return command_pos == 9 ? C_WRITE_DATA : C_INCOMPLETE; - - case 0x06: - case 0x0c: - return command_pos == 9 ? C_READ_DATA : C_INCOMPLETE; - - case 0x07: - return command_pos == 2 ? C_RECALIBRATE : C_INCOMPLETE; - - case 0x08: - return C_SENSE_INTERRUPT_STATUS; - - case 0x0a: - return command_pos == 2 ? C_READ_ID : C_INCOMPLETE; - - case 0x0d: - return command_pos == 6 ? C_FORMAT_TRACK : C_INCOMPLETE; - - case 0x0e: - return C_DUMP_REG; - - case 0x0f: - return command_pos == 3 ? C_SEEK : C_INCOMPLETE; - - case 0x12: - return command_pos == 2 ? C_PERPENDICULAR : C_INCOMPLETE; - - case 0x13: - return command_pos == 4 ? C_CONFIGURE : C_INCOMPLETE; - - case 0x14: - return C_LOCK; - - default: - return C_INVALID; - } -} - -void upd765_family_device::start_command(int cmd) -{ - command_pos = 0; - result_pos = 0; - main_phase = PHASE_EXEC; - tc_done = false; - switch(cmd) { - case C_CONFIGURE: - logerror("%s: command configure %02x %02x %02x\n", - tag(), - command[1], command[2], command[3]); - // byte 1 is ignored, byte 3 is precompensation-related - fifocfg = command[2]; - precomp = command[3]; - main_phase = PHASE_CMD; - break; - - case C_DUMP_REG: - logerror("%s: command dump regs\n", tag()); - main_phase = PHASE_RESULT; - result[0] = flopi[0].pcn; - result[1] = flopi[1].pcn; - result[2] = flopi[2].pcn; - result[3] = flopi[3].pcn; - result[4] = (spec & 0xff00) >> 8; - result[5] = (spec & 0x00ff); - result[6] = sector_size; - result[7] = locked ? 0x80 : 0x00; - result[7] |= (perpmode & 0x30); - result[8] = fifocfg; - result[9] = precomp; - result_pos = 10; - break; - - case C_FORMAT_TRACK: - format_track_start(flopi[command[1] & 3]); - break; - - case C_LOCK: - locked = command[0] & 0x80; - main_phase = PHASE_RESULT; - result[0] = locked ? 0x10 : 0x00; - result_pos = 1; - logerror("%s: command lock (%s)\n", tag(), locked ? "on" : "off"); - break; - - case C_PERPENDICULAR: - logerror("%s: command perpendicular\n", tag()); - perpmode = command[1]; - main_phase = PHASE_CMD; - break; - - case C_READ_DATA: - read_data_start(flopi[command[1] & 3]); - break; - - case C_READ_ID: - read_id_start(flopi[command[1] & 3]); - break; - - case C_READ_TRACK: - read_track_start(flopi[command[1] & 3]); - break; - - case C_RECALIBRATE: - recalibrate_start(flopi[command[1] & 3]); - main_phase = PHASE_CMD; - break; - - case C_SEEK: - seek_start(flopi[command[1] & 3]); - main_phase = PHASE_CMD; - break; - - case C_SENSE_DRIVE_STATUS: { - floppy_info &fi = flopi[command[1] & 3]; - main_phase = PHASE_RESULT; - result[0] = 0x08; - if(fi.ready) - result[0] |= 0x20; - if(fi.dev) - result[0] |= - (fi.dev->wpt_r() ? 0x40 : 0x00) | - (fi.dev->trk00_r() ? 0x00 : 0x10) | - (fi.dev->ss_r() ? 0x04 : 0x00) | - (command[1] & 3); - logerror("%s: command sense drive status (%02x)\n", tag(), result[0]); - result_pos = 1; - break; - } - - case C_SENSE_INTERRUPT_STATUS: { - main_phase = PHASE_RESULT; - - int fid; - for(fid=0; fid<4 && flopi[fid].irq == floppy_info::IRQ_NONE; fid++); - if(fid == 4) { - st0 = ST0_UNK; - result[0] = st0; - result_pos = 1; - logerror("%s: command sense interrupt status (%02x)\n", tag(), result[0]); - break; - } - floppy_info &fi = flopi[fid]; - if(fi.irq == floppy_info::IRQ_POLLED) { - // Documentation is somewhat contradictory w.r.t polling - // and irq. PC bios, especially 5150, requires that only - // one irq happens. That's also wait the ns82077a doc - // says it does. OTOH, a number of docs says you need to - // call SIS 4 times, once per drive... - // - // There's also the interaction with the seek irq. The - // somewhat borderline tf20 code seems to think that - // essentially ignoring the polling irq should work. - // - // So at that point the best bet seems to drop the - // "polled" irq as soon as a SIS happens, and override any - // polled-in-waiting information when a seek irq happens - // for a given floppy. - - st0 = ST0_ABRT | fid; - } - fi.irq = floppy_info::IRQ_NONE; - - polled_irq = false; - - result[0] = st0; - result[1] = fi.pcn; - logerror("%s: command sense interrupt status (fid=%d %02x %02x)\n", tag(), fid, result[0], result[1]); - result_pos = 2; - - check_irq(); - break; - } - - case C_SPECIFY: - logerror("%s: command specify %02x %02x\n", - tag(), - command[1], command[2]); - spec = (command[1] << 8) | command[2]; - main_phase = PHASE_CMD; - break; - - case C_WRITE_DATA: - write_data_start(flopi[command[1] & 3]); - break; - - default: - fprintf(stderr, "start command %d\n", cmd); - exit(1); - } -} - -void upd765_family_device::command_end(floppy_info &fi, bool data_completion) -{ - logerror("%s: command done (%s) -", tag(), data_completion ? "data" : "seek"); - for(int i=0; i != result_pos; i++) - logerror(" %02x", result[i]); - logerror("\n"); - fi.main_state = fi.sub_state = IDLE; - if(data_completion) - data_irq = true; - else - fi.irq = floppy_info::IRQ_SEEK; - check_irq(); -} - -void upd765_family_device::recalibrate_start(floppy_info &fi) -{ - logerror("%s: command recalibrate\n", tag()); - fi.main_state = RECALIBRATE; - fi.sub_state = SEEK_WAIT_STEP_TIME_DONE; - fi.dir = 1; - fi.counter = 77; - seek_continue(fi); -} - -void upd765_family_device::seek_start(floppy_info &fi) -{ - logerror("%s: command %sseek %d\n", tag(), command[0] & 0x80 ? "relative " : "", command[2]); - fi.main_state = SEEK; - fi.sub_state = SEEK_WAIT_STEP_TIME_DONE; - fi.dir = fi.pcn > command[2] ? 1 : 0; - seek_continue(fi); -} - -void upd765_family_device::delay_cycles(emu_timer *tm, int cycles) -{ - tm->adjust(attotime::from_double(double(cycles)/cur_rate)); -} - -void upd765_family_device::seek_continue(floppy_info &fi) -{ - for(;;) { - switch(fi.sub_state) { - case SEEK_MOVE: - if(fi.dev) { - fi.dev->dir_w(fi.dir); - fi.dev->stp_w(0); - } - fi.sub_state = SEEK_WAIT_STEP_SIGNAL_TIME; - fi.tm->adjust(attotime::from_nsec(2500)); - return; - - case SEEK_WAIT_STEP_SIGNAL_TIME: - return; - - case SEEK_WAIT_STEP_SIGNAL_TIME_DONE: - if(fi.dev) - fi.dev->stp_w(1); - - if(fi.main_state == SEEK) { - if(fi.pcn > command[2]) - fi.pcn--; - else - fi.pcn++; - } - fi.sub_state = SEEK_WAIT_STEP_TIME; - delay_cycles(fi.tm, 500*(16-(spec >> 12))); - return; - - case SEEK_WAIT_STEP_TIME: - return; - - case SEEK_WAIT_STEP_TIME_DONE: { - bool done = false; - switch(fi.main_state) { - case RECALIBRATE: - fi.counter--; - done = !fi.dev || !fi.dev->trk00_r(); - if(done) - fi.pcn = 0; - else if(!fi.counter) { - st0 = ST0_FAIL|ST0_SE|ST0_EC; - command_end(fi, false); - return; - } - break; - case SEEK: - done = fi.pcn == command[2]; - break; - } - if(done) { - st0 = ST0_SE; - command_end(fi, false); - return; - } - fi.sub_state = SEEK_MOVE; - break; - } - } - } -} - -void upd765_family_device::read_data_start(floppy_info &fi) -{ - fi.main_state = READ_DATA; - fi.sub_state = HEAD_LOAD_DONE; - mfm = command[0] & 0x40; - - logerror("%s: command read%s data%s%s%s%s cmd=%02x sel=%x chrn=(%d, %d, %d, %d) eot=%02x gpl=%02x dtl=%02x rate=%d\n", - tag(), - command[0] & 0x08 ? " deleted" : "", - command[0] & 0x80 ? " mt" : "", - command[0] & 0x40 ? " mfm" : "", - command[0] & 0x20 ? " sk" : "", - fifocfg & 0x40 ? " seek" : "", - command[0], - command[1], - command[2], - command[3], - command[4], - 128 << (command[5] & 7), - command[6], - command[7], - command[8], - cur_rate); - - st0 = command[1] & 7; - st1 = ST1_MA; - st2 = 0x00; - - if(fi.dev) - fi.dev->ss_w(command[1] & 4 ? 1 : 0); - read_data_continue(fi); -} - -void upd765_family_device::read_data_continue(floppy_info &fi) -{ - for(;;) { - switch(fi.sub_state) { - case HEAD_LOAD_DONE: - if(fi.pcn == command[2] || !(fifocfg & 0x40)) { - fi.sub_state = SEEK_DONE; - break; - } - st0 |= ST0_SE; - if(fi.dev) { - fi.dev->dir_w(fi.pcn > command[2] ? 1 : 0); - fi.dev->stp_w(0); - } - fi.sub_state = SEEK_WAIT_STEP_SIGNAL_TIME; - fi.tm->adjust(attotime::from_nsec(2500)); - return; - - case SEEK_WAIT_STEP_SIGNAL_TIME: - return; - - case SEEK_WAIT_STEP_SIGNAL_TIME_DONE: - if(fi.dev) - fi.dev->stp_w(1); - - fi.sub_state = SEEK_WAIT_STEP_TIME; - delay_cycles(fi.tm, 500*(16-(spec >> 12))); - return; - - case SEEK_WAIT_STEP_TIME: - return; - - case SEEK_WAIT_STEP_TIME_DONE: - if(fi.pcn > command[2]) - fi.pcn--; - else - fi.pcn++; - fi.sub_state = HEAD_LOAD_DONE; - break; - - case SEEK_DONE: - fi.counter = 0; - fi.sub_state = SCAN_ID; - live_start(fi, SEARCH_ADDRESS_MARK_HEADER); - return; - - case SCAN_ID: - if(cur_live.crc) { - st0 |= ST0_FAIL; - st1 |= ST1_DE|ST1_ND; - fi.sub_state = COMMAND_DONE; - break; - } - st1 &= ~ST1_MA; - if(!sector_matches()) { - if(cur_live.idbuf[0] != command[2]) { - if(cur_live.idbuf[0] == 0xff) - st2 |= ST2_WC|ST2_BC; - else - st2 |= ST2_WC; - st0 |= ST0_FAIL; - fi.sub_state = COMMAND_DONE; - break; - } - live_start(fi, SEARCH_ADDRESS_MARK_HEADER); - return; - } - logerror("%s: reading sector %02x %02x %02x %02x\n", - tag(), - cur_live.idbuf[0], - cur_live.idbuf[1], - cur_live.idbuf[2], - cur_live.idbuf[3]); - sector_size = calc_sector_size(cur_live.idbuf[3]); - fifo_expect(sector_size, false); - fi.sub_state = SECTOR_READ; - live_start(fi, SEARCH_ADDRESS_MARK_DATA); - return; - - case SCAN_ID_FAILED: - st0 |= ST0_FAIL; - st1 |= ST1_ND; - fi.sub_state = COMMAND_DONE; - break; - - case SECTOR_READ: { - if(st2 & ST2_MD) { - st0 |= ST0_FAIL; - fi.sub_state = COMMAND_DONE; - break; - } - if(cur_live.crc) { - st0 |= ST0_FAIL; - st1 |= ST1_DE; - st2 |= ST2_CM; - fi.sub_state = COMMAND_DONE; - break; - } - bool done = tc_done; - command[4]++; - if(command[4] > command[6]) { - command[4] = 1; - if(command[0] & 0x80) { - command[3] = command[3] ^ 1; - if(fi.dev) - fi.dev->ss_w(command[3] & 1); - } - if(!(command[0] & 0x80) || !(command[3] & 1)) { - command[2]++; - if(!tc_done) { - st0 |= ST0_FAIL; - st1 |= ST1_EN; - } - done = true; - } - } - if(!done) { - fi.sub_state = SEEK_DONE; - break; - } - fi.sub_state = COMMAND_DONE; - break; - } - - case COMMAND_DONE: - main_phase = PHASE_RESULT; - result[0] = st0; - result[1] = st1; - result[2] = st2; - result[3] = command[2]; - result[4] = command[3]; - result[5] = command[4]; - result[6] = command[5]; - result_pos = 7; - command_end(fi, true); - return; - - default: - logerror("%s: read sector unknown sub-state %d\n", ttsn().cstr(), fi.sub_state); - return; - } - } -} - -void upd765_family_device::write_data_start(floppy_info &fi) -{ - fi.main_state = WRITE_DATA; - fi.sub_state = HEAD_LOAD_DONE; - mfm = command[0] & 0x40; - logerror("%s: command write%s data%s%s cmd=%02x sel=%x chrn=(%d, %d, %d, %d) eot=%02x gpl=%02x dtl=%02x rate=%d\n", - tag(), - command[0] & 0x08 ? " deleted" : "", - command[0] & 0x80 ? " mt" : "", - command[0] & 0x40 ? " mfm" : "", - command[0], - command[1], - command[2], - command[3], - command[4], - 128 << (command[5] & 7), - command[6], - command[7], - command[8], - cur_rate); - - if(fi.dev) - fi.dev->ss_w(command[1] & 4 ? 1 : 0); - - st0 = command[1] & 7; - st1 = ST1_MA; - st2 = 0x00; - - write_data_continue(fi); -} - -void upd765_family_device::write_data_continue(floppy_info &fi) -{ - for(;;) { - switch(fi.sub_state) { - case HEAD_LOAD_DONE: - fi.counter = 0; - fi.sub_state = SCAN_ID; - live_start(fi, SEARCH_ADDRESS_MARK_HEADER); - return; - - case SCAN_ID: - if(!sector_matches()) { - live_start(fi, SEARCH_ADDRESS_MARK_HEADER); - return; - } - if(cur_live.crc) { - st0 |= ST0_FAIL; - st1 |= ST1_DE|ST1_ND; - fi.sub_state = COMMAND_DONE; - break; - } - st1 &= ~ST1_MA; - sector_size = calc_sector_size(cur_live.idbuf[3]); - fifo_expect(sector_size, true); - fi.sub_state = SECTOR_WRITTEN; - live_start(fi, WRITE_SECTOR_SKIP_GAP2); - return; - - case SCAN_ID_FAILED: - st0 |= ST0_FAIL; - st1 |= ST1_ND; - fi.sub_state = COMMAND_DONE; - break; - - case SECTOR_WRITTEN: { - bool done = tc_done; - command[4]++; - if(command[4] > command[6]) { - command[4] = 1; - if(command[0] & 0x80) { - command[3] = command[3] ^ 1; - if(fi.dev) - fi.dev->ss_w(command[3] & 1); - } - if(!(command[0] & 0x80) || !(command[3] & 1)) { - command[2]++; - if(!tc_done) { - st0 |= ST0_FAIL; - st1 |= ST1_EN; - } - done = true; - } - } - if(!done) { - fi.sub_state = HEAD_LOAD_DONE; - break; - } - fi.sub_state = COMMAND_DONE; - break; - } - - case COMMAND_DONE: - main_phase = PHASE_RESULT; - result[0] = st0; - result[1] = st1; - result[2] = st2; - result[3] = command[2]; - result[4] = command[3]; - result[5] = command[4]; - result[6] = command[5]; - result_pos = 7; - command_end(fi, true); - return; - - default: - logerror("%s: write sector unknown sub-state %d\n", ttsn().cstr(), fi.sub_state); - return; - } - } -} - -void upd765_family_device::read_track_start(floppy_info &fi) -{ - fi.main_state = READ_TRACK; - fi.sub_state = HEAD_LOAD_DONE; - mfm = command[0] & 0x40; - - logerror("%s: command read track%s cmd=%02x sel=%x chrn=(%d, %d, %d, %d) eot=%02x gpl=%02x dtl=%02x rate=%d\n", - tag(), - command[0] & 0x40 ? " mfm" : "", - command[0], - command[1], - command[2], - command[3], - command[4], - 128 << (command[5] & 7), - command[6], - command[7], - command[8], - cur_rate); - - if(fi.dev) - fi.dev->ss_w(command[1] & 4 ? 1 : 0); - read_track_continue(fi); -} - -void upd765_family_device::read_track_continue(floppy_info &fi) -{ - for(;;) { - switch(fi.sub_state) { - case HEAD_LOAD_DONE: - if(fi.pcn == command[2] || !(fifocfg & 0x40)) { - fi.sub_state = SEEK_DONE; - break; - } - if(fi.dev) { - fi.dev->dir_w(fi.pcn > command[2] ? 1 : 0); - fi.dev->stp_w(0); - } - fi.sub_state = SEEK_WAIT_STEP_SIGNAL_TIME; - fi.tm->adjust(attotime::from_nsec(2500)); - return; - - case SEEK_WAIT_STEP_SIGNAL_TIME: - return; - - case SEEK_WAIT_STEP_SIGNAL_TIME_DONE: - if(fi.dev) - fi.dev->stp_w(1); - - fi.sub_state = SEEK_WAIT_STEP_TIME; - delay_cycles(fi.tm, 500*(16-(spec >> 12))); - return; - - case SEEK_WAIT_STEP_TIME: - return; - - case SEEK_WAIT_STEP_TIME_DONE: - if(fi.pcn > command[2]) - fi.pcn--; - else - fi.pcn++; - fi.sub_state = HEAD_LOAD_DONE; - break; - - case SEEK_DONE: - fi.counter = 0; - fi.sub_state = SCAN_ID; - live_start(fi, SEARCH_ADDRESS_MARK_HEADER); - return; - - case SCAN_ID: - if(cur_live.crc) { - fprintf(stderr, "Header CRC error\n"); - live_start(fi, SEARCH_ADDRESS_MARK_HEADER); - return; - } - sector_size = calc_sector_size(cur_live.idbuf[3]); - fifo_expect(sector_size, false); - fi.sub_state = SECTOR_READ; - live_start(fi, SEARCH_ADDRESS_MARK_DATA); - return; - - case SCAN_ID_FAILED: - fprintf(stderr, "RNF\n"); - // command_end(fi, true, 1); - return; - - case SECTOR_READ: - if(cur_live.crc) { - fprintf(stderr, "CRC error\n"); - } - if(command[4] < command[6]) { - command[4]++; - fi.sub_state = HEAD_LOAD_DONE; - break; - } - - main_phase = PHASE_RESULT; - result[0] = 0x40 | (fi.dev->ss_r() << 2) | fi.id; - result[1] = 0; - result[2] = 0; - result[3] = command[2]; - result[4] = command[3]; - result[5] = command[4]; - result[6] = command[5]; - result_pos = 7; - // command_end(fi, true, 0); - return; - - default: - logerror("%s: read track unknown sub-state %d\n", ttsn().cstr(), fi.sub_state); - return; - } - } -} - -int upd765_family_device::calc_sector_size(UINT8 size) -{ - return size > 7 ? 16384 : 128 << size; -} - -void upd765_family_device::format_track_start(floppy_info &fi) -{ - fi.main_state = FORMAT_TRACK; - fi.sub_state = HEAD_LOAD_DONE; - mfm = command[0] & 0x40; - - logerror("%s: command format track %s h=%02x n=%02x sc=%02x gpl=%02x d=%02x\n", - tag(), - command[0] & 0x40 ? "mfm" : "fm", - command[1], command[2], command[3], command[4], command[5]); - - if(fi.dev) - fi.dev->ss_w(command[1] & 4 ? 1 : 0); - sector_size = calc_sector_size(command[2]); - - format_track_continue(fi); -} - -void upd765_family_device::format_track_continue(floppy_info &fi) -{ - for(;;) { - switch(fi.sub_state) { - case HEAD_LOAD_DONE: - fi.sub_state = WAIT_INDEX; - break; - - case WAIT_INDEX: - return; - - case WAIT_INDEX_DONE: - logerror("%s: index found, writing track\n", tag()); - fi.sub_state = TRACK_DONE; - cur_live.pll.start_writing(machine().time()); - live_start(fi, WRITE_TRACK_PRE_SECTORS); - return; - - case TRACK_DONE: - main_phase = PHASE_RESULT; - result[0] = (fi.dev->ss_r() << 2) | fi.id; - result[1] = 0; - result[2] = 0; - result[3] = 0; - result[4] = 0; - result[5] = 0; - result[6] = 0; - result_pos = 7; - command_end(fi, true); - return; - - default: - logerror("%s: format track unknown sub-state %d\n", ttsn().cstr(), fi.sub_state); - return; - } - } -} - -void upd765_family_device::read_id_start(floppy_info &fi) -{ - fi.main_state = READ_ID; - fi.sub_state = HEAD_LOAD_DONE; - mfm = command[0] & 0x40; - - logerror("%s: command read id%s, rate=%d\n", - tag(), - command[0] & 0x40 ? " mfm" : "", - cur_rate); - - if(fi.dev) - fi.dev->ss_w(command[1] & 4 ? 1 : 0); - - st0 = command[1] & 7; - st1 = 0x00; - st2 = 0x00; - - for(int i=0; i<4; i++) - cur_live.idbuf[i] = 0x00; - - read_id_continue(fi); -} - -void upd765_family_device::read_id_continue(floppy_info &fi) -{ - for(;;) { - switch(fi.sub_state) { - case HEAD_LOAD_DONE: - fi.counter = 0; - fi.sub_state = SCAN_ID; - live_start(fi, SEARCH_ADDRESS_MARK_HEADER); - return; - - case SCAN_ID: - if(cur_live.crc) { - st0 |= ST0_FAIL; - st1 |= ST1_MA|ST1_DE|ST1_ND; - } - fi.sub_state = COMMAND_DONE; - break; - - case SCAN_ID_FAILED: - st0 |= ST0_FAIL; - st1 |= ST1_ND|ST1_MA; - fi.sub_state = COMMAND_DONE; - break; - - case COMMAND_DONE: - main_phase = PHASE_RESULT; - result[0] = st0; - result[1] = st1; - result[2] = st2; - result[3] = cur_live.idbuf[0]; - result[4] = cur_live.idbuf[1]; - result[5] = cur_live.idbuf[2]; - result[6] = cur_live.idbuf[3]; - result_pos = 7; - command_end(fi, true); - return; - - default: - logerror("%s: read id unknown sub-state %d\n", ttsn().cstr(), fi.sub_state); - return; - } - } -} - -void upd765_family_device::check_irq() -{ - bool old_irq = cur_irq; - cur_irq = data_irq || polled_irq || internal_drq; - for(int i=0; i<4; i++) - cur_irq = cur_irq || flopi[i].irq == floppy_info::IRQ_SEEK; - cur_irq = cur_irq && (dor & 4) && (dor & 8); - if(cur_irq != old_irq && !intrq_cb.isnull()) { - logerror("%s: irq = %d\n", tag(), cur_irq); - intrq_cb(cur_irq); - } -} - -bool upd765_family_device::get_irq() const -{ - return cur_irq; -} - -astring upd765_family_device::tts(attotime t) -{ - char buf[256]; - const char *sign = ""; - if(t.seconds < 0) { - t = attotime::zero-t; - sign = "-"; - } - int nsec = t.attoseconds / ATTOSECONDS_PER_NANOSECOND; - sprintf(buf, "%s%04d.%03d,%03d,%03d", sign, int(t.seconds), nsec/1000000, (nsec/1000)%1000, nsec % 1000); - return buf; -} - -astring upd765_family_device::ttsn() -{ - return tts(machine().time()); -} - -void upd765_family_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) -{ - if(id == TIMER_DRIVE_READY_POLLING) { - run_drive_ready_polling(); - return; - } - - live_sync(); - - floppy_info &fi = flopi[id]; - switch(fi.sub_state) { - case SEEK_WAIT_STEP_SIGNAL_TIME: - fi.sub_state = SEEK_WAIT_STEP_SIGNAL_TIME_DONE; - break; - case SEEK_WAIT_STEP_TIME: - fi.sub_state = SEEK_WAIT_STEP_TIME_DONE; - break; - } - - general_continue(fi); -} - -void upd765_family_device::run_drive_ready_polling() -{ - if(main_phase != PHASE_CMD || (fifocfg & FIF_POLL)) - return; - - bool changed = false; - for(int fid=0; fid<4; fid++) { - bool ready = get_ready(fid); - if(ready != flopi[fid].ready) { - logerror("%s: polled %d : %d -> %d\n", tag(), fid, flopi[fid].ready, ready); - flopi[fid].ready = ready; - if(flopi[fid].irq == floppy_info::IRQ_NONE) { - flopi[fid].irq = floppy_info::IRQ_POLLED; - polled_irq = true; - changed = true; - } - } - } - if(changed) - check_irq(); -} - -void upd765_family_device::index_callback(floppy_image_device *floppy, int state) -{ - for(int fid=0; fid<4; fid++) { - floppy_info &fi = flopi[fid]; - if(fi.dev != floppy) - continue; - - if(fi.live) - live_sync(); - fi.index = state; - - if(!state) { - general_continue(fi); - continue; - } - - switch(fi.sub_state) { - case IDLE: - case SEEK_MOVE: - case SEEK_WAIT_STEP_SIGNAL_TIME: - case SEEK_WAIT_STEP_SIGNAL_TIME_DONE: - case SEEK_WAIT_STEP_TIME: - case SEEK_WAIT_STEP_TIME_DONE: - case HEAD_LOAD_DONE: - case SCAN_ID_FAILED: - case SECTOR_READ: - break; - - case WAIT_INDEX: - fi.sub_state = WAIT_INDEX_DONE; - break; - - case SCAN_ID: - fi.counter++; - if(fi.counter == 2) { - fi.sub_state = SCAN_ID_FAILED; - live_abort(); - } - break; - - case TRACK_DONE: - live_abort(); - break; - - default: - logerror("%s: Index pulse on unknown sub-state %d\n", ttsn().cstr(), fi.sub_state); - break; - } - - general_continue(fi); - } -} - - -void upd765_family_device::general_continue(floppy_info &fi) -{ - if(fi.live && cur_live.state != IDLE) { - live_run(); - if(cur_live.state != IDLE) - return; - } - - switch(fi.main_state) { - case IDLE: - break; - - case RECALIBRATE: - case SEEK: - seek_continue(fi); - break; - - case READ_DATA: - read_data_continue(fi); - break; - - case WRITE_DATA: - write_data_continue(fi); - break; - - case READ_TRACK: - read_track_continue(fi); - break; - - case FORMAT_TRACK: - format_track_continue(fi); - break; - - case READ_ID: - read_id_continue(fi); - break; - - default: - logerror("%s: general_continue on unknown main-state %d\n", ttsn().cstr(), fi.main_state); - break; - } -} - -bool upd765_family_device::read_one_bit(attotime limit) -{ - int bit = cur_live.pll.get_next_bit(cur_live.tm, cur_live.fi->dev, limit); - if(bit < 0) - return true; - cur_live.shift_reg = (cur_live.shift_reg << 1) | bit; - cur_live.bit_counter++; - if(cur_live.data_separator_phase) { - cur_live.data_reg = (cur_live.data_reg << 1) | bit; - if((cur_live.crc ^ (bit ? 0x8000 : 0x0000)) & 0x8000) - cur_live.crc = (cur_live.crc << 1) ^ 0x1021; - else - cur_live.crc = cur_live.crc << 1; - } - cur_live.data_separator_phase = !cur_live.data_separator_phase; - return false; -} - -bool upd765_family_device::write_one_bit(attotime limit) -{ - bool bit = cur_live.shift_reg & 0x8000; - if(cur_live.pll.write_next_bit(bit, cur_live.tm, cur_live.fi->dev, limit)) - return true; - if(cur_live.bit_counter & 1) { - if((cur_live.crc ^ (bit ? 0x8000 : 0x0000)) & 0x8000) - cur_live.crc = (cur_live.crc << 1) ^ 0x1021; - else - cur_live.crc = cur_live.crc << 1; - } - cur_live.shift_reg = cur_live.shift_reg << 1; - cur_live.bit_counter--; - return false; -} - -void upd765_family_device::live_write_raw(UINT16 raw) -{ - // logerror("write %04x %04x\n", raw, cur_live.crc); - cur_live.shift_reg = raw; - cur_live.data_bit_context = raw & 1; -} - -void upd765_family_device::live_write_mfm(UINT8 mfm) -{ - bool context = cur_live.data_bit_context; - UINT16 raw = 0; - for(int i=0; i<8; i++) { - bool bit = mfm & (0x80 >> i); - if(!(bit || context)) - raw |= 0x8000 >> (2*i); - if(bit) - raw |= 0x4000 >> (2*i); - context = bit; - } - cur_live.data_reg = mfm; - cur_live.shift_reg = raw; - cur_live.data_bit_context = context; - // logerror("write %02x %04x %04x\n", mfm, cur_live.crc, raw); -} - -void upd765_family_device::live_write_fm(UINT8 fm) -{ - UINT16 raw = 0xaaaa; - for(int i=0; i<8; i++) - if(fm & (0x80 >> i)) - raw |= 0x4000 >> (2*i); - cur_live.data_reg = fm; - cur_live.shift_reg = raw; - cur_live.data_bit_context = fm & 1; - // logerror("write %02x %04x %04x\n", fm, cur_live.crc, raw); -} - -bool upd765_family_device::sector_matches() const -{ - if(0) - logerror("%s: matching %02x %02x %02x %02x - %02x %02x %02x %02x\n", tag(), - cur_live.idbuf[0], cur_live.idbuf[1], cur_live.idbuf[2], cur_live.idbuf[3], - command[2], command[3], command[4], command[5]); - return - cur_live.idbuf[0] == command[2] && - cur_live.idbuf[1] == command[3] && - cur_live.idbuf[2] == command[4] && - cur_live.idbuf[3] == command[5]; -} - -void upd765_family_device::pll_t::set_clock(attotime _period) -{ - period = _period; - period_adjust_base = period * 0.05; - min_period = period * 0.75; - max_period = period * 1.25; -} - -void upd765_family_device::pll_t::reset(attotime when) -{ - ctime = when; - phase_adjust = attotime::zero; - freq_hist = 0; - write_position = 0; - write_start_time = attotime::never; -} - -void upd765_family_device::pll_t::start_writing(attotime tm) -{ - write_start_time = tm; - write_position = 0; -} - -void upd765_family_device::pll_t::stop_writing(floppy_image_device *floppy, attotime tm) -{ - commit(floppy, tm); - write_start_time = attotime::never; -} - -void upd765_family_device::pll_t::commit(floppy_image_device *floppy, attotime tm) -{ - if(write_start_time.is_never() || tm == write_start_time) - return; - - if(floppy) - floppy->write_flux(write_start_time, tm, write_position, write_buffer); - write_start_time = tm; - write_position = 0; -} - -int upd765_family_device::pll_t::get_next_bit(attotime &tm, floppy_image_device *floppy, attotime limit) -{ - attotime edge = floppy ? floppy->get_next_transition(ctime) : attotime::never; - - attotime next = ctime + period + phase_adjust; - -#if 0 - if(!edge.is_never()) - fprintf(stderr, "ctime=%s, transition_time=%s, next=%s, pha=%s\n", tts(ctime).cstr(), tts(edge).cstr(), tts(next).cstr(), tts(phase_adjust).cstr()); -#endif - - if(next > limit) - return -1; - - ctime = next; - tm = next; - - if(edge.is_never() || edge >= next) { - // No transition in the window means 0 and pll in free run mode - phase_adjust = attotime::zero; - return 0; - } - - // Transition in the window means 1, and the pll is adjusted - - attotime delta = edge - (next - period/2); - - if(delta.seconds < 0) - phase_adjust = attotime::zero - ((attotime::zero - delta)*65)/100; - else - phase_adjust = (delta*65)/100; - - if(delta < attotime::zero) { - if(freq_hist < 0) - freq_hist--; - else - freq_hist = -1; - } else if(delta > attotime::zero) { - if(freq_hist > 0) - freq_hist++; - else - freq_hist = 1; - } else - freq_hist = 0; - - if(freq_hist) { - int afh = freq_hist < 0 ? -freq_hist : freq_hist; - if(afh > 1) { - attotime aper = attotime::from_double(period_adjust_base.as_double()*delta.as_double()/period.as_double()); - period += aper; - - if(period < min_period) - period = min_period; - else if(period > max_period) - period = max_period; - } - } - - return 1; -} - -bool upd765_family_device::pll_t::write_next_bit(bool bit, attotime &tm, floppy_image_device *floppy, attotime limit) -{ - if(write_start_time.is_never()) { - write_start_time = ctime; - write_position = 0; - } - - attotime etime = ctime + period; - if(etime > limit) - return true; - - if(bit && write_position < ARRAY_LENGTH(write_buffer)) - write_buffer[write_position++] = ctime + period/2; - - tm = etime; - ctime = etime; - return false; -} - -upd765a_device::upd765a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : upd765_family_device(mconfig, UPD765A, "UPD765A", tag, owner, clock) -{ - m_shortname = "upd765a"; - dor_reset = 0x0c; -} - -upd765b_device::upd765b_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : upd765_family_device(mconfig, UPD765B, "UPD765B", tag, owner, clock) -{ - m_shortname = "upd765b"; - dor_reset = 0x0c; -} - -i8272a_device::i8272a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : upd765_family_device(mconfig, I8272A, "I8272A", tag, owner, clock) -{ - m_shortname = "i8272a"; - dor_reset = 0x0c; -} - -upd72065_device::upd72065_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : upd765_family_device(mconfig, UPD72065, "UPD72065", tag, owner, clock) -{ - m_shortname = "upd72065"; - dor_reset = 0x0c; -} - -smc37c78_device::smc37c78_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : upd765_family_device(mconfig, SMC37C78, "SMC37C78", tag, owner, clock) -{ - m_shortname = "smc37c78"; - ready_connected = false; - select_connected = true; -} - -n82077aa_device::n82077aa_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : upd765_family_device(mconfig, N82077AA, "N82077AA", tag, owner, clock) -{ - m_shortname = "n82077aa"; - ready_connected = false; - select_connected = true; -} - -pc_fdc_superio_device::pc_fdc_superio_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : upd765_family_device(mconfig, PC_FDC_SUPERIO, "PC FDC SUPERIO", tag, owner, clock) -{ - m_shortname = "pc_fdc_superio"; - ready_polled = false; - ready_connected = false; - select_connected = true; -} diff --git a/src/mess/machine/upd765.h b/src/mess/machine/upd765.h deleted file mode 100644 index 22f00f18394..00000000000 --- a/src/mess/machine/upd765.h +++ /dev/null @@ -1,441 +0,0 @@ -#ifndef __UPD765_F_H__ -#define __UPD765_F_H__ - -#include "emu.h" -#include "imagedev/floppy.h" - -/* - * ready = true if the ready line is physically connected to the floppy drive - * select = true if the fdc controls the floppy drive selection - * mode = MODE_AT, MODE_PS2 or MODE_M30 for the fdcs that have reset-time selection - */ - -#define MCFG_UPD765A_ADD(_tag, _ready, _select) \ - MCFG_DEVICE_ADD(_tag, UPD765A, 0) \ - downcast(device)->set_ready_line_connected(_ready); \ - downcast(device)->set_select_lines_connected(_select); - -#define MCFG_UPD765B_ADD(_tag, _ready, _select) \ - MCFG_DEVICE_ADD(_tag, UPD765B, 0) \ - downcast(device)->set_ready_line_connected(_ready); \ - downcast(device)->set_select_lines_connected(_select); - -#define MCFG_I8272A_ADD(_tag, _ready) \ - MCFG_DEVICE_ADD(_tag, I8272A, 0) \ - downcast(device)->set_ready_line_connected(_ready); - -#define MCFG_UPD72065_ADD(_tag, _ready, _select) \ - MCFG_DEVICE_ADD(_tag, UPD72065, 0) \ - downcast(device)->set_ready_line_connected(_ready); \ - downcast(device)->set_select_lines_connected(_select); - -#define MCFG_SMC37C78_ADD(_tag) \ - MCFG_DEVICE_ADD(_tag, SMC37C78, 0) - -#define MCFG_N82077AA_ADD(_tag, _mode) \ - MCFG_DEVICE_ADD(_tag, N82077AA, 0) \ - downcast(device)->set_mode(_mode); - -#define MCFG_PC_FDC_SUPERIO_ADD(_tag) \ - MCFG_DEVICE_ADD(_tag, PC_FDC_SUPERIO, 0) - -/* Interface required for PC ISA wrapping */ -class pc_fdc_interface : public device_t { -public: - typedef delegate line_cb; - typedef delegate byte_read_cb; - typedef delegate byte_write_cb; - - pc_fdc_interface(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock) : device_t(mconfig, type, name, tag, owner, clock) {} - - virtual void setup_intrq_cb(line_cb cb) = 0; - virtual void setup_drq_cb(line_cb cb) = 0; - - /* Note that the address map must cover and handle the whole 0-7 - * range. The upd765, while conforming to the rest of the - * interface, is not eligible as a result. - */ - - virtual DECLARE_ADDRESS_MAP(map, 8) = 0; - - virtual UINT8 dma_r() = 0; - virtual void dma_w(UINT8 data) = 0; - - virtual void tc_w(bool val) = 0; - virtual UINT8 do_dir_r() = 0; -}; - -class upd765_family_device : public pc_fdc_interface { -public: - enum { MODE_AT, MODE_PS2, MODE_M30 }; - - upd765_family_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock); - - void setup_intrq_cb(line_cb cb); - void setup_drq_cb(line_cb cb); - - virtual DECLARE_ADDRESS_MAP(map, 8) = 0; - - DECLARE_READ8_MEMBER (sra_r); - DECLARE_READ8_MEMBER (srb_r); - DECLARE_READ8_MEMBER (dor_r); - DECLARE_WRITE8_MEMBER(dor_w); - DECLARE_READ8_MEMBER (tdr_r); - DECLARE_WRITE8_MEMBER(tdr_w); - DECLARE_READ8_MEMBER (msr_r); - DECLARE_WRITE8_MEMBER(dsr_w); - DECLARE_READ8_MEMBER (fifo_r); - DECLARE_WRITE8_MEMBER(fifo_w); - DECLARE_READ8_MEMBER (dir_r); - DECLARE_WRITE8_MEMBER(ccr_w); - - virtual UINT8 do_dir_r(); - - UINT8 dma_r(); - void dma_w(UINT8 data); - - // Same as the previous ones, but as memory-mappable members - DECLARE_READ8_MEMBER(mdma_r); - DECLARE_WRITE8_MEMBER(mdma_w); - - bool get_irq() const; - bool get_drq() const; - void tc_w(bool val); - void ready_w(bool val); - - void set_rate(int rate); // rate in bps, to be used when the fdc is externally frequency-controlled - - void set_mode(int mode); - void set_ready_line_connected(bool ready); - void set_select_lines_connected(bool select); - void set_floppy(floppy_image_device *image); - -protected: - virtual void device_start(); - virtual void device_reset(); - virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); - - enum { - TIMER_DRIVE_READY_POLLING = 4 - }; - - enum { - PHASE_CMD, PHASE_EXEC, PHASE_RESULT - }; - - enum { - MSR_DB = 0x0f, - MSR_CB = 0x10, - MSR_EXM = 0x20, - MSR_DIO = 0x40, - MSR_RQM = 0x80, - - ST0_UNIT = 0x07, - ST0_NR = 0x08, - ST0_EC = 0x10, - ST0_SE = 0x20, - ST0_FAIL = 0x40, - ST0_UNK = 0x80, - ST0_ABRT = 0xc0, - - ST1_MA = 0x01, - ST1_NW = 0x02, - ST1_ND = 0x04, - ST1_OR = 0x10, - ST1_DE = 0x20, - ST1_EN = 0x80, - - ST2_MD = 0x01, - ST2_BC = 0x02, - ST2_SN = 0x04, - ST2_SH = 0x08, - ST2_WC = 0x10, - ST2_DD = 0x20, - ST2_CM = 0x40, - - ST3_UNIT = 0x07, - ST3_TS = 0x08, - ST3_T0 = 0x10, - ST3_RY = 0x20, - ST3_WP = 0x40, - ST3_FT = 0x80, - - FIF_THR = 0x0f, - FIF_POLL = 0x10, - FIF_DIS = 0x20, - FIF_EIS = 0x40, - - SPEC_ND = 0x0001, - }; - - - enum { - // General "doing nothing" state - IDLE, - - // Main states - RECALIBRATE, - SEEK, - READ_DATA, - WRITE_DATA, - READ_TRACK, - FORMAT_TRACK, - READ_ID, - - // Sub-states - COMMAND_DONE, - - SEEK_MOVE, - SEEK_WAIT_STEP_SIGNAL_TIME, - SEEK_WAIT_STEP_SIGNAL_TIME_DONE, - SEEK_WAIT_STEP_TIME, - SEEK_WAIT_STEP_TIME_DONE, - SEEK_DONE, - - HEAD_LOAD_DONE, - - WAIT_INDEX, - WAIT_INDEX_DONE, - - SCAN_ID, - SCAN_ID_FAILED, - - SECTOR_READ, - SECTOR_WRITTEN, - TC_DONE, - - TRACK_DONE, - - // Live states - SEARCH_ADDRESS_MARK_HEADER, - READ_HEADER_BLOCK_HEADER, - READ_DATA_BLOCK_HEADER, - READ_ID_BLOCK, - SEARCH_ADDRESS_MARK_DATA, - SEARCH_ADDRESS_MARK_DATA_FAILED, - READ_SECTOR_DATA, - READ_SECTOR_DATA_BYTE, - - WRITE_SECTOR_SKIP_GAP2, - WRITE_SECTOR_SKIP_GAP2_BYTE, - WRITE_SECTOR_DATA, - WRITE_SECTOR_DATA_BYTE, - - WRITE_TRACK_PRE_SECTORS, - WRITE_TRACK_PRE_SECTORS_BYTE, - - WRITE_TRACK_SECTOR, - WRITE_TRACK_SECTOR_BYTE, - - WRITE_TRACK_POST_SECTORS, - WRITE_TRACK_POST_SECTORS_BYTE, - }; - - struct pll_t { - attotime ctime, period, min_period, max_period, period_adjust_base, phase_adjust; - - attotime write_start_time; - attotime write_buffer[32]; - int write_position; - int freq_hist; - - void set_clock(attotime period); - void reset(attotime when); - int get_next_bit(attotime &tm, floppy_image_device *floppy, attotime limit); - bool write_next_bit(bool bit, attotime &tm, floppy_image_device *floppy, attotime limit); - void start_writing(attotime tm); - void commit(floppy_image_device *floppy, attotime tm); - void stop_writing(floppy_image_device *floppy, attotime tm); - }; - - struct floppy_info { - enum { IRQ_NONE, IRQ_SEEK, IRQ_POLLED }; - emu_timer *tm; - floppy_image_device *dev; - int id; - int main_state, sub_state; - int dir, counter; - UINT8 pcn; - int irq; - bool live, index, ready; - }; - - struct live_info { - enum { PT_NONE, PT_CRC_1, PT_CRC_2 }; - - attotime tm; - int state, next_state; - floppy_info *fi; - UINT16 shift_reg; - UINT16 crc; - int bit_counter, byte_counter, previous_type; - bool data_separator_phase, data_bit_context; - UINT8 data_reg; - UINT8 idbuf[6]; - pll_t pll; - }; - - static int rates[4]; - - bool ready_connected, ready_polled, select_connected; - - bool external_ready; - - int mode; - int main_phase; - - live_info cur_live, checkpoint_live; - line_cb intrq_cb, drq_cb; - bool cur_irq, polled_irq, data_irq, drq, internal_drq, tc, tc_done, locked, mfm; - floppy_info flopi[4]; - - int fifo_pos, fifo_expected, command_pos, result_pos; - bool fifo_write; - UINT8 dor, dsr, msr, fifo[16], command[16], result[16]; - UINT8 st0, st1, st2, st3; - UINT8 fifocfg, dor_reset; - UINT8 precomp, perpmode; - UINT16 spec; - int sector_size; - int cur_rate; - - emu_timer *poll_timer; - - static astring tts(attotime t); - astring ttsn(); - - enum { - C_CONFIGURE, - C_DUMP_REG, - C_FORMAT_TRACK, - C_LOCK, - C_PERPENDICULAR, - C_READ_DATA, - C_READ_ID, - C_READ_TRACK, - C_RECALIBRATE, - C_SEEK, - C_SENSE_DRIVE_STATUS, - C_SENSE_INTERRUPT_STATUS, - C_SPECIFY, - C_WRITE_DATA, - - C_INVALID, - C_INCOMPLETE, - }; - - void delay_cycles(emu_timer *tm, int cycles); - void check_irq(); - void soft_reset(); - void fifo_expect(int size, bool write); - void fifo_push(UINT8 data, bool internal); - UINT8 fifo_pop(bool internal); - void set_drq(bool state); - bool get_ready(int fid); - - void enable_transfer(); - void disable_transfer(); - int calc_sector_size(UINT8 size); - - void run_drive_ready_polling(); - - int check_command(); - void start_command(int cmd); - void command_end(floppy_info &fi, bool data_completion); - - void recalibrate_start(floppy_info &fi); - void seek_start(floppy_info &fi); - void seek_continue(floppy_info &fi); - - void read_data_start(floppy_info &fi); - void read_data_continue(floppy_info &fi); - - void write_data_start(floppy_info &fi); - void write_data_continue(floppy_info &fi); - - void read_track_start(floppy_info &fi); - void read_track_continue(floppy_info &fi); - - void format_track_start(floppy_info &fi); - void format_track_continue(floppy_info &fi); - - void read_id_start(floppy_info &fi); - void read_id_continue(floppy_info &fi); - - void general_continue(floppy_info &fi); - void index_callback(floppy_image_device *floppy, int state); - bool sector_matches() const; - - void live_start(floppy_info &fi, int live_state); - void live_abort(); - void checkpoint(); - void rollback(); - void live_delay(int state); - void live_sync(); - void live_run(attotime limit = attotime::never); - void live_write_raw(UINT16 raw); - void live_write_fm(UINT8 fm); - void live_write_mfm(UINT8 mfm); - - bool read_one_bit(attotime limit); - bool write_one_bit(attotime limit); -}; - -class upd765a_device : public upd765_family_device { -public: - upd765a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); - - virtual DECLARE_ADDRESS_MAP(map, 8); -}; - -class upd765b_device : public upd765_family_device { -public: - upd765b_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); - - virtual DECLARE_ADDRESS_MAP(map, 8); -}; - -class i8272a_device : public upd765_family_device { -public: - i8272a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); - - virtual DECLARE_ADDRESS_MAP(map, 8); -}; - -class smc37c78_device : public upd765_family_device { -public: - smc37c78_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); - - virtual DECLARE_ADDRESS_MAP(map, 8); -}; - -class upd72065_device : public upd765_family_device { -public: - upd72065_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); - - virtual DECLARE_ADDRESS_MAP(map, 8); -}; - -class n82077aa_device : public upd765_family_device { -public: - n82077aa_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); - - virtual DECLARE_ADDRESS_MAP(map, 8); -}; - -class pc_fdc_superio_device : public upd765_family_device { -public: - pc_fdc_superio_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); - - virtual DECLARE_ADDRESS_MAP(map, 8); -}; - -extern const device_type UPD765A; -extern const device_type UPD765B; -extern const device_type I8272A; -extern const device_type UPD72065; -extern const device_type SMC37C78; -extern const device_type N82077AA; -extern const device_type PC_FDC_SUPERIO; - -#endif diff --git a/src/mess/machine/wd1772.c b/src/mess/machine/wd1772.c deleted file mode 100644 index 3b29bfcce38..00000000000 --- a/src/mess/machine/wd1772.c +++ /dev/null @@ -1,1907 +0,0 @@ -/*************************************************************************** - - Copyright Olivier Galibert - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - * Neither the name 'MAME' nor the names of its contributors may be - used to endorse or promote products derived from this software - without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR - IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT, - INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGE. - -****************************************************************************/ - -#include "wd1772.h" - -#include "debugger.h" - -const device_type FD1771x = &device_creator; -const device_type FD1793x = &device_creator; -const device_type FD1797x = &device_creator; -const device_type WD2793x = &device_creator; -const device_type WD2797x = &device_creator; -const device_type WD1770x = &device_creator; -const device_type WD1772x = &device_creator; -const device_type WD1773x = &device_creator; - -wd177x_t::wd177x_t(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock) : - device_t(mconfig, type, name, tag, owner, clock) -{ -} - -void wd177x_t::device_start() -{ - t_gen = timer_alloc(TM_GEN); - t_cmd = timer_alloc(TM_CMD); - t_track = timer_alloc(TM_TRACK); - t_sector = timer_alloc(TM_SECTOR); - dden = false; - floppy = 0; - - save_item(NAME(status)); - save_item(NAME(command)); - save_item(NAME(main_state)); - save_item(NAME(sub_state)); - save_item(NAME(track)); - save_item(NAME(sector)); - save_item(NAME(intrq_cond)); - save_item(NAME(cmd_buffer)); - save_item(NAME(track_buffer)); - save_item(NAME(sector_buffer)); - save_item(NAME(counter)); - save_item(NAME(status_type_1)); - save_item(NAME(last_dir)); -} - -void wd177x_t::device_reset() -{ - command = 0x00; - main_state = IDLE; - sub_state = IDLE; - cur_live.state = IDLE; - track = 0x00; - sector = 0x00; - status = 0x00; - data = 0x00; - cmd_buffer = track_buffer = sector_buffer = -1; - counter = 0; - status_type_1 = true; - last_dir = 1; - intrq = false; - drq = false; - hld = false; - live_abort(); -} - -void wd177x_t::set_floppy(floppy_image_device *_floppy) -{ - if(floppy == _floppy) - return; - - if(floppy) { - floppy->mon_w(1); - floppy->setup_index_pulse_cb(floppy_image_device::index_pulse_cb()); - } - - floppy = _floppy; - - if(floppy) { - if(has_motor()) - floppy->mon_w(status & S_MON ? 0 : 1); - floppy->setup_index_pulse_cb(floppy_image_device::index_pulse_cb(FUNC(wd177x_t::index_callback), this)); - } -} - -void wd177x_t::setup_intrq_cb(line_cb cb) -{ - intrq_cb = cb; -} - -void wd177x_t::setup_drq_cb(line_cb cb) -{ - drq_cb = cb; -} - -void wd177x_t::setup_hld_cb(line_cb cb) -{ - hld_cb = cb; -} - -void wd177x_t::setup_enp_cb(line_cb cb) -{ - enp_cb = cb; -} - -void wd177x_t::dden_w(bool _dden) -{ - dden = _dden; -} - -astring wd177x_t::tts(attotime t) -{ - char buf[256]; - int nsec = t.attoseconds / ATTOSECONDS_PER_NANOSECOND; - sprintf(buf, "%4d.%03d,%03d,%03d", int(t.seconds), nsec/1000000, (nsec/1000)%1000, nsec % 1000); - return buf; -} - -astring wd177x_t::ttsn() -{ - return tts(machine().time()); -} - -void wd177x_t::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) -{ - live_sync(); - - switch(id) { - case TM_GEN: do_generic(); break; - case TM_CMD: do_cmd_w(); break; - case TM_TRACK: do_track_w(); break; - case TM_SECTOR: do_sector_w(); break; - } - - general_continue(); -} - -void wd177x_t::command_end() -{ - main_state = sub_state = IDLE; - status &= ~S_BUSY; - intrq = true; - motor_timeout = 0; - if(!intrq_cb.isnull()) - intrq_cb(intrq); -} - -void wd177x_t::seek_start(int state) -{ - main_state = state; - status = (status & ~(S_CRC|S_RNF|S_SPIN)) | S_BUSY; - if(has_head_load()) { - // TODO get value from HLT callback - if (command & 8) - status |= S_HLD; - else - status &= ~S_HLD; - } - sub_state = has_motor() && !has_head_load() ? SPINUP : SPINUP_DONE; - status_type_1 = true; - seek_continue(); -} - -void wd177x_t::seek_continue() -{ - for(;;) { - switch(sub_state) { - case SPINUP: - if(!(status & S_MON)) { - spinup(); - return; - } - if(!(command & 0x08)) - status |= S_SPIN; - sub_state = SPINUP_DONE; - break; - - case SPINUP_WAIT: - return; - - case SPINUP_DONE: - if(main_state == RESTORE && floppy && !floppy->trk00_r()) - sub_state = SEEK_DONE; - - if(main_state == SEEK && track == data) - sub_state = SEEK_DONE; - - if(sub_state == SPINUP_DONE) { - counter = 0; - sub_state = SEEK_MOVE; - } - break; - - case SEEK_MOVE: - if(floppy) { - floppy->dir_w(last_dir); - floppy->stp_w(0); - floppy->stp_w(1); - } - // When stepping with update, the track register is updated before seeking. - // Important for the sam coupe format code. - if(main_state == STEP && (command & 0x10)) - track += last_dir ? -1 : 1; - counter++; - sub_state = SEEK_WAIT_STEP_TIME; - delay_cycles(t_gen, step_time(command & 3)); - return; - - case SEEK_WAIT_STEP_TIME: - return; - - case SEEK_WAIT_STEP_TIME_DONE: { - bool done = false; - switch(main_state) { - case RESTORE: - done = !floppy || !floppy->trk00_r(); - break; - case SEEK: - track += last_dir ? -1 : 1; - done = track == data; - break; - case STEP: - done = true; - break; - } - - if(done || counter == 255) { - if(main_state == RESTORE) - track = 0; - - if(command & 0x04) { - sub_state = SEEK_WAIT_STABILIZATION_TIME; - delay_cycles(t_gen, 120000); - return; - } else - sub_state = SEEK_DONE; - - } else - sub_state = SEEK_MOVE; - - break; - } - - case SEEK_WAIT_STABILIZATION_TIME: - return; - - case SEEK_WAIT_STABILIZATION_TIME_DONE: - sub_state = SEEK_DONE; - break; - - case SEEK_DONE: - if(command & 0x04) { - if(has_ready() && !is_ready()) { - status |= S_RNF; - command_end(); - return; - } - sub_state = SCAN_ID; - counter = 0; - live_start(SEARCH_ADDRESS_MARK_HEADER); - return; - } - command_end(); - return; - - case SCAN_ID: - if(cur_live.idbuf[0] != track) { - live_start(SEARCH_ADDRESS_MARK_HEADER); - return; - } - if(cur_live.crc) { - status |= S_CRC; - live_start(SEARCH_ADDRESS_MARK_HEADER); - return; - } - command_end(); - return; - - case SCAN_ID_FAILED: - status |= S_RNF; - command_end(); - return; - - default: - logerror("%s: seek unknown sub-state %d\n", ttsn().cstr(), sub_state); - return; - } - } -} - -bool wd177x_t::sector_matches() const -{ - if(cur_live.idbuf[0] != track || cur_live.idbuf[2] != sector) - return false; - if(!has_side_check() || (command & 2)) - return true; - if(command & 8) - return cur_live.idbuf[1] & 1; - else - return !(cur_live.idbuf[1] & 1); -} - -bool wd177x_t::is_ready() -{ - return (floppy && !floppy->ready_r()); -} - -void wd177x_t::read_sector_start() -{ - if(has_ready() && !is_ready()) - command_end(); - - main_state = READ_SECTOR; - status = (status & ~(S_CRC|S_LOST|S_RNF|S_WP|S_DDM)) | S_BUSY; - drop_drq(); - if (has_side_select() && floppy) - floppy->ss_w(BIT(command, 1)); - sub_state = has_motor() && !has_head_load() ? SPINUP : SPINUP_DONE; - status_type_1 = false; - read_sector_continue(); -} - -void wd177x_t::read_sector_continue() -{ - for(;;) { - switch(sub_state) { - case SPINUP: - if(!(status & S_MON)) { - spinup(); - return; - } - sub_state = SPINUP_DONE; - break; - - case SPINUP_WAIT: - return; - - case SPINUP_DONE: - if(command & 4) { - sub_state = SETTLE_WAIT; - delay_cycles(t_gen, settle_time()); - return; - } else { - sub_state = SETTLE_DONE; - break; - } - - case SETTLE_WAIT: - return; - - case SETTLE_DONE: - sub_state = SCAN_ID; - counter = 0; - live_start(SEARCH_ADDRESS_MARK_HEADER); - return; - - case SCAN_ID: - if(!sector_matches()) { - live_start(SEARCH_ADDRESS_MARK_HEADER); - return; - } - if(cur_live.crc) { - status |= S_CRC; - live_start(SEARCH_ADDRESS_MARK_HEADER); - return; - } - // TODO WD2795/7 alternate sector size - sector_size = 128 << (cur_live.idbuf[3] & 3); - sub_state = SECTOR_READ; - live_start(SEARCH_ADDRESS_MARK_DATA); - return; - - case SCAN_ID_FAILED: - status |= S_RNF; - command_end(); - return; - - case SECTOR_READ: - if(cur_live.crc) - status |= S_CRC; - - if(command & 0x10 && !(status & S_RNF)) { - sector++; - sub_state = SETTLE_DONE; - } else { - command_end(); - return; - } - break; - - default: - logerror("%s: read sector unknown sub-state %d\n", ttsn().cstr(), sub_state); - return; - } - } -} - -void wd177x_t::read_track_start() -{ - if(has_ready() && !is_ready()) - command_end(); - - main_state = READ_TRACK; - status = (status & ~(S_LOST|S_RNF)) | S_BUSY; - drop_drq(); - if (has_side_select() && floppy) - floppy->ss_w(BIT(command, 1)); - sub_state = has_motor() && !has_head_load() ? SPINUP : SPINUP_DONE; - status_type_1 = false; - read_track_continue(); -} - -void wd177x_t::read_track_continue() -{ - for(;;) { - switch(sub_state) { - case SPINUP: - if(!(status & S_MON)) { - spinup(); - return; - } - sub_state = SPINUP_DONE; - break; - - case SPINUP_WAIT: - return; - - case SPINUP_DONE: - if(command & 4) { - sub_state = SETTLE_WAIT; - delay_cycles(t_gen, settle_time()); - return; - - } else { - sub_state = SETTLE_DONE; - break; - } - - case SETTLE_WAIT: - return; - - case SETTLE_DONE: - sub_state = WAIT_INDEX; - return; - - case WAIT_INDEX: - return; - - case WAIT_INDEX_DONE: - sub_state = TRACK_DONE; - live_start(READ_TRACK_DATA); - return; - - case TRACK_DONE: - command_end(); - return; - - default: - logerror("%s: read track unknown sub-state %d\n", ttsn().cstr(), sub_state); - return; - } - } -} - -void wd177x_t::read_id_start() -{ - if(has_ready() && !is_ready()) - command_end(); - - main_state = READ_ID; - status = (status & ~(S_WP|S_DDM|S_LOST|S_RNF)) | S_BUSY; - drop_drq(); - if (has_side_select() && floppy) - floppy->ss_w(BIT(command, 1)); - sub_state = has_motor() && !has_head_load() ? SPINUP : SPINUP_DONE; - status_type_1 = false; - read_id_continue(); -} - -void wd177x_t::read_id_continue() -{ - for(;;) { - switch(sub_state) { - case SPINUP: - if(!(status & S_MON)) { - spinup(); - return; - } - sub_state = SPINUP_DONE; - break; - - case SPINUP_WAIT: - return; - - case SPINUP_DONE: - if(command & 4) { - sub_state = SETTLE_WAIT; - delay_cycles(t_gen, settle_time()); - return; - } else { - sub_state = SETTLE_DONE; - break; - } - - case SETTLE_WAIT: - return; - - case SETTLE_DONE: - sub_state = SCAN_ID; - counter = 0; - live_start(SEARCH_ADDRESS_MARK_HEADER); - return; - - case SCAN_ID: - command_end(); - return; - - case SCAN_ID_FAILED: - status |= S_RNF; - command_end(); - return; - - default: - logerror("%s: read id unknown sub-state %d\n", ttsn().cstr(), sub_state); - return; - } - } -} - -void wd177x_t::write_track_start() -{ - if(has_ready() && !is_ready()) - command_end(); - - main_state = WRITE_TRACK; - status = (status & ~(S_WP|S_DDM|S_LOST|S_RNF)) | S_BUSY; - drop_drq(); - if (has_side_select() && floppy) - floppy->ss_w(BIT(command, 1)); - sub_state = has_motor() && !has_head_load() ? SPINUP : SPINUP_DONE; - status_type_1 = false; - write_track_continue(); -} - -void wd177x_t::write_track_continue() -{ - for(;;) { - switch(sub_state) { - case SPINUP: - if(!(status & S_MON)) { - spinup(); - return; - } - sub_state = SPINUP_DONE; - break; - - case SPINUP_WAIT: - return; - - case SPINUP_DONE: - if(command & 4) { - sub_state = SETTLE_WAIT; - delay_cycles(t_gen, settle_time()); - return; - } else { - sub_state = SETTLE_DONE; - break; - } - - case SETTLE_WAIT: - return; - - case SETTLE_DONE: - set_drq(); - sub_state = DATA_LOAD_WAIT; - delay_cycles(t_gen, 768); - return; - - case DATA_LOAD_WAIT: - return; - - case DATA_LOAD_WAIT_DONE: - if(drq) { - status |= S_LOST; - command_end(); - return; - } - sub_state = WAIT_INDEX; - break; - - case WAIT_INDEX: - return; - - case WAIT_INDEX_DONE: - sub_state = TRACK_DONE; - live_start(WRITE_TRACK_DATA); - cur_live.pll.start_writing(machine().time()); - return; - - case TRACK_DONE: - command_end(); - return; - - default: - logerror("%s: write track unknown sub-state %d\n", ttsn().cstr(), sub_state); - return; - } - } -} - - -void wd177x_t::write_sector_start() -{ - if(has_ready() && !is_ready()) - command_end(); - - main_state = WRITE_SECTOR; - status = (status & ~(S_CRC|S_LOST|S_RNF|S_WP|S_DDM)) | S_BUSY; - drop_drq(); - if (has_side_select() && floppy) - floppy->ss_w(BIT(command, 1)); - sub_state = has_motor() && !has_head_load() ? SPINUP : SPINUP_DONE; - status_type_1 = false; - write_sector_continue(); -} - -void wd177x_t::write_sector_continue() -{ - for(;;) { - switch(sub_state) { - case SPINUP: - if(!(status & S_MON)) { - spinup(); - return; - } - sub_state = SPINUP_DONE; - break; - - case SPINUP_WAIT: - return; - - case SPINUP_DONE: - if(command & 4) { - sub_state = SETTLE_WAIT; - delay_cycles(t_gen, settle_time()); - return; - } else { - sub_state = SETTLE_DONE; - break; - } - - case SETTLE_WAIT: - return; - - case SETTLE_DONE: - sub_state = SCAN_ID; - counter = 0; - live_start(SEARCH_ADDRESS_MARK_HEADER); - return; - - case SCAN_ID: - if(!sector_matches()) { - live_start(SEARCH_ADDRESS_MARK_HEADER); - return; - } - if(cur_live.crc) { - status |= S_CRC; - live_start(SEARCH_ADDRESS_MARK_HEADER); - return; - } - // TODO WD2795/7 alternate sector size - sector_size = 128 << (cur_live.idbuf[3] & 3); - sub_state = SECTOR_WRITE; - live_start(WRITE_SECTOR_PRE); - return; - - case SCAN_ID_FAILED: - status |= S_RNF; - command_end(); - return; - - case SECTOR_WRITE: - if(command & 0x10) { - sector++; - sub_state = SPINUP_DONE; - } else { - command_end(); - return; - } - break; - - default: - logerror("%s: write sector unknown sub-state %d\n", ttsn().cstr(), sub_state); - return; - } - } -} - -void wd177x_t::interrupt_start() -{ - if(status & S_BUSY) { - main_state = sub_state = cur_live.state = IDLE; - cur_live.tm = attotime::never; - status &= ~S_BUSY; - drop_drq(); - motor_timeout = 0; - } - - if(!(command & 0x0f)) { - intrq_cond = 0; - } else { - intrq_cond = (intrq_cond & I_IMM) | (command & 0x07); - } - - if(intrq_cond & I_IMM) { - intrq = true; - if(!intrq_cb.isnull()) - intrq_cb(intrq); - } - - if(command & 0x03) { - logerror("%s: unhandled interrupt generation (%02x)\n", ttsn().cstr(), command); - } -} - -void wd177x_t::general_continue() -{ - if(cur_live.state != IDLE) { - live_run(); - if(cur_live.state != IDLE) - return; - } - - switch(main_state) { - case IDLE: - break; - case RESTORE: case SEEK: case STEP: - seek_continue(); - break; - case READ_SECTOR: - read_sector_continue(); - break; - case READ_TRACK: - read_track_continue(); - break; - case READ_ID: - read_id_continue(); - break; - case WRITE_TRACK: - write_track_continue(); - break; - case WRITE_SECTOR: - write_sector_continue(); - break; - default: - logerror("%s: general_continue on unknown main-state %d\n", ttsn().cstr(), main_state); - break; - } -} - -void wd177x_t::do_generic() -{ - switch(sub_state) { - case IDLE: - case SCAN_ID: - case SECTOR_READ: - break; - - case SETTLE_WAIT: - sub_state = SETTLE_DONE; - break; - - case SEEK_WAIT_STEP_TIME: - sub_state = SEEK_WAIT_STEP_TIME_DONE; - break; - - case SEEK_WAIT_STABILIZATION_TIME: - sub_state = SEEK_WAIT_STABILIZATION_TIME_DONE; - break; - - case DATA_LOAD_WAIT: - sub_state = DATA_LOAD_WAIT_DONE; - break; - - default: - if(cur_live.tm.is_never()) - logerror("%s: do_generic on unknown sub-state %d\n", ttsn().cstr(), sub_state); - break; - } -} - -void wd177x_t::do_cmd_w() -{ - // fprintf(stderr, "%s: command %02x\n", ttsn().cstr(), cmd_buffer); - - // Only available command when busy is interrupt - if(main_state != IDLE && (cmd_buffer & 0xf0) != 0xd0) { - cmd_buffer = -1; - return; - } - command = cmd_buffer; - cmd_buffer = -1; - - switch(command & 0xf0) { - case 0x00: logerror("wd1772: restore\n"); last_dir = 1; seek_start(RESTORE); break; - case 0x10: logerror("wd1772: seek %d\n", data); last_dir = data > track ? 0 : 1; seek_start(SEEK); break; - case 0x20: case 0x30: logerror("wd1772: step\n"); seek_start(STEP); break; - case 0x40: case 0x50: logerror("wd1772: step +\n"); last_dir = 0; seek_start(STEP); break; - case 0x60: case 0x70: logerror("wd1772: step -\n"); last_dir = 1; seek_start(STEP); break; - case 0x80: case 0x90: logerror("wd1772: read sector%s %d, %d\n", command & 0x10 ? " multiple" : "", track, sector); read_sector_start(); break; - case 0xa0: case 0xb0: logerror("wd1772: write sector%s %d, %d\n", command & 0x10 ? " multiple" : "", track, sector); write_sector_start(); break; - case 0xc0: logerror("wd1772: read id\n"); read_id_start(); break; - case 0xd0: logerror("wd1772: interrupt\n"); interrupt_start(); break; - case 0xe0: logerror("wd1772: read track %d\n", track); read_track_start(); break; - case 0xf0: logerror("wd1772: write track %d\n", track); write_track_start(); break; - } -} - -void wd177x_t::cmd_w(UINT8 val) -{ - logerror("wd1772 cmd: %02x\n", val); - - if(intrq && !(intrq_cond & I_IMM)) { - intrq = false; - if(!intrq_cb.isnull()) - intrq_cb(intrq); - } - - // No more than one write in flight - if(cmd_buffer != -1) - return; - - cmd_buffer = val; - - delay_cycles(t_cmd, dden ? 384 : 184); -} - -UINT8 wd177x_t::status_r() -{ - if(intrq && !(intrq_cond & I_IMM)) { - intrq = false; - if(!intrq_cb.isnull()) - intrq_cb(intrq); - } - - if(main_state == IDLE || status_type_1) { - if(floppy && floppy->idx_r()) - status |= S_IP; - else - status &= ~S_IP; - } else { - if(drq) - status |= S_DRQ; - else - status &= ~S_DRQ; - } - - if(status_type_1) { - status &= ~(S_TR00|S_WP); - if(floppy) { - if(floppy->wpt_r()) - status |= S_WP; - if(!floppy->trk00_r()) - status |= S_TR00; - } - } - - if(has_ready()) { - if(!is_ready()) - status |= S_NRDY; - else - status &= ~S_NRDY; - } - - return status; -} - -void wd177x_t::do_track_w() -{ - track = track_buffer; - track_buffer = -1; -} - -void wd177x_t::track_w(UINT8 val) -{ - // No more than one write in flight - if(track_buffer != -1) - return; - - track_buffer = val; - delay_cycles(t_track, dden ? 256 : 128); -} - -UINT8 wd177x_t::track_r() -{ - return track; -} - -void wd177x_t::do_sector_w() -{ - sector = sector_buffer; - sector_buffer = -1; -} - -void wd177x_t::sector_w(UINT8 val) -{ - // No more than one write in flight - if(sector_buffer != -1) - return; - - sector_buffer = val; - delay_cycles(t_sector, dden ? 256 : 128); -} - -UINT8 wd177x_t::sector_r() -{ - return sector; -} - -void wd177x_t::data_w(UINT8 val) -{ - data = val; - drop_drq(); -} - -UINT8 wd177x_t::data_r() -{ - drop_drq(); - return data; -} - -void wd177x_t::gen_w(int reg, UINT8 val) -{ - switch(reg) { - case 0: cmd_w(val); break; - case 1: track_w(val); break; - case 2: sector_w(val); break; - case 3: data_w(val); break; - } -} - -UINT8 wd177x_t::gen_r(int reg) -{ - switch(reg) { - case 0: return status_r(); break; - case 1: return track_r(); break; - case 2: return sector_r(); break; - case 3: return data_r(); break; - } - return 0xff; -} - -void wd177x_t::delay_cycles(emu_timer *tm, int cycles) -{ - tm->adjust(clocks_to_attotime(cycles)); -} - -void wd177x_t::spinup() -{ - if(command & 0x08) - sub_state = SPINUP_DONE; - else { - sub_state = SPINUP_WAIT; - counter = 0; - } - - status |= S_MON; - if(floppy) - floppy->mon_w(0); - -} - -void wd177x_t::index_callback(floppy_image_device *floppy, int state) -{ - live_sync(); - - if(!state) { - general_continue(); - return; - } - - if(intrq_cond & I_IDX) { - intrq = true; - if(!intrq_cb.isnull()) - intrq_cb(intrq); - } - - switch(sub_state) { - case IDLE: - if(has_motor()) { - motor_timeout ++; - if(motor_timeout >= 5) { - status &= ~S_MON; - if(floppy) - floppy->mon_w(1); - } - } - break; - - case SPINUP: - break; - - case SPINUP_WAIT: - counter++; - if(counter == 6) { - sub_state = SPINUP_DONE; - if(status_type_1) - status |= S_SPIN; - } - break; - - case SPINUP_DONE: - case SETTLE_WAIT: - case SETTLE_DONE: - case DATA_LOAD_WAIT: - case DATA_LOAD_WAIT_DONE: - case SEEK_MOVE: - case SEEK_WAIT_STEP_TIME: - case SEEK_WAIT_STEP_TIME_DONE: - case SEEK_WAIT_STABILIZATION_TIME: - case SEEK_WAIT_STABILIZATION_TIME_DONE: - case SEEK_DONE: - case WAIT_INDEX_DONE: - case SCAN_ID_FAILED: - case SECTOR_READ: - case SECTOR_WRITE: - break; - - case SCAN_ID: - counter++; - if(counter == 5) { - sub_state = SCAN_ID_FAILED; - live_abort(); - } - break; - - case WAIT_INDEX: - sub_state = WAIT_INDEX_DONE; - break; - - case TRACK_DONE: - live_abort(); - break; - - default: - logerror("%s: Index pulse on unknown sub-state %d\n", ttsn().cstr(), sub_state); - break; - } - - general_continue(); -} - -bool wd177x_t::intrq_r() -{ - return intrq; -} - -bool wd177x_t::drq_r() -{ - return drq; -} - -bool wd177x_t::hld_r() -{ - return hld; -} - -void wd177x_t::hlt_w(bool state) -{ - hlt = state; -} - -bool wd177x_t::enp_r() -{ - return enp; -} - -void wd177x_t::live_start(int state) -{ - cur_live.tm = machine().time(); - cur_live.state = state; - cur_live.next_state = -1; - cur_live.shift_reg = 0; - cur_live.crc = 0xffff; - cur_live.bit_counter = 0; - cur_live.data_separator_phase = false; - cur_live.data_reg = 0; - cur_live.previous_type = live_info::PT_NONE; - cur_live.data_bit_context = false; - cur_live.byte_counter = 0; - cur_live.pll.reset(cur_live.tm); - cur_live.pll.set_clock(clocks_to_attotime(1)); - checkpoint_live = cur_live; - - live_run(); -} - -void wd177x_t::checkpoint() -{ - cur_live.pll.commit(floppy, cur_live.tm); - checkpoint_live = cur_live; -} - -void wd177x_t::rollback() -{ - cur_live = checkpoint_live; -} - -void wd177x_t::live_delay(int state) -{ - cur_live.next_state = state; - t_gen->adjust(cur_live.tm - machine().time()); -} - -void wd177x_t::live_sync() -{ - if(!cur_live.tm.is_never()) { - if(cur_live.tm > machine().time()) { - // fprintf(stderr, "%s: Rolling back and replaying (%s)\n", ttsn().cstr(), tts(cur_live.tm).cstr()); - rollback(); - live_run(machine().time()); - cur_live.pll.commit(floppy, cur_live.tm); - } else { - // fprintf(stderr, "%s: Committing (%s)\n", ttsn().cstr(), tts(cur_live.tm).cstr()); - cur_live.pll.commit(floppy, 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) { - cur_live.pll.stop_writing(floppy, cur_live.tm); - cur_live.tm = attotime::never; - } - } - cur_live.next_state = -1; - checkpoint(); - } -} - -void wd177x_t::live_abort() -{ - if(!cur_live.tm.is_never() && cur_live.tm > machine().time()) { - rollback(); - live_run(machine().time()); - } - - cur_live.pll.stop_writing(floppy, cur_live.tm); - cur_live.tm = attotime::never; - cur_live.state = IDLE; - cur_live.next_state = -1; -} - -bool wd177x_t::read_one_bit(attotime limit) -{ - int bit = cur_live.pll.get_next_bit(cur_live.tm, floppy, limit); - if(bit < 0) - return true; - cur_live.shift_reg = (cur_live.shift_reg << 1) | bit; - cur_live.bit_counter++; - if(cur_live.data_separator_phase) { - cur_live.data_reg = (cur_live.data_reg << 1) | bit; - if((cur_live.crc ^ (bit ? 0x8000 : 0x0000)) & 0x8000) - cur_live.crc = (cur_live.crc << 1) ^ 0x1021; - else - cur_live.crc = cur_live.crc << 1; - } - cur_live.data_separator_phase = !cur_live.data_separator_phase; - return false; -} - -bool wd177x_t::write_one_bit(attotime limit) -{ - bool bit = cur_live.shift_reg & 0x8000; - if(cur_live.pll.write_next_bit(bit, cur_live.tm, floppy, limit)) - return true; - if(cur_live.bit_counter & 1) { - if((cur_live.crc ^ (bit ? 0x8000 : 0x0000)) & 0x8000) - cur_live.crc = (cur_live.crc << 1) ^ 0x1021; - else - cur_live.crc = cur_live.crc << 1; - } - cur_live.shift_reg = cur_live.shift_reg << 1; - cur_live.bit_counter--; - return false; -} - -void wd177x_t::live_write_raw(UINT16 raw) -{ - // logerror("write %04x %04x\n", raw, cur_live.crc); - cur_live.shift_reg = raw; - cur_live.data_bit_context = raw & 1; -} - -void wd177x_t::live_write_mfm(UINT8 mfm) -{ - bool context = cur_live.data_bit_context; - UINT16 raw = 0; - for(int i=0; i<8; i++) { - bool bit = mfm & (0x80 >> i); - if(!(bit || context)) - raw |= 0x8000 >> (2*i); - if(bit) - raw |= 0x4000 >> (2*i); - context = bit; - } - cur_live.shift_reg = raw; - cur_live.data_bit_context = context; - // logerror("write %02x %04x %04x\n", mfm, cur_live.crc, raw); -} - -void wd177x_t::live_run(attotime limit) -{ - if(cur_live.state == IDLE || cur_live.next_state != -1) - return; - - if(limit == attotime::never) { - if(floppy) - limit = floppy->time_next_index(); - if(limit == attotime::never) { - // Happens when there's no disk or if the wd is not - // connected to a drive, hence no index pulse. Force a - // sync from time to time in that case, so that the main - // cpu timeout isn't too painful. Avoids looping into - // infinity looking for data too. - - limit = machine().time() + attotime::from_msec(1); - t_gen->adjust(attotime::from_msec(1)); - } - } - - // fprintf(stderr, "%s: live_run(%s)\n", ttsn().cstr(), tts(limit).cstr()); - - for(;;) { - switch(cur_live.state) { - case SEARCH_ADDRESS_MARK_HEADER: - if(read_one_bit(limit)) - return; -#if 0 - fprintf(stderr, "%s: shift = %04x data=%02x c=%d\n", tts(cur_live.tm).cstr(), cur_live.shift_reg, - (cur_live.shift_reg & 0x4000 ? 0x80 : 0x00) | - (cur_live.shift_reg & 0x1000 ? 0x40 : 0x00) | - (cur_live.shift_reg & 0x0400 ? 0x20 : 0x00) | - (cur_live.shift_reg & 0x0100 ? 0x10 : 0x00) | - (cur_live.shift_reg & 0x0040 ? 0x08 : 0x00) | - (cur_live.shift_reg & 0x0010 ? 0x04 : 0x00) | - (cur_live.shift_reg & 0x0004 ? 0x02 : 0x00) | - (cur_live.shift_reg & 0x0001 ? 0x01 : 0x00), - cur_live.bit_counter); -#endif - - if(cur_live.shift_reg == 0x4489) { - cur_live.crc = 0x443b; - cur_live.data_separator_phase = false; - cur_live.bit_counter = 0; - cur_live.state = READ_HEADER_BLOCK_HEADER; - } - break; - - case READ_HEADER_BLOCK_HEADER: { - if(read_one_bit(limit)) - return; -#if 0 - fprintf(stderr, "%s: shift = %04x data=%02x counter=%d\n", tts(cur_live.tm).cstr(), cur_live.shift_reg, - (cur_live.shift_reg & 0x4000 ? 0x80 : 0x00) | - (cur_live.shift_reg & 0x1000 ? 0x40 : 0x00) | - (cur_live.shift_reg & 0x0400 ? 0x20 : 0x00) | - (cur_live.shift_reg & 0x0100 ? 0x10 : 0x00) | - (cur_live.shift_reg & 0x0040 ? 0x08 : 0x00) | - (cur_live.shift_reg & 0x0010 ? 0x04 : 0x00) | - (cur_live.shift_reg & 0x0004 ? 0x02 : 0x00) | - (cur_live.shift_reg & 0x0001 ? 0x01 : 0x00), - cur_live.bit_counter); -#endif - if(cur_live.bit_counter & 15) - break; - - int slot = cur_live.bit_counter >> 4; - - if(slot < 3) { - if(cur_live.shift_reg != 0x4489) - cur_live.state = SEARCH_ADDRESS_MARK_HEADER; - break; - } - if(cur_live.data_reg != 0xfe && cur_live.data_reg != 0xff) { - cur_live.state = SEARCH_ADDRESS_MARK_HEADER; - break; - } - - cur_live.bit_counter = 0; - - if(main_state == READ_ID) - cur_live.state = READ_ID_BLOCK_TO_DMA; - else - cur_live.state = READ_ID_BLOCK_TO_LOCAL; - - break; - } - - case READ_ID_BLOCK_TO_LOCAL: { - if(read_one_bit(limit)) - return; - if(cur_live.bit_counter & 15) - break; - int slot = (cur_live.bit_counter >> 4)-1; - cur_live.idbuf[slot] = cur_live.data_reg; - if(slot == 5) { - live_delay(IDLE); - return; - } - break; - } - - case READ_ID_BLOCK_TO_DMA: { - if(read_one_bit(limit)) - return; - if(cur_live.bit_counter & 15) - break; - live_delay(READ_ID_BLOCK_TO_DMA_BYTE); - return; - } - - case READ_ID_BLOCK_TO_DMA_BYTE: - data = cur_live.data_reg; - if(cur_live.bit_counter == 16) - sector = data; - set_drq(); - - if(cur_live.bit_counter == 16*6) { - // Already synchronous - cur_live.state = IDLE; - return; - } - - cur_live.state = READ_ID_BLOCK_TO_DMA; - checkpoint(); - break; - - case SEARCH_ADDRESS_MARK_DATA: - if(read_one_bit(limit)) - return; -#if 0 - fprintf(stderr, "%s: shift = %04x data=%02x c=%d.%x\n", tts(cur_live.tm).cstr(), cur_live.shift_reg, - (cur_live.shift_reg & 0x4000 ? 0x80 : 0x00) | - (cur_live.shift_reg & 0x1000 ? 0x40 : 0x00) | - (cur_live.shift_reg & 0x0400 ? 0x20 : 0x00) | - (cur_live.shift_reg & 0x0100 ? 0x10 : 0x00) | - (cur_live.shift_reg & 0x0040 ? 0x08 : 0x00) | - (cur_live.shift_reg & 0x0010 ? 0x04 : 0x00) | - (cur_live.shift_reg & 0x0004 ? 0x02 : 0x00) | - (cur_live.shift_reg & 0x0001 ? 0x01 : 0x00), - cur_live.bit_counter >> 4, cur_live.bit_counter & 15); -#endif - if(cur_live.bit_counter > 43*16) { - live_delay(SEARCH_ADDRESS_MARK_DATA_FAILED); - return; - } - - if(cur_live.bit_counter >= 28*16 && cur_live.shift_reg == 0x4489) { - cur_live.crc = 0x443b; - cur_live.data_separator_phase = false; - cur_live.bit_counter = 0; - cur_live.state = READ_DATA_BLOCK_HEADER; - } - break; - - case READ_DATA_BLOCK_HEADER: { - if(read_one_bit(limit)) - return; -#if 0 - fprintf(stderr, "%s: shift = %04x data=%02x counter=%d\n", tts(cur_live.tm).cstr(), cur_live.shift_reg, - (cur_live.shift_reg & 0x4000 ? 0x80 : 0x00) | - (cur_live.shift_reg & 0x1000 ? 0x40 : 0x00) | - (cur_live.shift_reg & 0x0400 ? 0x20 : 0x00) | - (cur_live.shift_reg & 0x0100 ? 0x10 : 0x00) | - (cur_live.shift_reg & 0x0040 ? 0x08 : 0x00) | - (cur_live.shift_reg & 0x0010 ? 0x04 : 0x00) | - (cur_live.shift_reg & 0x0004 ? 0x02 : 0x00) | - (cur_live.shift_reg & 0x0001 ? 0x01 : 0x00), - cur_live.bit_counter); -#endif - if(cur_live.bit_counter & 15) - break; - - int slot = cur_live.bit_counter >> 4; - - if(slot < 3) { - if(cur_live.shift_reg != 0x4489) { - live_delay(SEARCH_ADDRESS_MARK_DATA_FAILED); - return; - } - break; - } - if((cur_live.data_reg & 0xfe) != 0xfa && (cur_live.data_reg & 0xfe) != 0xfc) { - live_delay(SEARCH_ADDRESS_MARK_DATA_FAILED); - return; - } - - cur_live.bit_counter = 0; - cur_live.state = READ_SECTOR_DATA; - break; - } - - case SEARCH_ADDRESS_MARK_DATA_FAILED: - status |= S_RNF; - cur_live.state = IDLE; - return; - - case READ_SECTOR_DATA: { - if(read_one_bit(limit)) - return; - if(cur_live.bit_counter & 15) - break; - int slot = (cur_live.bit_counter >> 4)-1; - if(slot < sector_size) { - // Sector data - live_delay(READ_SECTOR_DATA_BYTE); - return; - - } else if(slot < sector_size+2) { - // CRC - if(slot == sector_size+1) { - live_delay(IDLE); - return; - } - } - - break; - } - - case READ_SECTOR_DATA_BYTE: - data = cur_live.data_reg; - set_drq(); - cur_live.state = READ_SECTOR_DATA; - checkpoint(); - break; - - case READ_TRACK_DATA: { - if(read_one_bit(limit)) - return; - if(cur_live.bit_counter != 16 - && cur_live.shift_reg != 0x4489 - && cur_live.shift_reg != 0x5224) - break; - - // Incorrect, hmmm - // Probably >2 + not just after a sync if <16 - - // Transitions 00..00 -> 4489.4489.4489 at varied syncs: - // 0: 00.00.14.a1 1: ff.fe.c2.a1 2: 00.01.14.a1 3: ff.fc.c2.a1 - // 4: 00.02.14.a1 5: ff.f8.c2.a1 6: 00.05.14.a1 7: ff.f0.c2.a1 - // 8: 00.00.0a.a1 9: ff.ff.e1.a1 10: 00.00.14.a1 11: ff.ff.ce.a1 - // 12: 00.00.14.a1 13: ff.ff.c2.a1 14: 00.00.14.a1 15: ff.ff.c2.a1 - - bool output_byte = cur_live.bit_counter > 5; - - cur_live.data_separator_phase = false; - cur_live.bit_counter = 0; - - if(output_byte) { - live_delay(READ_TRACK_DATA_BYTE); - return; - } - - break; - } - - case READ_TRACK_DATA_BYTE: - data = cur_live.data_reg; - set_drq(); - cur_live.state = READ_TRACK_DATA; - checkpoint(); - break; - - case WRITE_TRACK_DATA: - if(drq) { - status |= S_LOST; - data = 0; - } - - switch(data) { - case 0xf5: - live_write_raw(0x4489); - cur_live.crc = 0x968b; // Ensures that the crc is cdb4 after writing the byte - cur_live.previous_type = live_info::PT_NONE; - break; - case 0xf6: - cur_live.previous_type = live_info::PT_NONE; - live_write_raw(0x5224); - break; - case 0xf7: - if(cur_live.previous_type == live_info::PT_CRC_2) { - cur_live.previous_type = live_info::PT_NONE; - live_write_mfm(0xf7); - } else { - cur_live.previous_type = live_info::PT_CRC_1; - live_write_mfm(cur_live.crc >> 8); - } - break; - default: - cur_live.previous_type = live_info::PT_NONE; - live_write_mfm(data); - break; - } - set_drq(); - cur_live.state = WRITE_BYTE; - cur_live.bit_counter = 16; - checkpoint(); - break; - - case WRITE_BYTE: - if(write_one_bit(limit)) - return; - if(cur_live.bit_counter == 0) { - live_delay(WRITE_BYTE_DONE); - return; - } - break; - - case WRITE_BYTE_DONE: - switch(sub_state) { - case TRACK_DONE: - if(cur_live.previous_type == live_info::PT_CRC_1) { - cur_live.previous_type = live_info::PT_CRC_2; - live_write_mfm(cur_live.crc >> 8); - cur_live.state = WRITE_BYTE; - cur_live.bit_counter = 16; - checkpoint(); - } else - cur_live.state = WRITE_TRACK_DATA; - break; - - case SECTOR_WRITE: - cur_live.state = WRITE_BYTE; - cur_live.bit_counter = 16; - cur_live.byte_counter++; - if(cur_live.byte_counter <= 11) - live_write_mfm(0x00); - else if(cur_live.byte_counter == 12) { - cur_live.crc = 0xffff; - live_write_raw(0x4489); - } else if(cur_live.byte_counter <= 14) - live_write_raw(0x4489); - else if(cur_live.byte_counter == 15) - live_write_mfm(command & 1 ? 0xf8 : 0xfb); - else if(cur_live.byte_counter <= sector_size + 16-2) { - if(drq) { - status |= S_LOST; - data = 0; - } - live_write_mfm(data); - set_drq(); - } else if(cur_live.byte_counter == sector_size + 16-1) { - if(drq) { - status |= S_LOST; - data = 0; - } - live_write_mfm(data); - } else if(cur_live.byte_counter <= sector_size + 16+1) - live_write_mfm(cur_live.crc >> 8); - else if(cur_live.byte_counter == sector_size + 16+2) - // Is that correct? It seems required (try ST formatting) - live_write_mfm(0xff); - else { - cur_live.pll.stop_writing(floppy, cur_live.tm); - cur_live.state = IDLE; - return; - } - - checkpoint(); - break; - - default: - logerror("%s: Unknown sub state %d in WRITE_BYTE_DONE\n", tts(cur_live.tm).cstr(), sub_state); - live_abort(); - return; - } - break; - - case WRITE_SECTOR_PRE: - if(read_one_bit(limit)) - return; - if(cur_live.bit_counter != 16) - break; - live_delay(WRITE_SECTOR_PRE_BYTE); - return; - - case WRITE_SECTOR_PRE_BYTE: - cur_live.state = WRITE_SECTOR_PRE; - cur_live.byte_counter++; - cur_live.bit_counter = 0; - switch(cur_live.byte_counter) { - case 2: - set_drq(); - checkpoint(); - break; - case 11: - if(drq) { - status |= S_LOST; - cur_live.state = IDLE; - return; - } - break; - case 22: - cur_live.state = WRITE_BYTE; - cur_live.bit_counter = 16; - cur_live.byte_counter = 0; - cur_live.data_bit_context = cur_live.data_reg & 1; - cur_live.pll.start_writing(cur_live.tm); - live_write_mfm(0x00); - break; - } - break; - - default: - logerror("%s: Unknown live state %d\n", tts(cur_live.tm).cstr(), cur_live.state); - return; - } - } -} - -void wd177x_t::set_drq() -{ - if(drq) - status |= S_LOST; - else { - drq = true; - if(!drq_cb.isnull()) - drq_cb(true); - } -} - -void wd177x_t::drop_drq() -{ - if(drq) { - drq = false; - if(!drq_cb.isnull()) - drq_cb(false); - } -} - -void wd177x_t::pll_t::set_clock(attotime period) -{ - for(int i=0; i<42; i++) - delays[i] = period*(i+1); -} - -void wd177x_t::pll_t::reset(attotime when) -{ - counter = 0; - increment = 128; - transition_time = 0xffff; - history = 0x80; - slot = 0; - ctime = when; - phase_add = 0x00; - phase_sub = 0x00; - freq_add = 0x00; - freq_sub = 0x00; - write_position = 0; - write_start_time = attotime::never; -} - -int wd177x_t::pll_t::get_next_bit(attotime &tm, floppy_image_device *floppy, attotime limit) -{ - attotime when = floppy ? floppy->get_next_transition(ctime) : attotime::never; -#if 0 - if(!when.is_never()) - fprintf(stderr, "transition_time=%s\n", tts(when).cstr()); -#endif - - for(;;) { - // fprintf(stderr, "slot=%2d, counter=%03x\n", slot, counter); - attotime etime = ctime+delays[slot]; - // fprintf(stderr, "etime=%s\n", tts(etime).cstr()); - if(etime > limit) - return -1; - if(transition_time == 0xffff && !when.is_never() && etime >= when) - transition_time = counter; - if(slot < 8) { - UINT8 mask = 1 << slot; - if(phase_add & mask) - counter += 226; - else if(phase_sub & mask) - counter += 30; - else - counter += increment; - - if((freq_add & mask) && increment < 140) - increment++; - else if((freq_sub & mask) && increment > 117) - increment--; - } else - counter += increment; - - slot++; - tm = etime; - if(counter & 0x800) - break; - } - // fprintf(stderr, "first transition, time=%03x, inc=%3d\n", transition_time, increment); - int bit = transition_time != 0xffff; - - if(transition_time != 0xffff) { - static const UINT8 pha[8] = { 0xf, 0x7, 0x3, 0x1, 0, 0, 0, 0 }; - static const UINT8 phs[8] = { 0, 0, 0, 0, 0x1, 0x3, 0x7, 0xf }; - static const UINT8 freqa[4][8] = { - { 0xf, 0x7, 0x3, 0x1, 0, 0, 0, 0 }, - { 0x7, 0x3, 0x1, 0, 0, 0, 0, 0 }, - { 0x7, 0x3, 0x1, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 } - }; - static const UINT8 freqs[4][8] = { - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0x1, 0x3, 0x7 }, - { 0, 0, 0, 0, 0, 0x1, 0x3, 0x7 }, - { 0, 0, 0, 0, 0x1, 0x3, 0x7, 0xf }, - }; - - int cslot = transition_time >> 8; - phase_add = pha[cslot]; - phase_sub = phs[cslot]; - int way = transition_time & 0x400 ? 1 : 0; - if(history & 0x80) - history = way ? 0x80 : 0x83; - else if(history & 0x40) - history = way ? history & 2 : (history & 2) | 1; - freq_add = freqa[history & 3][cslot]; - freq_sub = freqs[history & 3][cslot]; - history = way ? (history >> 1) | 2 : history >> 1; - - } else - phase_add = phase_sub = freq_add = freq_sub = 0; - - counter &= 0x7ff; - - ctime = tm; - transition_time = 0xffff; - slot = 0; - - return bit; -} - -void wd177x_t::pll_t::start_writing(attotime tm) -{ - write_start_time = tm; - write_position = 0; -} - -void wd177x_t::pll_t::stop_writing(floppy_image_device *floppy, attotime tm) -{ - commit(floppy, tm); - write_start_time = attotime::never; -} - -bool wd177x_t::pll_t::write_next_bit(bool bit, attotime &tm, floppy_image_device *floppy, attotime limit) -{ - if(write_start_time.is_never()) { - write_start_time = ctime; - write_position = 0; - } - - for(;;) { - attotime etime = ctime+delays[slot]; - if(etime > limit) - return true; - UINT16 pre_counter = counter; - counter += increment; - if(bit && !(pre_counter & 0x400) && (counter & 0x400)) - if(write_position < ARRAY_LENGTH(write_buffer)) - write_buffer[write_position++] = etime; - slot++; - tm = etime; - if(counter & 0x800) - break; - } - - counter &= 0x7ff; - - ctime = tm; - slot = 0; - - return false; -} - -void wd177x_t::pll_t::commit(floppy_image_device *floppy, attotime tm) -{ - if(write_start_time.is_never() || tm == write_start_time) - return; - - if(floppy) - floppy->write_flux(write_start_time, tm, write_position, write_buffer); - write_start_time = tm; - write_position = 0; -} - -int wd177x_t::step_time(int mode) const -{ - const static int step_times[4] = { 48000, 96000, 160000, 240000 }; - return step_times[mode]; -} - -int wd177x_t::settle_time() const -{ - return 240000; -} - -bool wd177x_t::has_ready() const -{ - return false; -} - -bool wd177x_t::has_head_load() const -{ - return false; -} - -bool wd177x_t::has_side_check() const -{ - return false; -} - -bool wd177x_t::has_side_select() const -{ - return false; -} - -bool wd177x_t::has_sector_length_select() const -{ - return false; -} - -bool wd177x_t::has_precompensation() const -{ - return false; -} - -fd1771_t::fd1771_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : wd177x_t(mconfig, FD1771x, "FD1771", tag, owner, clock) -{ -} - -fd1793_t::fd1793_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : wd177x_t(mconfig, FD1793x, "FD1793", tag, owner, clock) -{ -} - -fd1797_t::fd1797_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : wd177x_t(mconfig, FD1797x, "FD1797", tag, owner, clock) -{ -} - -wd2793_t::wd2793_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : wd177x_t(mconfig, WD2793x, "WD2793", tag, owner, clock) -{ -} - -wd2797_t::wd2797_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : wd177x_t(mconfig, WD2797x, "WD2797", tag, owner, clock) -{ -} - -wd1770_t::wd1770_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : wd177x_t(mconfig, WD1770x, "WD1770", tag, owner, clock) -{ -} - -wd1772_t::wd1772_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : wd177x_t(mconfig, WD1772x, "WD1772", tag, owner, clock) -{ -} - -int wd1772_t::step_time(int mode) const -{ - const static int step_times[4] = { 48000, 96000, 16000, 24000 }; - return step_times[mode]; -} - -int wd1772_t::settle_time() const -{ - return 120000; -} - -wd1773_t::wd1773_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : wd177x_t(mconfig, WD1773x, "WD1773", tag, owner, clock) -{ -} diff --git a/src/mess/machine/wd1772.h b/src/mess/machine/wd1772.h deleted file mode 100644 index 22803f6ad39..00000000000 --- a/src/mess/machine/wd1772.h +++ /dev/null @@ -1,431 +0,0 @@ -#ifndef WD1772_H -#define WD1772_H - -#include "emu.h" -#include "imagedev/floppy.h" - -#define MCFG_FD1771x_ADD(_tag, _clock) \ - MCFG_DEVICE_ADD(_tag, FD1771x, _clock) - -#define MCFG_FD1793x_ADD(_tag, _clock) \ - MCFG_DEVICE_ADD(_tag, FD1793x, _clock) - -#define MCFG_FD1797x_ADD(_tag, _clock) \ - MCFG_DEVICE_ADD(_tag, FD1797x, _clock) - -#define MCFG_WD2793x_ADD(_tag, _clock) \ - MCFG_DEVICE_ADD(_tag, WD2793x, _clock) - -#define MCFG_WD2797x_ADD(_tag, _clock) \ - MCFG_DEVICE_ADD(_tag, WD2797x, _clock) - -#define MCFG_WD1770x_ADD(_tag, _clock) \ - MCFG_DEVICE_ADD(_tag, WD1770x, _clock) - -#define MCFG_WD1772x_ADD(_tag, _clock) \ - MCFG_DEVICE_ADD(_tag, WD1772x, _clock) - -#define MCFG_WD1773x_ADD(_tag, _clock) \ - MCFG_DEVICE_ADD(_tag, WD1773x, _clock) - -class wd177x_t : public device_t { -public: - typedef delegate line_cb; - - wd177x_t(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock); - - void dden_w(bool dden); - void set_floppy(floppy_image_device *floppy); - void setup_intrq_cb(line_cb cb); - void setup_drq_cb(line_cb cb); - void setup_hld_cb(line_cb cb); - void setup_enp_cb(line_cb cb); - - void cmd_w(UINT8 val); - UINT8 status_r(); - DECLARE_READ8_MEMBER( status_r ) { return status_r(); } - DECLARE_WRITE8_MEMBER( cmd_w ) { cmd_w(data); } - - void track_w(UINT8 val); - UINT8 track_r(); - DECLARE_READ8_MEMBER( track_r ) { return track_r(); } - DECLARE_WRITE8_MEMBER( track_w ) { track_w(data); } - - void sector_w(UINT8 val); - UINT8 sector_r(); - DECLARE_READ8_MEMBER( sector_r ) { return sector_r(); } - DECLARE_WRITE8_MEMBER( sector_w ) { sector_w(data); } - - void data_w(UINT8 val); - UINT8 data_r(); - DECLARE_READ8_MEMBER( data_r ) { return data_r(); } - DECLARE_WRITE8_MEMBER( data_w ) { data_w(data); } - - void gen_w(int reg, UINT8 val); - UINT8 gen_r(int reg); - DECLARE_READ8_MEMBER( read ) { return gen_r(offset);} - DECLARE_WRITE8_MEMBER( write ) { gen_w(offset,data); } - - bool intrq_r(); - bool drq_r(); - - bool hld_r(); - void hlt_w(bool state); - - bool enp_r(); - -protected: - virtual void device_start(); - virtual void device_reset(); - virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); - - virtual bool has_ready() const; - virtual bool has_motor() const = 0; - virtual bool has_head_load() const; - virtual bool has_side_check() const; - virtual bool has_side_select() const; - virtual bool has_sector_length_select() const; - virtual bool has_precompensation() const; - virtual int step_time(int mode) const; - virtual int settle_time() const; - -private: - enum { TM_GEN, TM_CMD, TM_TRACK, TM_SECTOR }; - - // State machine general behaviour: - // - // There are three levels of state. - // - // Main state is associated to (groups of) commands. They're set - // by a *_start() function below, and the associated _continue() - // function can then be called at pretty much any time. - // - // Sub state is the state of execution within a command. The - // principle is that the *_start() function selects the initial - // substate, then the *_continue() function decides what to do, - // possibly changing state. Eventually it can: - // - decide to wait for an event (timer, index) - // - end the command with command_end() - // - start a live state (see below) - // - // In the first case, it must first switch to a waiting - // sub-state, then return. The waiting sub-state must just - // return immediatly when *_continue is called. Eventually the - // event handler function will advance the state machine to - // another sub-state, and things will continue synchronously. - // - // On command end it's also supposed to return immediatly. - // - // The last option is to switch to the next sub-state, start a - // live state with live_start() then return. The next sub-state - // will only be called once the live state is finished. - // - // Live states change continually depending on the disk contents - // until the next externally discernable event is found. They - // are checkpointing, run until an event is found, then they wait - // for it. When an event eventually happen the the changes are - // either committed or replayed until the sync event time. - // - // The transition to IDLE is only done on a synced event. Some - // other transitions, such as activating drq, are also done after - // syncing without exiting live mode. Syncing in live mode is - // done by calling live_delay() with the state to change to after - // syncing. - - enum { - // General "doing nothing" state - IDLE, - - // Main states - the commands - RESTORE, - SEEK, - STEP, - READ_SECTOR, - READ_TRACK, - READ_ID, - WRITE_TRACK, - WRITE_SECTOR, - - // Sub states - - SPINUP, - SPINUP_WAIT, - SPINUP_DONE, - - SETTLE_WAIT, - SETTLE_DONE, - - DATA_LOAD_WAIT, - DATA_LOAD_WAIT_DONE, - - SEEK_MOVE, - SEEK_WAIT_STEP_TIME, - SEEK_WAIT_STEP_TIME_DONE, - SEEK_WAIT_STABILIZATION_TIME, - SEEK_WAIT_STABILIZATION_TIME_DONE, - SEEK_DONE, - - WAIT_INDEX, - WAIT_INDEX_DONE, - - SCAN_ID, - SCAN_ID_FAILED, - - SECTOR_READ, - SECTOR_WRITE, - TRACK_DONE, - - // Live states - - SEARCH_ADDRESS_MARK_HEADER, - READ_HEADER_BLOCK_HEADER, - READ_DATA_BLOCK_HEADER, - READ_ID_BLOCK_TO_LOCAL, - READ_ID_BLOCK_TO_DMA, - READ_ID_BLOCK_TO_DMA_BYTE, - SEARCH_ADDRESS_MARK_DATA, - SEARCH_ADDRESS_MARK_DATA_FAILED, - READ_SECTOR_DATA, - READ_SECTOR_DATA_BYTE, - READ_TRACK_DATA, - READ_TRACK_DATA_BYTE, - WRITE_TRACK_DATA, - WRITE_BYTE, - WRITE_BYTE_DONE, - WRITE_SECTOR_PRE, - WRITE_SECTOR_PRE_BYTE, - }; - - struct pll_t { - UINT16 counter; - UINT16 increment; - UINT16 transition_time; - UINT8 history; - UINT8 slot; - UINT8 phase_add, phase_sub, freq_add, freq_sub; - attotime ctime; - - attotime delays[42]; - - attotime write_start_time; - attotime write_buffer[32]; - int write_position; - - void set_clock(attotime period); - void reset(attotime when); - int get_next_bit(attotime &tm, floppy_image_device *floppy, attotime limit); - bool write_next_bit(bool bit, attotime &tm, floppy_image_device *floppy, attotime limit); - void start_writing(attotime tm); - void commit(floppy_image_device *floppy, attotime tm); - void stop_writing(floppy_image_device *floppy, attotime tm); - }; - - struct live_info { - enum { PT_NONE, PT_CRC_1, PT_CRC_2 }; - - attotime tm; - int state, next_state; - UINT16 shift_reg; - UINT16 crc; - int bit_counter, byte_counter, previous_type; - bool data_separator_phase, data_bit_context; - UINT8 data_reg; - UINT8 idbuf[6]; - pll_t pll; - }; - - enum { - S_BUSY = 0x01, - S_DRQ = 0x02, - S_IP = 0x02, - S_TR00 = 0x04, - S_LOST = 0x04, - S_CRC = 0x08, - S_RNF = 0x10, - S_HLD = 0x20, - S_SPIN = 0x20, // WD1770, WD1772 - S_DDM = 0x20, - S_WF = 0x20, // WD1773 - S_WP = 0x40, - S_NRDY = 0x80, - S_MON = 0x80 // WD1770, WD1772 - }; - - enum { - I_RDY = 0x01, - I_NRDY = 0x02, - I_IDX = 0x04, - I_IMM = 0x08 - }; - - floppy_image_device *floppy; - - emu_timer *t_gen, *t_cmd, *t_track, *t_sector; - - bool dden, status_type_1, intrq, drq, hld, hlt, enp; - int main_state, sub_state; - UINT8 command, track, sector, data, status, intrq_cond; - int last_dir; - - int counter, motor_timeout, sector_size; - - int cmd_buffer, track_buffer, sector_buffer; - - live_info cur_live, checkpoint_live; - line_cb intrq_cb, drq_cb, hld_cb, enp_cb; - - static astring tts(attotime t); - astring ttsn(); - - void delay_cycles(emu_timer *tm, int cycles); - - // Device timer subfunctions - void do_cmd_w(); - void do_track_w(); - void do_sector_w(); - void do_generic(); - - - // Main-state handling functions - void seek_start(int state); - void seek_continue(); - - void read_sector_start(); - void read_sector_continue(); - - void read_track_start(); - void read_track_continue(); - - void read_id_start(); - void read_id_continue(); - - void write_track_start(); - void write_track_continue(); - - void write_sector_start(); - void write_sector_continue(); - - void interrupt_start(); - - void general_continue(); - void command_end(); - - void spinup(); - void index_callback(floppy_image_device *floppy, int state); - bool sector_matches() const; - bool is_ready(); - - void live_start(int live_state); - void live_abort(); - void checkpoint(); - void rollback(); - void live_delay(int state); - void live_sync(); - void live_run(attotime limit = attotime::never); - bool read_one_bit(attotime limit); - bool write_one_bit(attotime limit); - - void live_write_raw(UINT16 raw); - void live_write_mfm(UINT8 mfm); - - void drop_drq(); - void set_drq(); -}; - -class fd1771_t : public wd177x_t { -public: - fd1771_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); - -protected: - virtual bool has_ready() const { return true; } - virtual bool has_motor() const { return false; } - virtual bool has_head_load() const { return true; } - virtual bool has_side_check() const { return true; } -}; - -class fd1793_t : public wd177x_t { -public: - fd1793_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); - -protected: - virtual bool has_ready() const { return true; } - virtual bool has_motor() const { return false; } - virtual bool has_head_load() const { return true; } - virtual bool has_side_check() const { return true; } -}; - -class fd1797_t : public wd177x_t { -public: - fd1797_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); - -protected: - virtual bool has_ready() const { return true; } - virtual bool has_motor() const { return false; } - virtual bool has_head_load() const { return true; } - virtual bool has_side_select() const { return true; } - virtual bool has_sector_length_select() const { return true; } -}; - -class wd2793_t : public wd177x_t { -public: - wd2793_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); - -protected: - virtual bool has_ready() const { return true; } - virtual bool has_motor() const { return false; } - virtual bool has_head_load() const { return true; } - virtual bool has_side_check() const { return true; } -}; - -class wd2797_t : public wd177x_t { -public: - wd2797_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); - -protected: - virtual bool has_ready() const { return true; } - virtual bool has_motor() const { return false; } - virtual bool has_head_load() const { return true; } - virtual bool has_side_select() const { return true; } - virtual bool has_sector_length_select() const { return true; } -}; - -class wd1770_t : public wd177x_t { -public: - wd1770_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); - -protected: - virtual bool has_motor() const { return true; } - virtual bool has_precompensation() const { return true; } -}; - -class wd1772_t : public wd177x_t { -public: - wd1772_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); - -protected: - virtual bool has_motor() const { return true; } - virtual bool has_precompensation() const { return true; } - virtual int step_time(int mode) const; - virtual int settle_time() const; -}; - -class wd1773_t : public wd177x_t { -public: - wd1773_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); - -protected: - virtual bool has_motor() const { return false; } - virtual bool has_head_load() const { return true; } - virtual bool has_side_check() const { return true; } -}; - -extern const device_type FD1771x; -extern const device_type FD1793x; -extern const device_type FD1797x; -extern const device_type WD2793x; -extern const device_type WD2797x; -extern const device_type WD1770x; -extern const device_type WD1772x; -extern const device_type WD1773x; - -#endif diff --git a/src/mess/mess.mak b/src/mess/mess.mak index 0f5bb6ab5de..68c40d20020 100644 --- a/src/mess/mess.mak +++ b/src/mess/mess.mak @@ -526,7 +526,6 @@ $(MESSOBJ)/shared.a: \ $(MESS_MACHINE)/mos6530.o \ $(MESS_MACHINE)/s100.o \ $(MESS_MACHINE)/serial.o \ - $(MESS_MACHINE)/upd765.o \ $(MESS_MACHINE)/ncr5380.o \ $(MESS_MACHINE)/ncr5390.o \ $(MESS_MACHINE)/pc_kbdc.o \ @@ -554,7 +553,6 @@ $(MESSOBJ)/shared.a: \ $(MESS_MACHINE)/dp8390.o \ $(MESS_MACHINE)/ne1000.o \ $(MESS_MACHINE)/ne2000.o \ - $(MESS_MACHINE)/wd1772.o \ $(MESS_MACHINE)/3c503.o \ $(MESS_FORMATS)/z80bin.o \ $(MESS_MACHINE)/mb8795.o \