static int pc8477_micro_find_sync(pc8477_t *drv) { WORD w; while (*drv->mycontext->clk_ptr >= drv->clk + BYTE_RATE) { if (fdd_index_count(drv->fdd) > 1) { return -1; } drv->clk += BYTE_RATE; w = fdd_read(drv->fdd); switch (drv->sub_step) { case 0: /* zeros start */ if (w != 0) { break; } drv->sub_step++; break; case 1: /* zeros end */ if (w == 0) { break; } if (w != 0x1a1) { drv->sub_step = 0; break; } drv->sub_step++; break; case 2: /* sync end */ if (w == 0x1a1) { break; } drv->sub_step = 0; return w; } } return 0x200; }
static int pc8477_micro_readid(pc8477_t *drv) { BYTE b; while (*drv->mycontext->clk_ptr >= drv->clk + BYTE_RATE) { drv->clk += BYTE_RATE; b = (BYTE)fdd_read(drv->fdd); switch (drv->sub_step) { case 0: /* track */ drv->res[3] = b; drv->sub_step++; break; case 1: /* head */ drv->res[4] = b; drv->sub_step++; break; case 2: /* sector */ drv->res[5] = b; drv->sub_step++; break; case 3: /* size */ drv->res[6] = b; drv->sub_step++; break; case 4: /* crc */ drv->sub_step++; break; case 5: /* crc */ drv->st[1] &= ~PC8477_ST1_MA; return 0; } if (fdd_index_count(drv->fdd) > 1) { return -1; } } return 1; }
static pc8477_state_t pc8477_execute(pc8477_t *drv) { int res = -1; switch (drv->command) { case PC8477_CMD_SPECIFY: debug((pc8477_log, "SPECIFY %d, %d, %d, %d", drv->cmd[1] >> 4, drv->cmd[1] & 0xf, drv->cmd[2] >> 1, drv->cmd[2] & 1)); drv->step_rate = drv->cmd[1] >> 4; drv->motor_off_time = drv->cmd[1] & 0xf; drv->motor_on_time = drv->cmd[2] >> 1; drv->nodma = drv->cmd[2] & 1; return PC8477_WAIT; case PC8477_CMD_SENSE_INTERRUPT: if (!drv->irq) { break; } debug((pc8477_log, "SENSE INTERRUPT")); drv->irq = 0; drv->current->seeking = 0; /* TODO: Too early */ return PC8477_RESULT; case PC8477_CMD_VERSION: if (!drv->is8477) { break; } debug((pc8477_log, "VERSION")); return PC8477_RESULT; case PC8477_CMD_NSC: if (!drv->is8477) { break; } debug((pc8477_log, "NSC")); return PC8477_RESULT; case PC8477_CMD_SENSE_DRIVE_STATUS: debug((pc8477_log, "SENSE DRIVE STATUS #%d", drv->current->num)); return PC8477_RESULT; case PC8477_CMD_READ_ID: switch (drv->int_step) { case 0: debug((pc8477_log, "READ ID #%d", drv->current->num)); drv->st[1] |= PC8477_ST1_MA; drv->sub_step = 0; drv->int_step++; case 1: while (*drv->mycontext->clk_ptr >= drv->clk + BYTE_RATE) { res = pc8477_micro_find_sync(drv); if (res < 0) { drv->st[0] |= 0x40; return PC8477_RESULT; } if (res == 0xfe) { break; } } if (res != 0xfe) { break; } drv->sub_step = 0; drv->int_step++; case 2: res = pc8477_micro_readid(drv); if (res > 0) { break; } if (res < 0) { drv->st[0] |= 0x40; } return PC8477_RESULT; } return PC8477_EXEC; case PC8477_CMD_RECALIBRATE: debug((pc8477_log, "RECALIBRATE #%d", drv->current->num)); drv->current->seek_pulses = drv->is8477 ? -77 : -85; drv->current->track = 0; drv->current->recalibrating = 1; if (!drv->seeking_active) { alarm_set(drv->seek_alarm, *drv->mycontext->clk_ptr + STEP_RATE); drv->seeking_active = 1; } return PC8477_WAIT; case PC8477_CMD_SEEK: debug((pc8477_log, "SEEK #%d %d", drv->current->num, drv->cmd[2])); drv->current->seek_pulses = drv->cmd[2] - drv->current->track; drv->current->track = drv->cmd[2]; drv->current->recalibrating = 0; if (!drv->seeking_active) { alarm_set(drv->seek_alarm, *drv->mycontext->clk_ptr + STEP_RATE); drv->seeking_active = 1; } return PC8477_WAIT; case PC8477_CMD_DUMPREG: if (!drv->is8477) { break; } debug((pc8477_log, "DUMPREG")); return PC8477_RESULT; case PC8477_CMD_PERPENDICULAR_MODE: if (!drv->is8477) { break; } debug((pc8477_log, "PERPENDICULAR MODE %02x", drv->cmd[1])); if (drv->cmd[1] & 0x80) { for (res = 0; res < 4; res++) { drv->fdds[res].perpendicular = (drv->cmd[1] >> (2 + res)) & 1; } } return PC8477_WAIT; case PC8477_CMD_SET_TRACK: if ((drv->cmd[1] & 0xf8) != 0x30) { break; } debug((pc8477_log, "SET TRACK #%d %d", drv->current->num, drv->cmd[2])); if (drv->cmd[0] & 0x40) { if (drv->cmd[1] & 4) { drv->current->track = (drv->current->track & 0xff) | (drv->cmd[2] << 8); } else { drv->current->track = (drv->current->track & 0xff00) | drv->cmd[2]; } } return PC8477_RESULT; case PC8477_CMD_READ_DATA: while (*drv->mycontext->clk_ptr >= drv->clk + BYTE_RATE) { switch (drv->int_step) { case 0: debug((pc8477_log, "READ DATA #%d (%d/%d/%d)-%d %d", drv->current->num, drv->cmd[2], drv->cmd[3], drv->cmd[4], drv->cmd[6], 128 << drv->cmd[5])); drv->sector = drv->cmd[4]; drv->st[1] |= PC8477_ST1_MA; drv->sub_step = 0; drv->int_step++; case 1: res = pc8477_micro_find_sync(drv); if (res < 0) { drv->st[0] |= 0x40; return PC8477_RESULT; } if (res != 0xfe) { break; } drv->st[1] &= ~PC8477_ST1_MA; drv->st[1] |= PC8477_ST1_ND; drv->sub_step = 0; drv->int_step++; case 2: res = pc8477_micro_readid(drv); if (res > 0) { break; } if (res < 0) { drv->st[0] |= 0x40; return PC8477_RESULT; } if (0xff == drv->res[3]) { drv->st[2] = PC8477_ST2_BT; drv->st[0] |= 0x40; return PC8477_RESULT; } if (drv->cmd[2] != drv->res[3]) { drv->st[2] = PC8477_ST2_WT; drv->st[0] |= 0x40; return PC8477_RESULT; } if (drv->cmd[3] != drv->res[4] || drv->sector != drv->res[5] || drv->cmd[5] != drv->res[6]) { drv->sub_step = 0; drv->int_step = 1; break; } drv->byte_count = 128 << drv->res[6]; drv->sub_step = 0; drv->int_step++; case 3: res = pc8477_micro_find_sync(drv); if (res < 0) { drv->st[0] |= 0x40; return PC8477_RESULT; } if (res == 0x200) { break; } if (res == 0xf8) { drv->st[2] |= PC8477_ST2_CM; drv->st[0] |= 0x40; return PC8477_RESULT; } if (res != 0xfb) { drv->st[2] |= PC8477_ST2_MD; drv->st[0] |= 0x40; return PC8477_RESULT; } drv->st[1] &= ~PC8477_ST1_ND; drv->int_step++; break; case 4: drv->clk += BYTE_RATE; drv->fifo[drv->fifop2] = (BYTE)fdd_read(drv->fdd); drv->fifop2++; if (drv->fifop2 >= drv->fifo_size) { drv->fifop2 = 0; } if (drv->fifo_fill >= drv->fifo_size) { debug((pc8477_log, "Overrun")); drv->st[1] |= PC8477_ST1_OR; drv->st[0] |= 0x40; return PC8477_RESULT; } else { drv->fifo_fill++; } drv->byte_count--; if (drv->byte_count) { break; } drv->int_step++; case 5: if (drv->fifo_fill) { drv->clk += fdd_rotate(drv->fdd, (*drv->mycontext->clk_ptr - drv->clk) / BYTE_RATE) * BYTE_RATE; return PC8477_READ; } if (drv->cmd[6] != drv->sector) { drv->sector++; fdd_index_count_reset(drv->fdd); drv->sub_step = 0; drv->int_step = 1; break; } drv->st[1] |= PC8477_ST1_EOT; drv->st[0] |= 0x40; return PC8477_RESULT; } } return PC8477_READ; case PC8477_CMD_WRITE_DATA: while (*drv->mycontext->clk_ptr >= drv->clk + BYTE_RATE) { switch (drv->int_step) { case 0: debug((pc8477_log, "WRITE DATA #%d (%d/%d/%d)-%d %d", drv->current->num, drv->cmd[2], drv->cmd[3], drv->cmd[4], drv->cmd[6], 128 << drv->cmd[5])); drv->st[1] |= PC8477_ST1_MA; drv->sector = drv->cmd[4]; drv->sub_step = 0; drv->int_step++; case 1: res = pc8477_micro_find_sync(drv); if (res < 0) { drv->st[0] |= 0x40; return PC8477_RESULT; } if (res != 0xfe) { break; } drv->st[1] &= ~PC8477_ST1_MA; drv->st[1] |= PC8477_ST1_ND; drv->sub_step = 0; drv->int_step++; case 2: res = pc8477_micro_readid(drv); if (res > 0) { break; } if (res < 0) { drv->st[0] |= 0x40; return PC8477_RESULT; } if (0xff == drv->res[3]) { drv->st[2] = PC8477_ST2_BT; drv->st[0] |= 0x40; return PC8477_RESULT; } if (drv->cmd[2] != drv->res[3]) { drv->st[2] = PC8477_ST2_WT; drv->st[0] |= 0x40; return PC8477_RESULT; } if (fdd_write_protect(drv->fdd)) { drv->st[1] |= PC8477_ST1_NW; drv->st[0] |= 0x40; return PC8477_RESULT; } if (drv->cmd[3] != drv->res[4] || drv->sector != drv->res[5] || drv->cmd[5] != drv->res[6]) { drv->sub_step = 0; drv->int_step = 1; break; } drv->byte_count = 128 << drv->res[6]; drv->sub_step = 0; drv->int_step++; case 3: res = pc8477_micro_find_sync(drv); if (res < 0) { drv->st[0] |= 0x40; return PC8477_RESULT; } if (res == 0x200) { break; } if (res != 0xfb) { drv->st[2] |= 0x01; /* no data mark */ drv->st[0] |= 0x40; return PC8477_RESULT; } drv->st[1] &= ~PC8477_ST1_ND; drv->int_step++; break; case 4: if (drv->fifo_fill == 0) { debug((pc8477_log, "Underrun")); drv->st[1] |= PC8477_ST1_OR; drv->st[0] |= 0x40; return PC8477_RESULT; } fdd_write(drv->fdd, drv->fifo[drv->fifop2]); drv->clk += BYTE_RATE; drv->fifop2++; if (drv->fifop2 >= drv->fifo_size) { drv->fifop2 = 0; } drv->fifo_fill--; drv->byte_count--; if (drv->byte_count) { break; } drv->int_step++; case 5: if (drv->cmd[6] != drv->sector) { drv->sector++; fdd_index_count_reset(drv->fdd); drv->sub_step = 0; drv->int_step = 1; break; } drv->st[1] |= 0x80; /* end of track */ drv->st[0] |= 0x40; return PC8477_RESULT; } } return PC8477_WRITE; case PC8477_CMD_FORMAT_A_TRACK: while (*drv->mycontext->clk_ptr >= drv->clk + BYTE_RATE) { switch (drv->int_step) { case 0: debug((pc8477_log, "FORMAT TRACK #%d %d %d*%d %d %02x", drv->current->num, (drv->cmd[1] >> 2) & 1, 128 << drv->cmd[2], drv->cmd[3], drv->cmd[4], drv->cmd[5])); drv->sector = 0; drv->sub_step = 0; drv->int_step++; case 1: drv->clk += BYTE_RATE; fdd_read(drv->fdd); if (!fdd_index_count(drv->fdd)) { break; } if (fdd_write_protect(drv->fdd)) { drv->st[1] |= PC8477_ST1_NW; drv->st[0] |= 0x40; return PC8477_RESULT; } drv->int_step++; drv->byte_count = 80; break; case 2: fdd_write(drv->fdd, 0x4e); drv->clk += BYTE_RATE; drv->byte_count--; if (drv->byte_count) { break; } drv->byte_count = 12; drv->int_step++; break; case 3: fdd_write(drv->fdd, 0x00); drv->clk += BYTE_RATE; drv->byte_count--; if (drv->byte_count) { break; } drv->byte_count = 3; drv->int_step++; break; case 4: fdd_write(drv->fdd, 0x1a1); drv->clk += BYTE_RATE; drv->byte_count--; if (drv->byte_count) { break; } drv->int_step++; break; case 5: fdd_write(drv->fdd, 0xfc); drv->clk += BYTE_RATE; drv->byte_count = 50; drv->int_step++; break; case 6: fdd_write(drv->fdd, 0x4e); drv->clk += BYTE_RATE; drv->byte_count--; if (drv->byte_count) { break; } drv->byte_count = 12; drv->int_step++; break; case 7: fdd_write(drv->fdd, 0x00); drv->clk += BYTE_RATE; drv->byte_count--; if (drv->byte_count) { break; } drv->byte_count = 3; drv->int_step++; break; case 8: fdd_write(drv->fdd, 0x1a1); drv->clk += BYTE_RATE; drv->byte_count--; if (drv->byte_count) { break; } drv->int_step++; break; case 9: fdd_write(drv->fdd, 0xfe); drv->clk += BYTE_RATE; drv->byte_count = 4; drv->int_step++; break; case 10: if (drv->fifo_fill == 0) { debug((pc8477_log, "Underrun")); drv->st[1] |= PC8477_ST1_OR; drv->st[0] |= 0x40; return PC8477_RESULT; } fdd_write(drv->fdd, drv->fifo[drv->fifop2]); drv->clk += BYTE_RATE; drv->fifop2++; if (drv->fifop2 >= drv->fifo_size) { drv->fifop2 = 0; } drv->fifo_fill--; drv->byte_count--; if (drv->byte_count) { break; } drv->int_step++; break; case 11: fdd_write(drv->fdd, 0x00); drv->clk += BYTE_RATE; drv->int_step++; break; case 12: fdd_write(drv->fdd, 0x00); drv->clk += BYTE_RATE; drv->byte_count = (drv->rate == 1000 && drv->current->perpendicular) ? 41 : 22; drv->int_step++; break; case 13: fdd_write(drv->fdd, 0x4e); drv->clk += BYTE_RATE; drv->byte_count--; if (drv->byte_count) { break; } drv->byte_count = 12; drv->int_step++; break; case 14: fdd_write(drv->fdd, 0x00); drv->clk += BYTE_RATE; drv->byte_count--; if (drv->byte_count) { break; } drv->byte_count = 3; drv->int_step++; break; case 15: fdd_write(drv->fdd, 0x1a1); drv->clk += BYTE_RATE; drv->byte_count--; if (drv->byte_count) { break; } drv->int_step++; break; case 16: fdd_write(drv->fdd, 0xfb); drv->clk += BYTE_RATE; drv->byte_count = 128 << drv->cmd[2]; drv->int_step++; break; case 17: fdd_write(drv->fdd, drv->cmd[5]); drv->clk += BYTE_RATE; drv->byte_count--; if (drv->byte_count) { break; } drv->int_step++; break; case 18: fdd_write(drv->fdd, 0x00); drv->clk += BYTE_RATE; drv->int_step++; break; case 19: fdd_write(drv->fdd, 0x00); drv->clk += BYTE_RATE; drv->byte_count = drv->cmd[4]; drv->sector++; if (drv->sector < drv->cmd[3]) { drv->int_step = 6; break; } drv->int_step++; break; case 20: fdd_write(drv->fdd, 0x4e); drv->clk += BYTE_RATE; break; } if (fdd_index_count(drv->fdd) > 1) { drv->clk += fdd_rotate(drv->fdd, (*drv->mycontext->clk_ptr - drv->clk) / BYTE_RATE) * BYTE_RATE; drv->cmd[3] = drv->sector; drv->st[0] |= 0x40; return PC8477_RESULT; } } return PC8477_WRITE; default: break; } debug((pc8477_log, "invalid command %02x", drv->cmd[0])); drv->command = PC8477_CMD_INVALID; drv->st[0] = drv->st[3] | 0x80; /* invalid command */ drv->res_size = 1; return PC8477_RESULT; }
/* Execute microcode */ static void wd1770_execute(wd1770_t *drv) { int res; for (;; ) { switch (drv->type) { case -1: drv->status &= ~(WD_WP | WD_IP | WD_T0); drv->status |= fdd_index(drv->fdd) ? WD_IP : 0; drv->status |= fdd_track0(drv->fdd) ? WD_T0 : 0; drv->status |= fdd_write_protect(drv->fdd) ? WD_WP : 0; case 0: /* idle */ if (*drv->cpu_clk_ptr < drv->clk + PREPARE) { return; } drv->status &= ~WD_BSY; drv->clk += fdd_rotate(drv->fdd, (*drv->cpu_clk_ptr - drv->clk) / BYTE_RATE) * BYTE_RATE; if (fdd_index_count(drv->fdd) >= 10) { drv->status &= ~WD_MO; } if ((drv->cmd & WD_I2) && fdd_index_count(drv->fdd) != drv->tmp) { drv->irq = 1; drv->tmp = fdd_index_count(drv->fdd); } return; case 1: /* type 1 */ switch (drv->step) { case 0: if (*drv->cpu_clk_ptr < drv->clk + PREPARE) { return; } drv->clk += PREPARE; drv->status |= WD_BSY; drv->status &= ~(WD_CRC | WD_SE | WD_DRQ); drv->irq = 0; drv->step++; case 1: if ((drv->cmd & WD_H) || (drv->status & WD_MO)) { drv->status |= WD_MO; drv->step += 2; continue; } drv->status |= WD_MO; fdd_index_count_reset(drv->fdd); drv->step++; case 2: drv->clk += fdd_rotate(drv->fdd, (*drv->cpu_clk_ptr - drv->clk) / BYTE_RATE) * BYTE_RATE; if (fdd_index_count(drv->fdd) < 6) { return; } drv->step++; case 3: switch (drv->command) { case WD_STEP: break; case WD_STEP_IN: drv->direction = 1; break; case WD_STEP_OUT: drv->direction = 0; break; case WD_RESTORE: drv->track = 0xff; drv->data = 0x00; default: drv->step++; continue; } drv->step = (drv->cmd & WD_U) ? 5 : 6; continue; case 4: if (drv->data == drv->track) { drv->step = 8; continue; } drv->direction = (drv->data > drv->track); drv->step++; case 5: drv->track += drv->direction ? 1 : -1; drv->step++; case 6: if (fdd_track0(drv->fdd) && !drv->direction) { drv->track = 0; drv->step = 8; continue; } fdd_seek_pulse(drv->fdd, drv->direction); drv->step++; case 7: if (*drv->cpu_clk_ptr < drv->clk + STEP_RATE) { return; } drv->clk += STEP_RATE; if (drv->cmd < WD_STEP) { drv->step = 4; continue; } drv->step++; case 8: if (!(drv->cmd & WD_V)) { drv->type = -1; break; } drv->step++; case 9: if (*drv->cpu_clk_ptr < drv->clk + SETTLING) { return; } drv->clk += SETTLING; fdd_index_count_reset(drv->fdd); drv->sync = 0; drv->step++; case 10: if (fdd_index_count(drv->fdd) >= 6) { drv->status |= WD_SE; drv->type = -1; break; } if (*drv->cpu_clk_ptr < drv->clk + BYTE_RATE) { return; } drv->clk += BYTE_RATE; res = fdd_read(drv->fdd); if (!drv->dden || res != 0x1fe) { if (!drv->sync || res != 0xfe) { drv->sync = (res == 0x1a1); continue; } } drv->sync = 0; drv->crc = 0xb230; drv->byte_count = 6; drv->step++; case 11: if (*drv->cpu_clk_ptr < drv->clk + BYTE_RATE) { return; } drv->clk += BYTE_RATE; res = fdd_read(drv->fdd); if (drv->byte_count == 6 && res != drv->track) { drv->step--; continue; } drv->crc = fdd_crc(drv->crc, (BYTE)res); if (--drv->byte_count) { continue; } if (drv->crc) { drv->status |= WD_CRC; drv->step--; continue; } drv->status &= ~WD_CRC; drv->type = -1; break; } break; case 2: /* type 2 */ switch (drv->step) { case 0: if (*drv->cpu_clk_ptr < drv->clk + PREPARE) { return; } drv->clk += PREPARE; drv->status |= WD_BSY; drv->status &= ~(WD_DRQ | WD_LD | WD_RNF | WD_RT | WD_WP); drv->step++; case 1: if ((drv->cmd & WD_H) || (drv->status & WD_MO)) { drv->status |= WD_MO; drv->step += 2; continue; } drv->status |= WD_MO; fdd_index_count_reset(drv->fdd); drv->step++; case 2: drv->clk += fdd_rotate(drv->fdd, (*drv->cpu_clk_ptr - drv->clk) / BYTE_RATE) * BYTE_RATE; if (fdd_index_count(drv->fdd) < 6) { return; } drv->step++; case 3: if (!(drv->cmd & WD_E)) { drv->step += 2; continue; } drv->step++; case 4: if (*drv->cpu_clk_ptr < drv->clk + SETTLING) { return; } drv->clk += SETTLING; drv->step++; case 5: if (drv->command == WD_WRITE_SECTOR && fdd_write_protect(drv->fdd)) { drv->status |= WD_WP; drv->type = 0; break; } fdd_index_count_reset(drv->fdd); drv->sync = 0; drv->step++; case 6: if (fdd_index_count(drv->fdd) >= 5) { drv->status |= WD_RNF; drv->type = 0; break; } if (*drv->cpu_clk_ptr < drv->clk + BYTE_RATE) { return; } drv->clk += BYTE_RATE; res = fdd_read(drv->fdd); if (!drv->dden || res != 0x1fe) { if (!drv->sync || res != 0xfe) { drv->sync = (res == 0x1a1); continue; } } drv->sync = 0; drv->crc = 0xb230; drv->byte_count = 6; drv->step++; case 7: if (*drv->cpu_clk_ptr < drv->clk + BYTE_RATE) { return; } drv->clk += BYTE_RATE; res = fdd_read(drv->fdd); if (drv->byte_count == 6 && res != drv->track) { drv->step--; continue; } if (drv->byte_count == 4 && res != drv->sector) { drv->step--; continue; } if (drv->byte_count == 3) { drv->tmp = res; } drv->crc = fdd_crc(drv->crc, (BYTE)res); if (--drv->byte_count) { continue; } if (drv->crc) { drv->status |= WD_CRC; drv->step--; continue; } drv->status &= ~WD_CRC; drv->crc = 0xffff; if (drv->command == WD_WRITE_SECTOR) { drv->byte_count = 0; drv->step = 10; continue; } drv->byte_count = 43; drv->step++; case 8: if (*drv->cpu_clk_ptr < drv->clk + BYTE_RATE) { return; } if (!drv->byte_count--) { drv->step -= 2; continue; } drv->clk += BYTE_RATE; res = fdd_read(drv->fdd); if (!drv->dden || (res != 0x1fb && res != 0x1f8)) { if (!drv->sync || (res != 0xfb && res != 0xf8)) { if (!drv->sync) { drv->crc = 0xffff; } drv->crc = fdd_crc(drv->crc, (BYTE)res); drv->sync = (res == 0x1a1); continue; } } drv->crc = fdd_crc(drv->crc, (BYTE)res); drv->status |= ((res & 0xff) == 0xf8) ? WD_RT : 0; drv->byte_count = (128 << drv->tmp) + 2; drv->step++; case 9: if (*drv->cpu_clk_ptr < drv->clk + BYTE_RATE) { return; } drv->clk += BYTE_RATE; res = fdd_read(drv->fdd); if (drv->byte_count > 2) { drv->status |= (drv->status & WD_DRQ) ? WD_LD : WD_DRQ; drv->data = res; } drv->crc = fdd_crc(drv->crc, (BYTE)res); if (--drv->byte_count) { continue; } if (drv->crc) { drv->status |= WD_CRC; drv->type = 0; break; } if (drv->cmd & WD_M) { drv->sector++; drv->step = 5; continue; } drv->type = 0; break; case 10: if (*drv->cpu_clk_ptr < drv->clk + BYTE_RATE) { return; } drv->clk += BYTE_RATE; drv->byte_count++; drv->status |= (drv->byte_count == 2) ? WD_DRQ : 0; if (drv->byte_count == (2 + 9) && (drv->status & WD_DRQ)) { drv->status ^= WD_DRQ | WD_LD; drv->type = 0; break; } if (drv->byte_count <= (drv->dden ? 0 : 11) + 2 + 9) { fdd_read(drv->fdd); continue; } if (drv->byte_count <= (drv->dden ? 6 : (11 + 12)) + 2 + 9) { fdd_write(drv->fdd, 0); continue; } if (!drv->dden && drv->byte_count <= (11 + 12 + 2 + 9 + 3)) { fdd_write(drv->fdd, 0x1a1); drv->crc = fdd_crc(drv->crc, 0xa1); continue; } res = ((drv->cmd & WD_A) ? 0xf8 : 0xfb) | (drv->dden ? 0x100 : 0); fdd_write(drv->fdd, (BYTE)res); drv->crc = fdd_crc(drv->crc, (BYTE)res); drv->byte_count = (128 << drv->tmp) + 3; drv->step++; case 11: if (*drv->cpu_clk_ptr < drv->clk + BYTE_RATE) { return; } drv->clk += BYTE_RATE; switch (--drv->byte_count) { case 0: fdd_write(drv->fdd, 0xff); break; case 1: fdd_write(drv->fdd, (BYTE)(drv->crc & 0xff)); continue; case 2: fdd_write(drv->fdd, (BYTE)(drv->crc >> 8)); continue; default: drv->status |= (drv->status & WD_DRQ) ? WD_LD : WD_DRQ; drv->crc = fdd_crc(drv->crc, drv->data); fdd_write(drv->fdd, drv->data); drv->data = 0; continue; } if (drv->cmd & WD_M) { drv->sector++; drv->step = 5; continue; } drv->type = 0; break; } break; case 3: /* type 3 */ switch (drv->step) { case 0: if (*drv->cpu_clk_ptr < drv->clk + PREPARE) { return; } drv->clk += PREPARE; drv->status |= WD_BSY; drv->status &= ~(WD_DRQ | WD_LD | WD_RNF | WD_CRC); drv->step++; case 1: if ((drv->cmd & WD_H) || (drv->status & WD_MO)) { drv->status |= WD_MO; drv->step += 2; continue; } drv->status |= WD_MO; fdd_index_count_reset(drv->fdd); drv->step++; case 2: drv->clk += fdd_rotate(drv->fdd, (*drv->cpu_clk_ptr - drv->clk) / BYTE_RATE) * BYTE_RATE; if (fdd_index_count(drv->fdd) < 6) { return; } drv->step++; case 3: if (!(drv->cmd & WD_E)) { drv->step += 2; continue; } drv->step++; case 4: if (*drv->cpu_clk_ptr < drv->clk + SETTLING) { return; } drv->clk += SETTLING; drv->step++; case 5: fdd_index_count_reset(drv->fdd); drv->sync = 0; drv->step++; if (drv->command == WD_WRITE_TRACK) { if (fdd_write_protect(drv->fdd)) { drv->status |= WD_WP; drv->type = 0; break; } drv->status |= WD_DRQ; drv->byte_count = 3; drv->step = 9; continue; } if (drv->command != WD_READ_TRACK) { drv->step++; continue; } case 6: if (fdd_index_count(drv->fdd) < 1) { drv->clk += fdd_rotate(drv->fdd, (*drv->cpu_clk_ptr - drv->clk) / BYTE_RATE) * BYTE_RATE; return; } if (fdd_index_count(drv->fdd) > 1) { drv->type = 0; break; } if (*drv->cpu_clk_ptr < drv->clk + BYTE_RATE) { return; } drv->clk += BYTE_RATE; drv->data = (BYTE)fdd_read(drv->fdd); drv->status |= (drv->status & WD_DRQ) ? WD_LD : WD_DRQ; continue; case 7: if (fdd_index_count(drv->fdd) >= 6) { drv->status |= WD_RNF; drv->type = 0; break; } if (*drv->cpu_clk_ptr < drv->clk + BYTE_RATE) { return; } drv->clk += BYTE_RATE; res = fdd_read(drv->fdd); if (!drv->dden || res != 0x1fe) { if (!drv->sync || res != 0xfe) { drv->sync = (res == 0x1a1); continue; } } drv->crc = 0xb230; drv->byte_count = 6; drv->step++; case 8: if (*drv->cpu_clk_ptr < drv->clk + BYTE_RATE) { return; } drv->status |= (drv->status & WD_DRQ) ? WD_LD : WD_DRQ; drv->clk += BYTE_RATE; drv->data = (BYTE)fdd_read(drv->fdd); if (drv->byte_count == 6) { drv->sector = drv->data; } drv->crc = fdd_crc(drv->crc, drv->data); if (--drv->byte_count) { continue; } drv->status |= drv->crc ? WD_CRC : 0; drv->type = 0; break; case 9: if (*drv->cpu_clk_ptr < drv->clk + BYTE_RATE) { return; } drv->clk += BYTE_RATE; fdd_read(drv->fdd); if (--drv->byte_count) { continue; } if (drv->status & WD_DRQ) { drv->status ^= WD_DRQ | WD_LD; drv->type = 0; break; } drv->byte_count = 0; drv->tmp = 0; drv->step++; case 10: if (fdd_index_count(drv->fdd) < 1) { drv->clk += fdd_rotate(drv->fdd, (*drv->cpu_clk_ptr - drv->clk) / BYTE_RATE) * BYTE_RATE; return; } if (fdd_index_count(drv->fdd) > 1) { drv->status &= ~WD_DRQ; drv->type = 0; break; } if (*drv->cpu_clk_ptr < drv->clk + BYTE_RATE) { return; } drv->clk += BYTE_RATE; res = drv->data; if (drv->byte_count) { fdd_write(drv->fdd, (BYTE)(drv->crc & 0xff)); drv->byte_count--; } else { drv->status |= (drv->status & WD_DRQ) ? WD_LD : WD_DRQ; if (drv->dden) { switch (res) { case 0xf7: drv->byte_count = 1; res = drv->crc >> 8; drv->tmp = 0; break; case 0xf8: case 0xf9: case 0xfa: case 0xfb: case 0xfe: if (!drv->tmp) { drv->crc = 0xffff; drv->tmp = 1; } case 0xfc: res |= 0x100; } } else { switch (res) { case 0xf5: res = 0x1a1; if (!drv->tmp) { drv->crc = 0xffff; drv->tmp = 1; } break; case 0xf6: res = 0x1c2; break; case 0xf7: drv->byte_count = 1; res = drv->crc >> 8; drv->tmp = 0; break; } } if (drv->tmp) { drv->crc = fdd_crc(drv->crc, (BYTE)res); } fdd_write(drv->fdd, (BYTE)res); drv->data = 0; } continue; } break; case 4: /* type 4 */ if (*drv->cpu_clk_ptr < drv->clk + PREPARE) { return; } drv->clk += PREPARE; drv->status &= WD_BSY; if (drv->cmd & WD_I3) { drv->irq = 1; } fdd_index_count_reset(drv->fdd); drv->tmp = fdd_index_count(drv->fdd); drv->type = (drv->status & WD_BSY) ? 0 : -1; continue; } drv->cmd = 0; drv->irq = 1; fdd_index_count_reset(drv->fdd); }