static void pc8477_result(pc8477_t *drv) { switch (drv->command) { case PC8477_CMD_SPECIFY: return; case PC8477_CMD_SENSE_INTERRUPT: drv->res[0] = drv->st[0]; drv->res[1] = drv->current->track; return; case PC8477_CMD_VERSION: drv->res[0] = 0x90; return; case PC8477_CMD_NSC: drv->res[0] = 0x72; return; case PC8477_CMD_SENSE_DRIVE_STATUS: drv->res[0] = drv->st[3] | 0x20 | (drv->is8477 ? 0x08 : 0) | (fdd_track0(drv->fdd) ? PC8477_ST3_TK0 : 0) | (fdd_write_protect(drv->fdd) ? PC8477_ST3_WP : 0); return; case PC8477_CMD_READ_ID: memcpy(drv->res, drv->st, 3); return; case PC8477_CMD_RECALIBRATE: return; case PC8477_CMD_SEEK: return; case PC8477_CMD_DUMPREG: drv->res[0] = drv->fdds[0].track; drv->res[1] = drv->fdds[1].track; drv->res[2] = drv->fdds[2].track; drv->res[3] = drv->fdds[3].track; drv->res[4] = (drv->step_rate << 4) | drv->motor_off_time; drv->res[5] = (drv->motor_on_time << 1) | drv->nodma; drv->res[6] = drv->sector; drv->res[7] = (drv->fdds[0].perpendicular ? 0x02 : 0); drv->res[7] |= (drv->fdds[1].perpendicular ? 0x04 : 0); drv->res[7] |= (drv->fdds[2].perpendicular ? 0x08 : 0); drv->res[7] |= (drv->fdds[3].perpendicular ? 0x10 : 0); /* TODO */ return; case PC8477_CMD_SET_TRACK: drv->res[0] = drv->current->track >> ((drv->cmd[1] & 4) ? 8 : 0); return; case PC8477_CMD_READ_DATA: case PC8477_CMD_WRITE_DATA: case PC8477_CMD_FORMAT_A_TRACK: memcpy(drv->res, drv->st, 3); memcpy(drv->res + 3, drv->cmd + 2, 4); return; default: drv->res[0] = drv->st[0]; } }
static void seek_alarm_handler(CLOCK offset, void *data) { pc8477_t *drv = (pc8477_t *)data; int i; for (i = 0; i < 4; i++) { if (drv->fdds[i].seek_pulses < 0) { if (fdd_track0(drv->fdds[i].fdd)) { continue; } fdd_seek_pulse(drv->fdds[i].fdd, 0); drv->fdds[i].seek_pulses++; drv->fdds[i].seeking = 1; if (drv->fdds[i].recalibrating && drv->fdds[i].seek_pulses == 0 && !fdd_track0(drv->fdds[i].fdd)) { drv->st[0] |= PC8477_ST0_EC; } break; } if (drv->fdds[i].seek_pulses > 0) { fdd_seek_pulse(drv->fdds[i].fdd, 1); drv->fdds[i].seek_pulses--; drv->fdds[i].seeking = 1; break; } } if (i == 4) { alarm_unset(drv->seek_alarm); drv->seeking_active = 0; drv->st[0] |= PC8477_ST0_SE; drv->irq = 1; } else { alarm_set(drv->seek_alarm, *drv->mycontext->clk_ptr + STEP_RATE); } }
/* 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); }