Esempio n. 1
0
void cart_unset_alarms(void)
{
    alarm_unset(cartridge_freeze_alarm);
    alarm_unset(cartridge_nmi_alarm);
    cart_freeze_alarm_time = CLOCK_MAX;
    cart_nmi_alarm_time = CLOCK_MAX;
}
Esempio n. 2
0
/*! \brief reset the ACIA */
void myacia_reset(void)
{
    DEBUG_LOG_MESSAGE((acia.log, "reset_myacia"));

    acia.rs232_status_lines = 0;
    rs232drv_set_status(acia.fd, acia.rs232_status_lines);

    acia.cmd = ACIA_CMD_DEFAULT_AFTER_HW_RESET;
    acia.ctrl = ACIA_CTRL_DEFAULT_AFTER_HW_RESET;
    acia.ectrl = T232_ECTRL_DEFAULT_AFTER_HW_RESET;

    set_acia_ticks();

    acia.status = ACIA_SR_DEFAULT_AFTER_HW_RESET;
    acia.in_tx = ACIA_TX_STATE_NO_TRANSMIT;

    if (acia.fd >= 0) {
        rs232drv_close(acia.fd);
    }
    acia.fd = -1;

    if (acia.alarm_tx) {
        alarm_unset(acia.alarm_tx);
    }
    if (acia.alarm_rx) {
        alarm_unset(acia.alarm_rx);
    }
    acia.alarm_active_tx = 0;
    acia.alarm_active_rx = 0;

    acia_set_int(acia.irq_type, acia.int_num, IK_NONE);
    acia.irq = 0;
}
Esempio n. 3
0
void ted_snapshot_prepare(void)
{
    ted.fetch_clk = CLOCK_MAX;
    alarm_unset(ted.raster_fetch_alarm);
    ted.draw_clk = CLOCK_MAX;
    alarm_unset(ted.raster_draw_alarm);
    ted.raster_irq_clk = CLOCK_MAX;
    alarm_unset(ted.raster_irq_alarm);
}
/* Make sure all the VIC-II alarms are removed.  This just makes it easier to
   write functions for loading snapshot modules in other video chips without
   caring that the VIC-II alarms are dispatched when they really shouldn't
   be.  */
void vicii_snapshot_prepare(void)
{
    vicii.fetch_clk = CLOCK_MAX;
    alarm_unset(vicii.raster_fetch_alarm);
    vicii.draw_clk = CLOCK_MAX;
    alarm_unset(vicii.raster_draw_alarm);
    vicii.raster_irq_clk = CLOCK_MAX;
    alarm_unset(vicii.raster_irq_alarm);
}
Esempio n. 5
0
/*
 * according to Rockwell, all internal registers are cleared, except
 * for the Timer (1 and 2, counter and latches) and the shift register.
 */
