Exemplo n.º 1
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);
    }
}
Exemplo n.º 2
0
/* 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);
    }