summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/machine/i8271.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/machine/i8271.cpp')
-rw-r--r--src/devices/machine/i8271.cpp1698
1 files changed, 1698 insertions, 0 deletions
diff --git a/src/devices/machine/i8271.cpp b/src/devices/machine/i8271.cpp
new file mode 100644
index 00000000000..6e938162ada
--- /dev/null
+++ b/src/devices/machine/i8271.cpp
@@ -0,0 +1,1698 @@
+// license:BSD-3-Clause
+// copyright-holders:Carl,Olivier Galibert
+
+#include "i8271.h"
+
+const device_type I8271 = &device_creator<i8271_device>;
+
+i8271_device::i8271_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, I8271, "Intel 8271", tag, owner, clock, "i8271", __FILE__),
+ intrq_cb(*this),
+ drq_cb(*this),
+ hdl_cb(*this),
+ opt_cb(*this)
+{
+ select_connected = true;
+ external_ready = false;
+}
+
+DEVICE_ADDRESS_MAP_START(map, 8, i8271_device)
+ AM_RANGE(0x0, 0x0) AM_READWRITE(sr_r, cmd_w)
+ AM_RANGE(0x1, 0x1) AM_READWRITE(rr_r, param_w)
+ AM_RANGE(0x2, 0x2) AM_WRITE(reset_w)
+ADDRESS_MAP_END
+
+void i8271_device::set_ready_line_connected(bool _ready)
+{
+ ready_connected = _ready;
+}
+
+void i8271_device::set_select_lines_connected(bool _select)
+{
+ select_connected = _select;
+}
+
+void i8271_device::device_start()
+{
+ intrq_cb.resolve_safe();
+ drq_cb.resolve_safe();
+ hdl_cb.resolve_safe();
+ opt_cb.resolve_safe();
+
+ for(int i=0; i != 2; 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<floppy_connector>(name);
+ if(con) {
+ flopi[i].dev = con->get_device();
+ if (flopi[i].dev != NULL)
+ flopi[i].dev->setup_index_pulse_cb(floppy_image_device::index_pulse_cb(FUNC(i8271_device::index_callback), this));
+ } else
+ flopi[i].dev = NULL;
+ } else
+ flopi[i].dev = NULL;
+
+ flopi[i].main_state = IDLE;
+ flopi[i].sub_state = IDLE;
+ flopi[i].dir = 0;
+ flopi[i].counter = 0;
+ flopi[i].pcn = 0;
+ flopi[i].live = false;
+ flopi[i].index = false;
+ flopi[i].ready = true;
+ }
+ cur_rate = 250000;
+
+ cur_live.tm = attotime::never;
+ cur_live.state = IDLE;
+ cur_live.next_state = -1;
+ cur_live.fi = NULL;
+}
+
+void i8271_device::device_reset()
+{
+ soft_reset();
+}
+
+void i8271_device::soft_reset()
+{
+ main_phase = PHASE_IDLE;
+ for(int i=0; i<2; i++) {
+ flopi[i].main_state = IDLE;
+ flopi[i].sub_state = IDLE;
+ flopi[i].live = false;
+ flopi[i].ready = get_ready(i);
+ }
+ set_irq(false);
+ set_drq(false);
+ command_pos = 0;
+ cur_live.fi = 0;
+ cur_live.tm = attotime::never;
+ cur_live.state = IDLE;
+ cur_live.next_state = -1;
+ cur_live.fi = NULL;
+ rr = 0;
+ scan_sec = 0;
+ moder = 0xc0;
+ oport = 0;
+ scan_cnt[0] = scan_cnt[1] = 0;
+}
+
+void i8271_device::ready_w(bool _ready)
+{
+ external_ready = _ready;
+}
+
+bool i8271_device::get_ready(int fid)
+{
+ if(!flopi[fid].ready)
+ return false;
+ if(ready_connected)
+ return flopi[fid].dev ? !flopi[fid].dev->ready_r() : false;
+ return !external_ready;
+}
+
+void i8271_device::set_floppy(floppy_image_device *flop)
+{
+ for(int fid=0; fid<2; 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(i8271_device::index_callback), this));
+}
+
+READ8_MEMBER(i8271_device::sr_r)
+{
+ UINT32 ret = (irq ? SR_IRQ : 0);
+ switch(main_phase) {
+ case PHASE_CMD:
+ ret |= SR_CF;
+ break;
+ case PHASE_EXEC:
+ ret |= SR_BSY;
+ if((moder & 1) && drq)
+ ret |= SR_DRQ;
+ break;
+ case PHASE_RESULT:
+ ret |= SR_RF;
+ break;
+ }
+ return ret;
+}
+
+READ8_MEMBER(i8271_device::rr_r)
+{
+ if(main_phase == PHASE_RESULT)
+ main_phase = PHASE_IDLE;
+ set_irq(false);
+ return rr;
+}
+
+void i8271_device::set_rate(int rate)
+{
+ cur_rate = rate;
+}
+
+READ8_MEMBER(i8271_device::data_r)
+{
+ set_drq(false);
+ return dma_data;
+}
+
+WRITE8_MEMBER(i8271_device::data_w)
+{
+ if(drq) {
+ set_drq(false);
+ dma_data = data;
+ }
+}
+
+WRITE8_MEMBER(i8271_device::cmd_w)
+{
+ if(main_phase == PHASE_IDLE) {
+ command[0] = data;
+ command_pos = 1;
+
+ int cmd = check_command();
+ if(cmd != C_INVALID) {
+ main_phase = PHASE_CMD;
+ if(cmd != C_INCOMPLETE)
+ start_command(cmd);
+ }
+ }
+}
+
+WRITE8_MEMBER(i8271_device::param_w)
+{
+ if(main_phase == PHASE_CMD) {
+ command[command_pos++] = data;
+ int cmd = check_command();
+ if(cmd != C_INCOMPLETE)
+ start_command(cmd);
+ }
+}
+
+bool i8271_device::set_output(UINT8 data)
+{
+ if(main_phase == PHASE_EXEC) {
+ if(drq) {
+ rr = ERR_DMA;
+ return false;
+ }
+ dma_data = data;
+ set_drq(true);
+ }
+ return true;
+}
+
+bool i8271_device::get_input(UINT8 *data)
+{
+ if(main_phase == PHASE_EXEC) {
+ if(drq) {
+ rr = ERR_DMA;
+ return false;
+ }
+ *data = dma_data;
+ set_drq(true);
+ }
+ return true;
+}
+
+void i8271_device::set_drq(bool state)
+{
+ if(state != drq) {
+ drq = state;
+ drq_cb(drq);
+ if(moder & 1)
+ intrq_cb(drq);
+ }
+}
+
+void i8271_device::set_irq(bool state)
+{
+ if(state != irq) {
+ irq = state;
+ intrq_cb(irq);
+ }
+}
+
+void i8271_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(cur_rate));
+ checkpoint_live = cur_live;
+ fi.live = true;
+
+ live_run();
+}
+
+void i8271_device::checkpoint()
+{
+ if(cur_live.fi)
+ cur_live.pll.commit(cur_live.fi->dev, cur_live.tm);
+ checkpoint_live = cur_live;
+}
+
+void i8271_device::rollback()
+{
+ cur_live = checkpoint_live;
+}
+
+void i8271_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 i8271_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 i8271_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 i8271_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).c_str(), 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 == 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_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).c_str(), slot, cur_live.data_reg, cur_live.crc);
+ cur_live.idbuf[slot] = cur_live.data_reg;
+ if(cur_live.fi->main_state == READ_ID) {
+ if(!set_output(cur_live.data_reg)) {
+ live_delay(IDLE);
+ return;
+ }
+ }
+ 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).c_str(), 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 > 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 SEARCH_ADDRESS_MARK_DATA_FAILED:
+ 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
+ if(cur_live.fi->main_state == SCAN_DATA)
+ live_delay(SCAN_SECTOR_DATA_BYTE);
+ else if(cur_live.fi->main_state == VERIFY_DATA)
+ live_delay(VERIFY_SECTOR_DATA_BYTE);
+ else
+ 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(!set_output(cur_live.data_reg)) {
+ live_delay(IDLE);
+ return;
+ }
+ cur_live.state = READ_SECTOR_DATA;
+ checkpoint();
+ break;
+
+ case SCAN_SECTOR_DATA_BYTE:
+ if(!scan_done)
+ {
+ UINT8 data = 0;
+ if(!get_input(&data)) {
+ live_delay(IDLE);
+ return;
+ }
+ if(cur_live.data_reg != 0xff)
+ {
+ switch(command[4] >> 6) {
+ case 0:
+ if(cur_live.data_reg != data)
+ scan_match = false;
+ break;
+ case 1:
+ if(cur_live.data_reg < data)
+ scan_match = false;
+ break;
+ case 2:
+ if(cur_live.data_reg > data)
+ scan_match = false;
+ break;
+ default:
+ scan_match = false;
+ break;
+ }
+ }
+ scan_len++;
+ if(scan_len == command[5]) {
+ if(scan_match) {
+ int slot = calc_sector_size(command[3] >> 5) - ((cur_live.bit_counter >> 4)-1);
+ scan_sec = cur_live.idbuf[2];
+ scan_cnt[0] = slot & 0x7f;
+ scan_cnt[1] = slot >> 9;
+ scan_done = true;
+ rr = command[4] & 0xc0 ? ERR_SMNE : ERR_SMEQ;
+ }
+ else
+ {
+ scan_match = true;
+ scan_len = 0;
+ }
+ }
+ }
+ cur_live.state = READ_SECTOR_DATA;
+ checkpoint();
+ break;
+
+ case VERIFY_SECTOR_DATA_BYTE:
+ 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(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(cur_live.byte_counter < 6)
+ live_write_fm(0x00);
+ else if(cur_live.byte_counter < 7) {
+ cur_live.crc = 0xffff;
+ live_write_raw(BIT(command[0], 2) ? 0xf56a : 0xf56f);
+ } else if(cur_live.byte_counter < 7+sector_size) {
+ UINT8 data = 0;
+ if(!get_input(&data)) {
+ live_delay(IDLE);
+ return;
+ }
+ live_write_fm(data);
+ }
+ 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+1)
+ 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(command[4]) {
+ if(cur_live.byte_counter < command[4])
+ live_write_fm(0xff);
+ else if(cur_live.byte_counter < (command[4] + 6))
+ live_write_fm(0x00);
+ else if(cur_live.byte_counter < (command[4] + 7))
+ live_write_raw(0xf77a);
+ else if(cur_live.byte_counter < (command[4] + command[5] + 7))
+ live_write_fm(0xff);
+ else {
+ cur_live.state = WRITE_TRACK_SECTOR;
+ cur_live.byte_counter = 0;
+ break;
+ }
+ } else {
+ if(cur_live.byte_counter < command[5])
+ 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 < 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) {
+ UINT8 data = 0;
+ if(!get_input(&data)) {
+ live_delay(IDLE);
+ return;
+ }
+ live_write_fm(data);
+ } 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(0xe5);
+ 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[2])
+ live_write_fm(0xff);
+ else {
+ cur_live.byte_counter = 0;
+ command[3] = (command[3] & 0xe0) | ((command[3] & 0x1f) - 1);
+ cur_live.state = command[3] & 0x1f ? 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:
+ 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).c_str(), cur_live.state);
+ return;
+ }
+ }
+}
+
+int i8271_device::check_command()
+{
+ switch(command[0] & 0x3f) {
+ case 0x00:
+ case 0x04:
+ return command_pos == 6 ? C_SCAN : C_INCOMPLETE;
+
+ case 0x0a:
+ case 0x0e:
+ return command_pos == 3 ? C_WRITE_DATA_SINGLE : C_INCOMPLETE;
+
+ case 0x0b:
+ case 0x0f:
+ return command_pos == 4 ? C_WRITE_DATA_MULTI : C_INCOMPLETE;
+
+ case 0x12:
+ case 0x16:
+ return command_pos == 3 ? C_READ_DATA_SINGLE : C_INCOMPLETE;
+
+ case 0x13:
+ case 0x17:
+ return command_pos == 4 ? C_READ_DATA_MULTI : C_INCOMPLETE;
+
+ case 0x1e:
+ return command_pos == 3 ? C_VERIFY_DATA_SINGLE : C_INCOMPLETE;
+
+ case 0x1f:
+ return command_pos == 4 ? C_VERIFY_DATA_MULTI : C_INCOMPLETE;
+
+ case 0x1b:
+ return command_pos == 4 ? C_READ_ID : C_INCOMPLETE;
+
+ case 0x23:
+ return command_pos == 6 ? C_FORMAT_TRACK : C_INCOMPLETE;
+
+ case 0x29:
+ return command_pos == 2 ? C_SEEK : C_INCOMPLETE;
+
+ case 0x2c:
+ return C_READ_DRIVE_STATUS;
+
+ case 0x35:
+ return command_pos == 5 ? C_SPECIFY : C_INCOMPLETE;
+
+ case 0x3a:
+ return command_pos == 3 ? C_WRITE_SPECIAL_REGISTER : C_INCOMPLETE;
+
+ case 0x3d:
+ return command_pos == 2 ? C_READ_SPECIAL_REGISTER : C_INCOMPLETE;
+
+ default:
+ return C_INVALID;
+ }
+}
+
+void i8271_device::start_command(int cmd)
+{
+ command_pos = 0;
+ main_phase = PHASE_EXEC;
+ switch(cmd) {
+ case C_READ_DATA_SINGLE:
+ command[3] = 1;
+ case C_READ_DATA_MULTI:
+ read_data_start(flopi[BIT(command[0], 7)]);
+ break;
+
+ case C_VERIFY_DATA_SINGLE:
+ command[3] = 1;
+ case C_VERIFY_DATA_MULTI:
+ verify_data_start(flopi[BIT(command[0], 7)]);
+ break;
+
+ case C_FORMAT_TRACK:
+ format_track_start(flopi[BIT(command[0], 7)]);
+ break;
+
+ case C_READ_ID:
+ read_id_start(flopi[BIT(command[0], 7)]);
+ break;
+
+ case C_SCAN:
+ scan_start(flopi[BIT(command[0], 7)]);
+ break;
+
+ case C_SEEK:
+ if(!command[1])
+ recalibrate_start(flopi[BIT(command[0], 7)]);
+ else
+ seek_start(flopi[BIT(command[0], 7)]);
+ break;
+
+ case C_READ_DRIVE_STATUS:
+ {
+ floppy_info &fi = flopi[BIT(command[0], 7)];
+ rr = (get_ready(1) ? 0x40 : 0) | (fi.dev->idx_r() ? 0x10 : 0) | (fi.dev->wpt_r() ? 0 : 8) |
+ (get_ready(0) ? 4 : 0) | (fi.dev->trk00_r() ? 1 : 0);
+ flopi[0].ready = true;
+ flopi[1].ready = true;
+ main_phase = PHASE_IDLE;
+ break;
+ }
+ case C_SPECIFY:
+ logerror("%s: command specify %02x %02x %02x %02x\n",
+ tag(), command[1],
+ command[2], command[3], command[4]);
+ switch(command[1]) {
+ case 0x0d:
+ srate = command[2];
+ hset = command[3];
+ icnt = command[4] >> 4;
+ hload = command[4] & 0xf;
+ break;
+ case 0x10:
+ case 0x18:
+ {
+ floppy_info &fi = flopi[BIT(command[1], 3)];
+ fi.badtrack[0] = command[2];
+ fi.badtrack[1] = command[3];
+ fi.pcn = command[4];
+ }
+ }
+ main_phase = PHASE_IDLE;
+ break;
+
+ case C_WRITE_DATA_SINGLE:
+ command[3] = 1;
+ case C_WRITE_DATA_MULTI:
+ write_data_start(flopi[BIT(command[0], 7)]);
+ break;
+
+ case C_READ_SPECIAL_REGISTER:
+ switch(command[1] & 0x3f) {
+ case 0x06:
+ rr = scan_sec;
+ break;
+ case 0x10:
+ case 0x11:
+ rr = flopi[0].badtrack[BIT(command[1], 0)];
+ break;
+ case 0x12:
+ rr = flopi[0].pcn;
+ break;
+ case 0x13:
+ rr = scan_cnt[0];
+ break;
+ case 0x14:
+ rr = scan_cnt[1];
+ break;
+ case 0x17:
+ rr = moder;
+ break;
+ case 0x18:
+ case 0x19:
+ rr = flopi[1].badtrack[BIT(command[1], 0)];
+ break;
+ case 0x1a:
+ rr = flopi[1].pcn;
+ break;
+ case 0x22: {
+ floppy_info &fi = flopi[BIT(command[0], 7)];
+ rr = (get_ready(1) ? 0x40 : 0) | (fi.dev->idx_r() ? 0x10 : 0) | (fi.dev->wpt_r() ? 0 : 8) |
+ (get_ready(0) ? 4 : 0) | (fi.dev->trk00_r() ? 1 : 0);
+ break;
+ }
+ case 0x23:
+ rr = (command[0] & 0xc0) | oport;
+ break;
+ default:
+ rr = 0;
+ break;
+ }
+ main_phase = PHASE_IDLE;
+ break;
+
+ case C_WRITE_SPECIAL_REGISTER:
+ switch(command[1]) {
+ case 0x06:
+ scan_sec = command[2];
+ break;
+ case 0x10:
+ case 0x11:
+ flopi[0].badtrack[BIT(command[1], 0)] = command[2];
+ break;
+ case 0x12:
+ flopi[0].pcn = command[2];
+ break;
+ case 0x13:
+ scan_cnt[0] = command[2];
+ break;
+ case 0x14:
+ scan_cnt[1] = command[2];
+ break;
+ case 0x17:
+ moder = command[2] | 0xc0;
+ break;
+ case 0x18:
+ case 0x19:
+ flopi[1].badtrack[BIT(command[1], 0)] = command[2];
+ break;
+ case 0x1a:
+ flopi[1].pcn = command[2];
+ break;
+ case 0x22:
+ break;
+ case 0x23: {
+ oport = command[2] & ~0xc0;
+ floppy_info &fi = flopi[BIT(command[0], 7)];
+ fi.dev->dir_w(BIT(command[2], 2));
+ fi.dev->stp_w(BIT(command[2], 1));
+ opt_cb(BIT(command[2], 5));
+ hdl_cb(BIT(command[2], 3));
+ break;
+ }
+ }
+ main_phase = PHASE_IDLE;
+ break;
+
+ default:
+ fprintf(stderr, "start command %d\n", cmd);
+ exit(1);
+ }
+}
+
+void i8271_device::command_end(floppy_info &fi, bool data_completion)
+{
+ logerror("%s: command done (%s) - %02x\n", tag(), data_completion ? "data" : "seek", rr);
+ fi.main_state = fi.sub_state = IDLE;
+ main_phase = PHASE_RESULT;
+ set_irq(true);
+}
+
+void i8271_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 = 255;
+ seek_continue(fi);
+}
+
+void i8271_device::seek_start(floppy_info &fi)
+{
+ logerror("%s: command seek %d\n", tag(), command[1]);
+ fi.main_state = SEEK;
+ fi.sub_state = SEEK_WAIT_STEP_TIME_DONE;
+ fi.dir = fi.pcn > command[1] ? 1 : 0;
+ seek_continue(fi);
+}
+
+void i8271_device::delay_cycles(emu_timer *tm, int cycles)
+{
+ tm->adjust(attotime::from_double(double(cycles)/cur_rate));
+}
+
+void i8271_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);
+
+ do {
+ if(fi.pcn > command[1])
+ fi.pcn--;
+ else
+ fi.pcn++;
+ } while((fi.pcn == fi.badtrack[0]) || (fi.pcn == fi.badtrack[1]));
+ fi.sub_state = SEEK_WAIT_STEP_TIME;
+ delay_cycles(fi.tm, 500*srate);
+ 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) {
+ rr = ERR_T0NF;
+ command_end(fi, false);
+ return;
+ }
+ break;
+ case SEEK:
+ done = fi.pcn == command[1];
+ break;
+ }
+ if(done) {
+ rr = ERR_NONE;
+ command_end(fi, false);
+ return;
+ }
+ fi.sub_state = SEEK_MOVE;
+ break;
+ }
+ }
+ }
+}
+
+void i8271_device::read_data_start(floppy_info &fi)
+{
+ fi.main_state = READ_DATA;
+ fi.sub_state = HEAD_LOAD_DONE;
+
+ logerror("%s: command read%s data%s cmd=%02x crn=(%d, %d, %d) len=%02x rate=%d\n",
+ tag(),
+ command[0] & 0x04 ? " deleted" : "",
+ command[0] & 0x01 ? " multi" : "",
+ command[0],
+ command[1],
+ command[2],
+ calc_sector_size(command[3] >> 5),
+ command[3] & 0x1f,
+ cur_rate);
+
+ rr = ERR_NONE;
+ fi.ready = get_ready(BIT(command[0], 7));
+
+ if(!fi.ready) {
+ rr = ERR_NR;
+ fi.sub_state = COMMAND_DONE;
+ read_data_continue(fi);
+ return;
+ }
+
+ read_data_continue(fi);
+}
+
+void i8271_device::scan_start(floppy_info &fi)
+{
+ fi.main_state = SCAN_DATA;
+ fi.sub_state = HEAD_LOAD_DONE;
+
+ logerror("%s: command scan%s data%s cmd=%02x crn=(%d, %d, %d) len=%02x rate=%d\n",
+ tag(),
+ command[0] & 0x04 ? " deleted" : "",
+ command[0] & 0x01 ? " multi" : "",
+ command[0],
+ command[1],
+ command[2],
+ calc_sector_size(command[3] >> 5),
+ command[3] & 0x1f,
+ cur_rate);
+
+ rr = ERR_NONE;
+ scan_done = false;
+ scan_len = 0;
+ scan_match = true;
+ fi.ready = get_ready(BIT(command[0], 7));
+
+ if(!fi.ready) {
+ rr = ERR_NR;
+ fi.sub_state = COMMAND_DONE;
+ read_data_continue(fi);
+ return;
+ }
+ read_data_continue(fi);
+}
+
+void i8271_device::verify_data_start(floppy_info &fi)
+{
+ fi.main_state = VERIFY_DATA;
+ fi.sub_state = HEAD_LOAD_DONE;
+
+ logerror("%s: command verify%s data%s cmd=%02x crn=(%d, %d, %d) len=%02x rate=%d\n",
+ tag(),
+ command[0] & 0x04 ? " deleted" : "",
+ command[0] & 0x01 ? " multi" : "",
+ command[0],
+ command[1],
+ command[2],
+ calc_sector_size(command[3] >> 5),
+ command[3] & 0x1f,
+ cur_rate);
+
+ rr = ERR_NONE;
+ fi.ready = get_ready(BIT(command[0], 7));
+
+ if(!fi.ready) {
+ rr = ERR_NR;
+ fi.sub_state = COMMAND_DONE;
+ read_data_continue(fi);
+ return;
+ }
+ read_data_continue(fi);
+}
+
+void i8271_device::read_data_continue(floppy_info &fi)
+{
+ for(;;) {
+ switch(fi.sub_state) {
+ case HEAD_LOAD_DONE:
+ if(fi.pcn == command[1]) {
+ fi.sub_state = SEEK_DONE;
+ break;
+ }
+ if(fi.dev) {
+ fi.dev->dir_w(fi.pcn > command[1] ? 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*srate);
+ return;
+
+ case SEEK_WAIT_STEP_TIME:
+ return;
+
+ case SEEK_WAIT_STEP_TIME_DONE:
+ do {
+ if(fi.pcn > command[1])
+ fi.pcn--;
+ else
+ fi.pcn++;
+ } while((fi.pcn == fi.badtrack[0]) || (fi.pcn == fi.badtrack[1]));
+ 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) {
+ rr = ERR_ICRC;
+ fi.sub_state = COMMAND_DONE;
+ break;
+ }
+ if(!sector_matches()) {
+ if(cur_live.idbuf[0] != command[1]) {
+ rr = ERR_NF;
+ 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]);
+ fi.sub_state = SECTOR_READ;
+ live_start(fi, SEARCH_ADDRESS_MARK_DATA);
+ return;
+
+ case SCAN_ID_FAILED:
+ rr = ERR_NF;
+ fi.sub_state = COMMAND_DONE;
+ break;
+
+ case SECTOR_READ: {
+ if(cur_live.crc) {
+ rr = ERR_DCRC;
+ fi.sub_state = COMMAND_DONE;
+ break;
+ }
+ bool done = rr || (!(command[0] & 1) && (fi.main_state != SCAN_DATA));
+ if(!done)
+ {
+ command[3] = (command[3] & 0xe0) | ((command[3] & 0x1f) - 1);
+ if(command[3] & 0x1f)
+ command[2]++;
+ else
+ done = true;
+ }
+ if(!done) {
+ fi.sub_state = SEEK_DONE;
+ break;
+ }
+ fi.sub_state = COMMAND_DONE;
+ break;
+ }
+
+ case COMMAND_DONE:
+ command_end(fi, true);
+ return;
+
+ default:
+ logerror("%s: read sector unknown sub-state %d\n", ttsn().c_str(), fi.sub_state);
+ return;
+ }
+ }
+}
+
+void i8271_device::write_data_start(floppy_info &fi)
+{
+ fi.main_state = WRITE_DATA;
+ fi.sub_state = HEAD_LOAD_DONE;
+ logerror("%s: command write%s data%s cmd=%02x crn=(%d, %d, %d) len=%02x rate=%d\n",
+ tag(),
+ command[0] & 0x04 ? " deleted" : "",
+ command[0] & 0x01 ? " multi" : "",
+ command[0],
+ command[1],
+ command[2],
+ calc_sector_size(command[3] >> 5),
+ command[3] & 0x1f,
+ cur_rate);
+
+ rr = ERR_NONE;
+ fi.ready = get_ready(BIT(command[0], 7));
+
+ if(!fi.ready) {
+ rr = ERR_NR;
+ fi.sub_state = COMMAND_DONE;
+ write_data_continue(fi);
+ return;
+ }
+
+ write_data_continue(fi);
+}
+
+void i8271_device::write_data_continue(floppy_info &fi)
+{
+ for(;;) {
+ switch(fi.sub_state) {
+ case HEAD_LOAD_DONE:
+ if(fi.pcn == command[1]) {
+ fi.sub_state = SEEK_DONE;
+ break;
+ }
+ if(fi.dev) {
+ fi.dev->dir_w(fi.pcn > command[1] ? 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*srate);
+ return;
+
+ case SEEK_WAIT_STEP_TIME:
+ return;
+
+ case SEEK_WAIT_STEP_TIME_DONE:
+ do {
+ if(fi.pcn > command[1])
+ fi.pcn--;
+ else
+ fi.pcn++;
+ } while((fi.pcn == fi.badtrack[0]) || (fi.pcn == fi.badtrack[1]));
+ 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(!sector_matches()) {
+ live_start(fi, SEARCH_ADDRESS_MARK_HEADER);
+ return;
+ }
+ if(cur_live.crc) {
+ rr = ERR_ICRC;
+ fi.sub_state = COMMAND_DONE;
+ break;
+ }
+ sector_size = calc_sector_size(cur_live.idbuf[3]);
+ fi.sub_state = SECTOR_WRITTEN;
+ set_drq(true);
+ live_start(fi, WRITE_SECTOR_SKIP_GAP2);
+ return;
+
+ case SCAN_ID_FAILED:
+ rr = ERR_NF;
+ fi.sub_state = COMMAND_DONE;
+ break;
+
+ case SECTOR_WRITTEN: {
+ bool done = rr || !(command[0] & 1);
+ if(!done)
+ {
+ command[3] = (command[3] & 0xe0) | ((command[3] & 0x1f) - 1);
+ if(command[3] & 0x1f)
+ command[2]++;
+ else
+ done = true;
+ }
+ if(!done) {
+ fi.sub_state = HEAD_LOAD_DONE;
+ break;
+ }
+ fi.sub_state = COMMAND_DONE;
+ break;
+ }
+
+ case COMMAND_DONE:
+ command_end(fi, true);
+ return;
+
+ default:
+ logerror("%s: write sector unknown sub-state %d\n", ttsn().c_str(), fi.sub_state);
+ return;
+ }
+ }
+}
+
+int i8271_device::calc_sector_size(UINT8 size)
+{
+ return size > 7 ? 16384 : 128 << size;
+}
+
+void i8271_device::format_track_start(floppy_info &fi)
+{
+ fi.main_state = FORMAT_TRACK;
+ fi.sub_state = HEAD_LOAD_DONE;
+
+ logerror("%s: command format track c=%02x n=%02x sc=%02x gap3=%02x gap5=%02x gap1=%02x\n",
+ tag(),
+ command[1], command[3] >> 5, command[3] & 0x1f, command[2], command[4], command[5]);
+
+ rr = ERR_NONE;
+
+ fi.ready = get_ready(BIT(command[0], 7));
+
+ if(!fi.ready) {
+ rr = ERR_NR;
+ fi.sub_state = TRACK_DONE;
+ format_track_continue(fi);
+ return;
+ }
+ sector_size = calc_sector_size(command[3] >> 5);
+
+ format_track_continue(fi);
+}
+
+void i8271_device::format_track_continue(floppy_info &fi)
+{
+ for(;;) {
+ switch(fi.sub_state) {
+ case HEAD_LOAD_DONE:
+ if(fi.pcn == command[1]) {
+ fi.sub_state = WAIT_INDEX;
+ break;
+ }
+ if(fi.dev) {
+ fi.dev->dir_w(fi.pcn > command[1] ? 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*srate);
+ return;
+
+ case SEEK_WAIT_STEP_TIME:
+ return;
+
+ case SEEK_WAIT_STEP_TIME_DONE:
+ do {
+ if(fi.pcn > command[1])
+ fi.pcn--;
+ else
+ fi.pcn++;
+ } while((fi.pcn == fi.badtrack[0]) || (fi.pcn == fi.badtrack[1]));
+ fi.sub_state = HEAD_LOAD_DONE;
+ break;
+
+ case SEEK_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());
+ set_drq(true);
+ live_start(fi, WRITE_TRACK_PRE_SECTORS);
+ return;
+
+ case TRACK_DONE:
+ command_end(fi, true);
+ return;
+
+ default:
+ logerror("%s: format track unknown sub-state %d\n", ttsn().c_str(), fi.sub_state);
+ return;
+ }
+ }
+}
+
+void i8271_device::read_id_start(floppy_info &fi)
+{
+ fi.main_state = READ_ID;
+ fi.sub_state = HEAD_LOAD_DONE;
+
+ logerror("%s: command read id, rate=%d\n",
+ tag(),
+ cur_rate);
+
+ rr = ERR_NONE;
+
+ for(int i=0; i<4; i++)
+ cur_live.idbuf[i] = 0x00;
+
+ fi.ready = get_ready(command[1] & 3);
+
+ if(!fi.ready) {
+ rr = ERR_NR;
+ fi.sub_state = COMMAND_DONE;
+ read_id_continue(fi);
+ return;
+ }
+
+ read_id_continue(fi);
+}
+
+void i8271_device::read_id_continue(floppy_info &fi)
+{
+ for(;;) {
+ switch(fi.sub_state) {
+ case HEAD_LOAD_DONE:
+ if(fi.pcn == command[1]) {
+ fi.sub_state = SEEK_DONE;
+ break;
+ }
+ if(fi.dev) {
+ fi.dev->dir_w(fi.pcn > command[1] ? 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*srate);
+ return;
+
+ case SEEK_WAIT_STEP_TIME:
+ return;
+
+ case SEEK_WAIT_STEP_TIME_DONE:
+ do {
+ if(fi.pcn > command[1])
+ fi.pcn--;
+ else
+ fi.pcn++;
+ } while((fi.pcn == fi.badtrack[0]) || (fi.pcn == fi.badtrack[1]));
+ 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) {
+ rr = ERR_ICRC;
+ fi.sub_state = COMMAND_DONE;
+ break;
+ }
+ if(!(command[3]--)) {
+ fi.counter = 0;
+ fi.sub_state = SCAN_ID;
+ }
+ else
+ fi.sub_state = COMMAND_DONE;
+ break;
+
+ case SCAN_ID_FAILED:
+ if(rr != ERR_DMA)
+ rr = ERR_NF;
+ fi.sub_state = COMMAND_DONE;
+ break;
+
+ case COMMAND_DONE:
+ command_end(fi, true);
+ return;
+
+ default:
+ logerror("%s: read id unknown sub-state %d\n", ttsn().c_str(), fi.sub_state);
+ return;
+ }
+ }
+}
+
+std::string i8271_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;
+}
+
+std::string i8271_device::ttsn()
+{
+ return tts(machine().time());
+}
+
+void i8271_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ 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 i8271_device::index_callback(floppy_image_device *floppy, int state)
+{
+ for(int fid=0; fid<2; 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().c_str(), fi.sub_state);
+ break;
+ }
+
+ general_continue(fi);
+ }
+}
+
+
+void i8271_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:
+ case SCAN_DATA:
+ case VERIFY_DATA:
+ read_data_continue(fi);
+ break;
+
+ case WRITE_DATA:
+ write_data_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().c_str(), fi.main_state);
+ break;
+ }
+}
+
+bool i8271_device::read_one_bit(const 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 i8271_device::write_one_bit(const 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 i8271_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 i8271_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 i8271_device::sector_matches() const
+{
+ if(0)
+ logerror("%s: matching %02x %02x %02x - %02x %02x %02x\n", tag(),
+ cur_live.idbuf[0], cur_live.idbuf[2], cur_live.idbuf[3],
+ command[1], command[2], command[3] >> 5);
+ return
+ cur_live.idbuf[0] == command[1] &&
+ cur_live.idbuf[2] == command[2] &&
+ cur_live.idbuf[3] == (command[3] >> 5);
+}