void viacore_reset(via_context_t *via_context)
{
    int i;

    /* clear registers */
    for (i = 0; i < 4; i++) {
        via_context->via[i] = 0;
    }
    for (i = 4; i < 10; i++) {
        via_context->via[i] = 0xff;
    }
    for (i = 11; i < 16; i++) {
        via_context->via[i] = 0;
    }

    via_context->tal = 0xffff;
    via_context->t2cl = 0xff;
    via_context->t2ch = 0xff;
    via_context->tau = *(via_context->clk_ptr);
    via_context->tbu = *(via_context->clk_ptr);

    via_context->read_clk = 0;

    via_context->ier = 0;
    via_context->ifr = 0;

    via_context->pb7 = 0;
    via_context->pb7x = 0;
    via_context->pb7o = 0;
    via_context->pb7xx = 0;
    via_context->pb7sx = 0;

    via_context->shift_state = 0;

    /* disable vice interrupts */
    via_context->tai = 0;
    via_context->tbi = 0;
    alarm_unset(via_context->t1_alarm);
    alarm_unset(via_context->t2_alarm);
    update_myviairq(via_context);

    via_context->oldpa = 0xff;
    via_context->oldpb = 0xff;

    via_context->ca2_state = 1;
    via_context->cb2_state = 1;
    (via_context->set_ca2)(via_context, via_context->ca2_state);      /* input = high */
    (via_context->set_cb2)(via_context, via_context->cb2_state);      /* input = high */

    if (via_context && via_context->reset) {
        (via_context->reset)(via_context);
    }

    via_context->enabled = 1;
}
Esempio n. 6
0
static void viacore_intt1(CLOCK offset, void *data)
{
    via_context_t *via_context = (via_context_t *)data;

#ifdef MYVIA_TIMER_DEBUG
    if (app_resources.debugFlag)
        log_message(via_context->log, "myvia timer A interrupt");
#endif

    if (!(via_context->via[VIA_ACR] & 0x40)) {     /* one-shot mode */
#ifdef MYVIA_TIMER_DEBUG
        log_message(via_context->log,
                    "MYVIA Timer A interrupt -- one-shot mode: next int won't happen");
#endif
        alarm_unset(via_context->t1_alarm);
        via_context->tai = 0;
    } else {                    /* continuous mode */
        /* load counter with latch value */
        via_context->tai += via_context->tal + 2;
        alarm_set(via_context->t1_alarm, via_context->tai);
    }
    via_context->ifr |= VIA_IM_T1;
    update_myviairq(via_context);

    /* TODO: toggle PB7? */
    /*(viaier & VIA_IM_T1) ? 1:0; */
}
Esempio n. 7
0
static void datasette_internal_reset(void)
{
    int mode = current_image ? current_image->mode : notape_mode;

    DBG(("datasette_internal_reset (mode:%d)", mode));

    if (mode == DATASETTE_CONTROL_START ||
        mode == DATASETTE_CONTROL_FORWARD ||
        mode == DATASETTE_CONTROL_REWIND) {
        alarm_unset(datasette_alarm);
        datasette_alarm_pending = 0;
    }
    datasette_control(DATASETTE_CONTROL_STOP);
    if (current_image != NULL) {
        if (!autostart_ignore_reset) {
            tap_seek_start(current_image);
        }
        current_image->cycle_counter = 0;
    }
    datasette_counter_offset = 0;
    datasette_long_gap_pending = 0;
    datasette_long_gap_elapsed = 0;
    datasette_last_direction = 0;
    motor_stop_clk = 0;
    datasette_update_ui_counter();
    fullwave = 0;
}
Esempio n. 8
0
static void midi_suspend(void)
{
#ifdef DEBUG
    log_message(midi_log, "suspend");
#endif
    status = MIDI_STATUS_DEFAULT;
    intx = 0;

    if (fd_in >= 0) {
        mididrv_in_close();
    }
    fd_in = -1;

    if (fd_out >= 0) {
        mididrv_out_close();
    }
    fd_out = -1;

    alarm_unset(midi_alarm);
    alarm_active = 0;
    intx = 0;

    midi_set_int(midi_irq, midi_int_num, 0);
    irq = 0;
}
Esempio n. 9
0
static void epyxfastload_alarm_handler(CLOCK offset, void *data)
{
    /* Virtual capacitor charged, disable rom */
    alarm_unset(epyxrom_alarm);
    epyxrom_alarm_time = CLOCK_MAX;
    cart_config_changed_slotmain(2, 2, CMODE_READ);
}
Esempio n. 10
0
void riotcore_reset(riot_context_t *riot_context)
{
    riot_context->riot_io[0] = 0;
    riot_context->riot_io[1] = 0;
    riot_context->riot_io[2] = 0;
    riot_context->riot_io[3] = 0;

    riot_context->read_clk = 0;

    alarm_unset(riot_context->alarm);

    riot_context->old_pa = 0xff;
    riot_context->old_pb = 0xff;

    riot_context->r_edgectrl = 0;
    riot_context->r_irqfl = 0;
    riot_context->r_irqline = 0;
    riot_context->set_irq(riot_context, 0, *(riot_context->clk_ptr));

    riot_context->r_write_clk = *(riot_context->clk_ptr);
    riot_context->r_N = 255;
    riot_context->r_divider = 1;
    riot_context->r_irqen = 0;

    riot_context->reset(riot_context);

    riot_context->enabled = 1;
}
Esempio n. 11
0
static void ata_change_power_mode(ata_drive_t *drv, BYTE value)
{
    if (drv->power == 0x00 && value != 0x00) {
        drv->busy |= 1;
        alarm_set(drv->spindle_alarm, maincpu_clk + drv->spinup_time);
    }
    if (drv->power != 0x00 && value == 0x00) {
        drv->busy |= 1;
        alarm_set(drv->spindle_alarm, maincpu_clk + drv->spindown_time);
    }
    if (value == 0x00) {
        drv->standby = 0;
    } else {
        drv->standby = drv->standby_max;
    }
    if (value != 0xff) {
        drv->pos = 0;
    }
    if (drv->standby) {
        alarm_set(drv->standby_alarm, maincpu_clk + 5 * drv->cycles_1s);
    } else {
        alarm_unset(drv->standby_alarm);
    }
    drv->power = value;
}
Esempio n. 12
0
static void viacore_intt1(CLOCK offset, void *data)
{
    CLOCK rclk;
    via_context_t *via_context = (via_context_t *)data;

    rclk = *(via_context->clk_ptr) - offset;


#ifdef MYVIA_TIMER_DEBUG
    if (app_resources.debugFlag)
        log_message(via_context->log, "myvia timer A interrupt");
#endif

    if (!(via_context->via[VIA_ACR] & 0x40)) {     /* one-shot mode */
#ifdef MYVIA_TIMER_DEBUG
        log_message(via_context->log,
                    "MYVIA Timer A interrupt -- one-shot mode: next int won't happen");
#endif
        alarm_unset(via_context->t1_alarm);
        via_context->tai = 0;
    } else {                    /* continuous mode */
        /* load counter with latch value */
        via_context->tai += via_context->tal + 2;
        alarm_set(via_context->t1_alarm, via_context->tai);
        
        /* Let tau also keep up with the cpu clock
           this should avoid "% (via_context->tal + 2)" case */
        via_context->tau += via_context->tal + 2;
    }
    via_context->ifr |= VIA_IM_T1;
    update_myviairq_rclk(via_context, rclk);

    /* TODO: toggle PB7? */
    /*(viaier & VIA_IM_T1) ? 1:0; */
}
Esempio n. 13
0
static void kbdbuf_flush_alarm_triggered(CLOCK offset, void *data)
{
    alarm_unset(kbdbuf_flush_alarm);
    kbdbuf_flush_alarm_time = 0;

    tokbdbuffer(13);
    removefromqueue();
}
Esempio n. 14
0
static void epyxfastload_trigger_access(void)
{
    /* Discharge virtual capacitor, enable rom */
    alarm_unset(epyxrom_alarm);
    epyxrom_alarm_time = maincpu_clk + EPYX_ROM_CYCLES;
    alarm_set(epyxrom_alarm, epyxrom_alarm_time);
    cart_config_changed_slotmain(0, 0, CMODE_READ);
}
Esempio n. 15
0
static void ted_timer_t3_store_high(BYTE value)
{
    alarm_unset(ted_t3_alarm);
    t3_value = (t3_start = (t3_start & 0x00ff) | (value << 8)) << 1;
    alarm_set(ted_t3_alarm, maincpu_clk
              + (t3_start == 0 ? 65536 : t3_start) * 2);
    t3_last_restart = maincpu_clk;
    t3_running = 1;
}
Esempio n. 16
0
static void joystick_latch_handler(CLOCK offset, void *data)
{
    alarm_unset(joystick_alarm);
    alarm_context_update_next_pending(joystick_alarm->context);

    joystick_latch_matrix(offset);

    joystick_event_record();
}
Esempio n. 17
0
static void ted_timer_t1_store_low(BYTE value)
{
    alarm_unset(ted_t1_alarm);
    if (t1_running) {
        t1_value -= maincpu_clk - t1_last_restart;
        t1_last_restart = maincpu_clk;
    }
    t1_value = (t1_start = (t1_start & 0xff00) | value) << 1;
    t1_running = 0;
}
Esempio n. 18
0
static void riotcore_int_riot(CLOCK offset, void *data)
{
    riot_context_t *riot_context = (riot_context_t *)data;

/*  CLOCK rclk = *(riot_context->clk_ptr) - offset; */

    alarm_unset(riot_context->alarm);

    update_irq(riot_context, (BYTE)(riot_context->r_irqfl | 0x80));
}
Esempio n. 19
0
static void datasette_rewind(void)
{
    if (current_image->mode == DATASETTE_CONTROL_START
        || current_image->mode == DATASETTE_CONTROL_FORWARD) {
        alarm_unset(datasette_alarm);
        datasette_alarm_pending = 0;
    }
    alarm_set(datasette_alarm, maincpu_clk + 1000);
    datasette_alarm_pending = 1;
}
Esempio n. 20
0
void fdc_reset(unsigned int fnum, unsigned int drive_type)
{
    fdc_t *thefdc = &fdc[fnum];
    int drive1 = mk_drive1(fnum);
    disk_image_t *saved_image0,
                 *saved_image1;

#ifdef FDC_DEBUG
    log_message(fdc_log, "fdc_reset: drive %d type=%d\n",fnum, drive_type);
#endif

    saved_image0 = fdc[fnum].realimage;
    saved_image1 = NULL;

    /* detach disk images */
    if (thefdc->image) {
        thefdc->wps_change = 0;
        fdc_detach_image(thefdc->image, fnum + 8);
    }
    if (thefdc->num_drives == 2) {
        saved_image1 = fdc[drive1].realimage;
        if (fdc[drive1].image) {
            fdc[drive1].wps_change = 0;
            fdc_detach_image(fdc[drive1].image, drive1 + 8);
        }
    }

    if (drive_check_old(drive_type)) {
        thefdc->drive_type = drive_type;
        thefdc->num_drives = is_drive1(fnum) ? 1 :
                             drive_check_dual(drive_type) ? 2 : 1;
        thefdc->fdc_state = FDC_RESET0;
        alarm_set(thefdc->fdc_alarm, drive_clk[fnum] + 20);
    } else {
        thefdc->drive_type = DRIVE_TYPE_NONE;
        alarm_unset(thefdc->fdc_alarm);
        thefdc->fdc_state = FDC_UNUSED;
        thefdc->num_drives = 0;
    }

    /* re-attach disk images */
    if (saved_image0) {
#ifdef FDC_DEBUG
        printf("ieee/fdc.c:fdc_reset dev %d type %d drive 0 re-attach image %p (drive: %p)\n", fnum+8, drive_type, saved_image0, drive_context[fnum]->drive->image);
#endif
        fdc_attach_image(saved_image0, fnum + 8);
    }
    if (saved_image1) {
#ifdef FDC_DEBUG
        printf("ieee/fdc.c:fdc_reset dev %d type %d drive 1 re-attach image %p (drive: %p)\n", fnum+8, drive_type, saved_image0, drive_context[drive1]->drive->image);
#endif
        fdc_attach_image(saved_image1, drive1 + 8);
    }
}
Esempio n. 21
0
/* called by the Freeze Button alarm */
static void cart_freeze_alarm_triggered(CLOCK offset, void *data)
{
    DBG(("cart_freeze_alarm_triggered\n"));
    alarm_unset(cartridge_freeze_alarm);
    cart_freeze_alarm_time = CLOCK_MAX;

    if (cart_freeze_allowed()) {  /* c64carthooks.c */
        DBG(("cart_trigger_freeze delay 3 cycles\n"));
        maincpu_set_nmi(cartridge_int_num, IK_NMI);
        cart_nmi_alarm_time = maincpu_clk + 3;
        alarm_set(cartridge_nmi_alarm, cart_nmi_alarm_time);
    }
}
Esempio n. 22
0
static void datasette_rewind(void)
{
    int mode = current_image ? current_image->mode : notape_mode;

    DBG(("datasette_rewind"));

    if (mode == DATASETTE_CONTROL_START ||
        mode == DATASETTE_CONTROL_FORWARD) {
        alarm_unset(datasette_alarm);
        datasette_alarm_pending = 0;
    }
    alarm_set(datasette_alarm, maincpu_clk + 1000);
    datasette_alarm_pending = 1;
}
Esempio n. 23
0
static void viacore_intt2(CLOCK offset, void *data)
{
    via_context_t *via_context = (via_context_t *)data;

#ifdef MYVIA_TIMER_DEBUG
    if (app_resources.debugFlag)
        log_message(via_context->log, "MYVIA timer B interrupt.");
#endif

    alarm_unset(via_context->t2_alarm);       /*int_clk[I_MYVIAT2] = 0; */
    via_context->tbi = 0;

    via_context->ifr |= VIA_IM_T2;
    update_myviairq(via_context);
}
Esempio n. 24
0
/* timer reset */
void ciat_reset(ciat_t *state, CLOCK cclk)
{
    CIAT_LOGIN(("%s reset: cclk=%d",state->name, cclk));

    /* FIXME? */
    state->clk = cclk;
    state->alarmclk = CLOCK_MAX;
    state->cnt = 0xffff;
    state->latch = 0xffff;
    state->state = 0;

    alarm_unset(state->alarm);

    CIAT_LOGOUT((""));
}
Esempio n. 25
0
static void cap_trigger_access(void)
{
    alarm_unset(stardos_alarm);
    stardos_alarm_time = CLOCK_MAX;

    if (cap_voltage < CHARGEMAXIDLE) {
        stardos_alarm_time = maincpu_clk + 1;
        alarm_set(stardos_alarm, stardos_alarm_time);
    }
#ifdef DBGSTARDOSCC
    else if (dbglast != 4) {
        DBG(("STARDOS: charged (idle) (%d)\n", cap_voltage));
        dbglast = 4;
    }
#endif
}
Esempio n. 26
0
/*! \internal \brief Set the handshake (output) lines to the status of the cmd register

 This function sets the physical handshake lines accordingly
 to the state of the emulated ACIA cmd register.
*/
static void acia_set_handshake_lines(void)
{
    switch (acia.cmd & ACIA_CMD_BITS_TRANSMITTER_MASK) {
    case ACIA_CMD_BITS_TRANSMITTER_NO_RTS:
        /* unset RTS, we are NOT ready to receive */
        acia.rs232_status_lines &= ~RS232_HSO_RTS;
        if (acia.alarm_active_rx) {
            /* diable RX alarm */
            acia.alarm_active_rx = 0;
            alarm_unset(acia.alarm_rx);
        }
        break;

    case ACIA_CMD_BITS_TRANSMITTER_BREAK:
    /* FALL THROUGH */
    case ACIA_CMD_BITS_TRANSMITTER_TX_WITH_IRQ:
    /* FALL THROUGH */
    case ACIA_CMD_BITS_TRANSMITTER_TX_WO_IRQ:
        /* set RTS, we are ready to receive */
        acia.rs232_status_lines |= RS232_HSO_RTS;

        if (!acia.alarm_active_rx) {
            /* enable RX alarm */
            acia.alarm_active_rx = 1;
            set_acia_ticks();
        }
        break;
    }

    if (acia.cmd & ACIA_CMD_BITS_DTR_ENABLE_RECV_AND_IRQ) {
        /* set DTR, we are ready to transmit and receive */
        acia.rs232_status_lines |= RS232_HSO_DTR;
    } else {
        /* unset DTR, we are NOT ready to receive or to transmit */
        acia.rs232_status_lines &= ~RS232_HSO_DTR;
    }
    /* set the RTS and the DTR status */
    rs232drv_set_status(acia.fd, acia.rs232_status_lines);
}
Esempio n. 27
0
void alarm_destroy(alarm_t *alarm)
{
    alarm_context_t *context;

    if (alarm == NULL)
        return;

    alarm_unset(alarm);

    context = alarm->context;

    if (alarm == context->alarms)
        context->alarms = alarm->next;

    if (alarm->next != NULL)
        alarm->next->prev = alarm->prev;
    if (alarm->prev != NULL)
        alarm->prev->next = alarm->next;

    lib_free(alarm->name);

    lib_free(alarm);
}
Esempio n. 28
0
/*! \internal \brief Transmit (TX) alarm function

 This function is called when the transmit alarm fires.
 It checks if there is any data to send. If there is some,
 this data is sent to the physical RS232 device.

 \param offset
   The clock offset this alarm is executed at.

   The current implementation of the emulation core does
   not allow to guarantee that the alarm will fire exactly
   at the time it was scheduled at. The offset tells the
   alarm function how many cycles have passed since the
   time the alarm was scheduled to fire. Thus, (myclk - offset)
   yiels the clock count which the alarm was scheduled to.

 \param data
   Additional data defined in the call to alarm_new().
   For the acia implementation, this is always NULL.

 \remark
   If we just transmitted a value, the alarm is re-scheduled for
   the time when the transmission has completed. This way, we
   ensure that we do not send out faster than a real ACIA could
   do.

 \todo
   If no transmit is in progress (in_tx == ACIA_TX_STATE_NO_TRANSMIT),
   it is not necessary to schedule a new alarm.
*/
static void int_acia_tx(CLOCK offset, void *data)
{
    DEBUG_VERBOSE_LOG_MESSAGE((acia.log, "int_acia_tx(offset=%ld, myclk=%d", offset, myclk));

    assert(data == NULL);

    if ((acia.in_tx == ACIA_TX_STATE_DR_WRITTEN) && (acia.fd >= 0)) {
        rs232drv_putc(acia.fd, acia.txdata);

        /* tell the status register that the transmit register is empty */
        acia.status |= ACIA_SR_BITS_TRANSMIT_DR_EMPTY;

        /* generate an interrupt if the ACIA was programmed to generate one */
        if ((acia.cmd & ACIA_CMD_BITS_TRANSMITTER_MASK) == ACIA_CMD_BITS_TRANSMITTER_TX_WITH_IRQ) {
            acia_set_int(acia.irq_type, acia.int_num, acia.irq_type);
            acia.irq = 1;
        }
    }

    if (acia.in_tx != ACIA_TX_STATE_NO_TRANSMIT) {
        /*
         * ACIA_TX_STATE_DR_WRITTEN is decremented to ACIA_TX_STATE_TX_STARTED
         * ACIA_TX_STATE_TX_STARTED is decremented to ACIA_TX_STATE_NO_TRANSMIT
         */
        acia.in_tx--;
    }

    if (acia.in_tx != ACIA_TX_STATE_NO_TRANSMIT) {
        /* re-schedule alarm */
        acia.alarm_clk_tx = myclk + acia.ticks;
        alarm_set(acia.alarm_tx, acia.alarm_clk_tx);
        acia.alarm_active_tx = 1;
    } else {
        alarm_unset(acia.alarm_tx);
        acia.alarm_active_tx = 0;
    }
}
Esempio n. 29
0
void vicii_irq_set_raster_line(unsigned int line)
{
    if (line == vicii.raster_irq_line && vicii.raster_irq_clk != CLOCK_MAX) {
        return;
    }

    if (line < (unsigned int)vicii.screen_height) {
        unsigned int current_line = VICII_RASTER_Y(maincpu_clk);

        vicii.raster_irq_clk = (VICII_LINE_START_CLK(maincpu_clk)
                                + VICII_RASTER_IRQ_DELAY - INTERRUPT_DELAY
                                + (vicii.cycles_per_line
                                   * (line - current_line)));
        /* Raster interrupts on line 0 are delayed by 1 cycle.  */
        if (line == 0) {
            vicii.raster_irq_clk++;
        }

        if (line <= current_line) {
            vicii.raster_irq_clk += (vicii.screen_height * vicii.cycles_per_line);
        }
        alarm_set(vicii.raster_irq_alarm, vicii.raster_irq_clk);
    } else {
        VICII_DEBUG_RASTER(("update_raster_irq(): "
                            "raster compare out of range ($%04X)!", line));
        vicii.raster_irq_clk = CLOCK_MAX;
        alarm_unset(vicii.raster_irq_alarm);
    }

    VICII_DEBUG_RASTER(("update_raster_irq(): "
                        "vicii.raster_irq_clk = %ul, "
                        "line = $%04X, "
                        "vicii.regs[0x1a] & 1 = %d",
                        vicii.raster_irq_clk, line, vicii.regs[0x1a] & 1));

    vicii.raster_irq_line = line;
}
Esempio n. 30
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);
    }
}