Ejemplo n.º 1
0
static int
wd_fdc_spinup( wd_fdc *f, libspectrum_byte b )
{
  libspectrum_dword delay = 0;
  fdd_t *d = f->current_drive;

  if( f->state != WD_FDC_STATE_SEEK && ( b & 0x04 ) )
    delay = 30;

  if( f->type == WD1770 || f->type == WD1772 ) {

    if( !( f->status_register & WD_FDC_SR_MOTORON ) ) {
      f->status_register |= WD_FDC_SR_MOTORON;
      fdd_motoron( d, 1 );
      if( !( b & 0x08 ) )
        delay += 6 * 200;
    }
  } else {			/* WD1773/FD1793/WD2797 */
    event_remove_type( motor_off_event );
    if( f->state == WD_FDC_STATE_SEEK ) {
      if( b & 0x08 ) {
	f->head_load = 1;
        if( f->flags & WD_FLAG_BETA128 )
          fdd_motoron( d, 1 );
        else
	  fdd_head_load( d, 1 );
      } else if( !( b & 0x04 ) ) {	/* HLD reset only if V flag == 0 too */
	f->head_load = 0;
        if( !( f->flags & WD_FLAG_NOHLT ) && f->hlt_time > 0 ) f->hlt = 0;		/* reset the trigger */
        if( f->flags & WD_FLAG_BETA128 )
          fdd_motoron( d, 0 );
        else
	  fdd_head_load( d, 0 );
      }
      return 0;
    } else {
      f->head_load = 1;
      if( f->flags & WD_FLAG_BETA128 )
        fdd_motoron( d, 1 );
      else
        fdd_head_load( d, 1 );
      if( f->hlt_time > 0 )
        delay += f->hlt_time;
    }
  }

  /* For Type III commands on WD2797 */
  if( f->type == WD2797 && ( b & 0xc0 ) == 0xc0 && ( b & 0x30 ) != 0x10 )
    fdd_set_head( d, b & 0x02 ? 1 : 0 );

  if( delay ) {
    event_remove_type( fdc_event );
    event_add_with_data( tstates + delay *
    		    machine_current->timings.processor_speed / 1000,
			fdc_event, f );
    return 1;
  }
  return 0;
}
Ejemplo n.º 2
0
static int
wd_fdc_spinup( wd_fdc *f, libspectrum_byte b )
{
  libspectrum_dword delay = 0;

  if( f->state != WD_FDC_STATE_SEEK && ( b & 0x04 ) )
    delay = 30;

  if( f->type == WD1770 || f->type == WD1772 ) {
    if( !( b & 0x08 ) &&
	!( f->status_register & WD_FDC_SR_MOTORON ) ) {
      f->status_register |= WD_FDC_SR_MOTORON;
      fdd_motoron( &f->current_drive->fdd, 1 );
      statusbar_update( 1 );
      delay += 6 * 200;
    }
  } else {			/* WD1773/FD1793 */
    event_remove_type( motor_off_event );
    if( f->state == WD_FDC_STATE_SEEK ) {
      if( b & 0x08 ) {
	f->head_load = 1;
        if( f->flags & WD_FLAG_BETA128 )
          fdd_motoron( &f->current_drive->fdd, 1 );
        else
	  fdd_head_load( &f->current_drive->fdd, 1 );
	statusbar_update( 1 );
      } else {
	f->head_load = 0;
        if( f->hlt_time > 0 ) f->hlt = 0;		/* reset the trigger */
        if( f->flags & WD_FLAG_BETA128 )
          fdd_motoron( &f->current_drive->fdd, 0 );
        else
	  fdd_head_load( &f->current_drive->fdd, 0 );
	statusbar_update( 0 );
      }
      return 0;
    } else {
      f->head_load = 1;
      if( f->flags & WD_FLAG_BETA128 )
        fdd_motoron( &f->current_drive->fdd, 1 );
      else
        fdd_head_load( &f->current_drive->fdd, 1 );
      statusbar_update( 1 );
      if( f->hlt_time > 0 )
        delay += f->hlt_time;
    }
  }
  if( delay ) {
    event_remove_type( fdc_event );
    event_add_with_data( tstates + delay * 
    		    machine_current->timings.processor_speed / 1000,
			fdc_event, f );
    return 1;
  }
  return 0;
}
Ejemplo n.º 3
0
static int
tape_play( int autoplay )
{
  if( !libspectrum_tape_present( tape ) ) return 1;
  
  /* Otherwise, start the tape going */
  tape_playing = 1;
  tape_autoplay = autoplay;
  tape_microphone = 0;

  event_remove_type( tape_mic_off_event );

  /* Update the status bar */
  ui_statusbar_update( UI_STATUSBAR_ITEM_TAPE, UI_STATUSBAR_STATE_ACTIVE );

  /* If we're fastloading, turn sound off */
  if( settings_current.fastload ) sound_pause();

  loader_tape_play();

  event_add( tstates + next_tape_edge_tstates, tape_edge_event );
  next_tape_edge_tstates = 0;

  debugger_event( play_event );

  return 0;
}
Ejemplo n.º 4
0
static void
head_load( upd_fdc *f )
{
  event_remove_type( head_event );
  if( f->head_load ) {		/* head already loaded */
    if( f->cmd->id == UPD_CMD_READ_DATA || f->cmd->id == UPD_CMD_SCAN )
      start_read_data( f );
    else if( f->cmd->id == UPD_CMD_READ_ID )
      start_read_id( f );
    else if( f->cmd->id == UPD_CMD_READ_DIAG ) {
      fdd_wait_index_hole( f->current_drive );		/* start reading from index hole */
      start_read_diag( f );
    } else if( f->cmd->id == UPD_CMD_WRITE_DATA )
      start_write_data( f );
    else if( f->cmd->id == UPD_CMD_WRITE_ID ) {
      fdd_wait_index_hole( f->current_drive );		/* start writing from index hole */
      start_write_id( f );
    }
  } else {
    fdd_head_load( f->current_drive, 1 );
    f->head_load = 1;
    event_add_with_data( tstates + f->hld_time * 
			 machine_current->timings.processor_speed / 1000,
			 fdc_event, f );
  }
}
Ejemplo n.º 5
0
int
tape_stop( void )
{
  if( tape_playing ) {

    tape_playing = 0;
    ui_statusbar_update( UI_STATUSBAR_ITEM_TAPE, UI_STATUSBAR_STATE_INACTIVE );
    loader_tape_stop();

    /* If we were fastloading, sound was off, so turn it back on, and
       reset the speed counter */
    if( settings_current.fastload ) {
      sound_unpause();
      timer_estimate_reset();
    }

    tape_save_next_edge();
    event_remove_type( tape_edge_event );

    /* Turn off any lingering MIC level in a second (some loaders like Alkatraz
       seem to check the MIC level soon after loading is finished, presumably as
       a copy protection check */
    event_add( tstates + machine_current->timings.tstates_per_frame,
               tape_mic_off_event );
  }

  if( stop_event != -1 ) debugger_event( stop_event );

  return 0;
}
Ejemplo n.º 6
0
static int playback_frame( void )
{
  int error, finished;
  libspectrum_snap *snap;

  error = libspectrum_rzx_playback_frame( rzx, &finished, &snap );
  if( error ) return rzx_stop_playback( 0 );

  if( finished ) {
    ui_error( UI_ERROR_INFO, "Finished RZX playback" );
    return rzx_stop_playback( 0 );
  }

  /* Move the RZX sentinel back out to 79000 tstates; the addition of
     the frame length is because everything is reduced by that in
     event_frame() */
  event_remove_type( sentinel_event );
  event_add( RZX_SENTINEL_TIME + tstates, sentinel_event );

  if( snap ) {
    error = snapshot_copy_from( snap );
    if( error ) return rzx_stop_playback( 0 );
  }

  /* If we've got another frame to do, fetch the new instruction count and
     continue */
  rzx_instruction_count = libspectrum_rzx_instructions( rzx );
  counter_reset();

  return 0;
}
Ejemplo n.º 7
0
static int
start_playback( libspectrum_rzx *rzx )
{
  int error;
  libspectrum_snap *snap;

  error = libspectrum_rzx_start_playback( rzx, 0, &snap );
  if( error ) return error;

  if( snap ) {
    error = snapshot_copy_from( snap );
    if( error ) return error;
  }

  /* End of frame will now be generated by the RZX code */
  event_remove_type( spectrum_frame_event );

  /* Add a sentinel event to prevent tstates overrun (bug #1057471) */
  event_add( RZX_SENTINEL_TIME, sentinel_event );

  tstates = libspectrum_rzx_tstates( rzx );
  rzx_instruction_count = libspectrum_rzx_instructions( rzx );
  rzx_playback = 1;
  counter_reset();

  ui_menu_activate( UI_MENU_ITEM_RECORDING, 1 );
  ui_menu_activate( UI_MENU_ITEM_RECORDING_ROLLBACK, 0 );

  return 0;
}
Ejemplo n.º 8
0
static void
start_read_diag( upd_fdc *f )
{
  int i;
  
  if( !f->read_id ) {
    f->rev = 2;
    f->read_id = 1;
  }
  if( f->rev ) {
    i = f->current_drive->disk.i >= f->current_drive->disk.bpt ?
    	0 : f->current_drive->disk.i;			/* start position */
    if( read_id( f ) != 2 )
      f->rev = 0;
    i = f->current_drive->disk.bpt ? 
      ( f->current_drive->disk.i - i ) * 200 / f->current_drive->disk.bpt : 200;
    if( i > 0 ) {
      event_add_with_data( tstates + i *		/* i * 1/20 revolution */
			 machine_current->timings.processor_speed / 1000,
			 fdc_event, f );
      return;
    }
  }
  f->read_id = 0;
  if( f->id_mark == UPD_FDC_AM_NONE ) {
    f->status_register[0] |= UPD_FDC_ST0_INT_ABNORM;
    f->status_register[1] |= UPD_FDC_ST1_EOF_CYLINDER;
    goto abort_read_diag;
  }
  if( f->id_track != f->data_register[1] || f->id_sector != f->data_register[3] || 
    f->data_register[2] != f->id_head ) {
    f->status_register[1] |= UPD_FDC_ST1_NO_DATA;
  }

  if( f->id_track != f->data_register[1] ) {		/*FIXME UPD765 set it always? */
    f->status_register[2] |= UPD_FDC_ST2_WRONG_CYLINDER;
    if( f->id_track == 0xff )
      f->status_register[2] |= UPD_FDC_ST2_BAD_CYLINDER;
  }

  if( read_datamark( f ) > 0 ) {	/* not found */
    f->status_register[0] |= UPD_FDC_ST0_INT_ABNORM;
    goto abort_read_diag;
  }

  f->main_status |= UPD_FDC_MAIN_DATAREQ | UPD_FDC_MAIN_DATA_READ;
  f->data_offset = 0;
  event_remove_type( timeout_event );
  event_add_with_data( tstates + 4 *			/* 2 revolution: 2 * 200 / 1000  */
		       machine_current->timings.processor_speed / 10,
		       timeout_event, f );
  return;

abort_read_diag:
    f->state = UPD_FDC_STATE_RES;	/* end of execution phase */
    f->cycle = f->cmd->res_length;
    f->main_status &= ~UPD_FDC_MAIN_EXECUTION;
    f->intrq = UPD_INTRQ_RESULT;
    cmd_result( f );
}
Ejemplo n.º 9
0
static void
wd_fdc_seek_verify( wd_fdc *f )
{
  fdd_t *d = f->current_drive;

  event_remove_type( fdc_event );
  if( f->type == WD1773 || f->type == FD1793 || f->type == WD2797 ) {
    if( !f->hlt ) {
      event_add_with_data( tstates + 5 * 			/* sample every 5 ms */
		    machine_current->timings.processor_speed / 1000,
			fdc_event, f );
      return;
    }
    if( f->head_load )
      f->status_register |= WD_FDC_SR_SPINUP;
			/* when set, it indicates head is loaded and enganged.
			   This bit is logical "and" of HLD and "HLT" signals.  */
  }

  if( d->tr00 )
    f->status_register |= WD_FDC_SR_LOST;
  else
    f->status_register &= ~WD_FDC_SR_LOST;

  f->rev = 5;
  f->id_mark = WD_FDC_AM_NONE;
  wd_fdc_seek_verify_read_id( f );
}
Ejemplo n.º 10
0
static void
wd_fdc_seek_verify_read_id( wd_fdc *f )
{
  fdd_t *d = f->current_drive;
  int i;
  f->read_id = 1;

  event_remove_type( fdc_event );
  if( f->id_mark == WD_FDC_AM_NONE ) {
    while( f->rev ) {
      i = d->disk.i >= d->disk.bpt ? 0 : d->disk.i;	/* start position */
      if( !read_id( f ) ) {
	if( f->id_track != f->track_register ) {
	  f->status_register |= WD_FDC_SR_RNF;
	}
      } else
        f->id_mark = WD_FDC_AM_NONE;
      i = d->disk.bpt ? ( d->disk.i - i ) * 200 / d->disk.bpt : 200;
      if( i > 0 ) {
        event_add_with_data( tstates + i *		/* i * 1/20 revolution */
			   machine_current->timings.processor_speed / 1000,
			   fdc_event, f );
        return;
      } else if( f->id_mark != WD_FDC_AM_NONE )
        break;
    }
    if( f->id_mark == WD_FDC_AM_NONE )
      f->status_register |= WD_FDC_SR_RNF;
  }
  f->state = WD_FDC_STATE_NONE;
  f->status_register &= ~WD_FDC_SR_BUSY;
  wd_fdc_set_intrq( f );
  f->read_id = 0;
}
Ejemplo n.º 11
0
static void
wd_fdc_type_ii( wd_fdc *f )
{
  libspectrum_byte b = f->command_register;
  wd_fdc_drive *d = f->current_drive;

  event_remove_type( fdc_event );
  if( f->type == WD1773 || f->type == FD1793 ) {
    if( !f->hlt ) {
      event_add_with_data( tstates + 5 * 
    		    machine_current->timings.processor_speed / 1000,
			fdc_event, f );
      return;
    }
  }

  if( f->state == WD_FDC_STATE_WRITE ) {
    if( d->fdd.wrprot ) {
      f->status_register |= WD_FDC_SR_WRPROT;
      f->status_register &= ~WD_FDC_SR_BUSY;
      f->state = WD_FDC_STATE_NONE;
      wd_fdc_set_intrq( f );
      return;
    }
    f->status_register &= ~WD_FDC_SR_WRPROT;
  }

  f->data_multisector = b & 0x10 ? 1 : 0;
  f->rev = 5;
  f->id_mark = WD_FDC_AM_NONE;
  wd_fdc_type_ii_seek( f );
}
Ejemplo n.º 12
0
int rzx_stop_playback( int add_interrupt )
{
  libspectrum_error libspec_error;

  rzx_playback = 0;
  if( settings_current.movie_stop_after_rzx ) movie_stop();

  ui_menu_activate( UI_MENU_ITEM_RECORDING, 0 );
  ui_menu_activate( UI_MENU_ITEM_RECORDING_ROLLBACK, 0 );

  event_remove_type( sentinel_event );

  /* We've now finished with the RZX file, so add an end of frame
     event if we've been requested to do so; we don't if we just run
     out of frames, as this occurs just before a normal end of frame
     and everything works normally as rzx_playback is now zero again */
  if( add_interrupt ) {

    event_add( machine_current->timings.tstates_per_frame,
               spectrum_frame_event );

    /* We're no longer doing RZX playback, so tstates now be <= the
       normal frame count */
    if( tstates > machine_current->timings.tstates_per_frame )
      tstates = machine_current->timings.tstates_per_frame;

  } else {

    /* Ensure that tstates will be zero after it is reduced in
       spectrum_frame() */
    tstates = machine_current->timings.tstates_per_frame;

  }

  libspec_error = libspectrum_rzx_free( rzx );
  if( libspec_error != LIBSPECTRUM_ERROR_NONE ) return libspec_error;

  debugger_event( end_event );

  return 0;
}  
Ejemplo n.º 13
0
int tape_stop( void )
{
  if( tape_playing ) {

    tape_playing = 0;
    ui_statusbar_update( UI_STATUSBAR_ITEM_TAPE, UI_STATUSBAR_STATE_INACTIVE );
    loader_tape_stop();

    /* If we were fastloading, sound was off, so turn it back on, and
       reset the speed counter */
    if( settings_current.fastload ) {
      sound_unpause();
      timer_estimate_reset();
    }

    event_remove_type( tape_edge_event );
  }

  if( stop_event != -1 ) debugger_event( stop_event );

  return 0;
}
Ejemplo n.º 14
0
static void
cmd_result( upd_fdc *f )
{
  f->cycle = f->cmd->res_length;
  f->main_status &= ~UPD_FDC_MAIN_EXECUTION;
  f->main_status |= UPD_FDC_MAIN_DATAREQ;
  if( f->cycle > 0 ) {	/* result state */
    f->state = UPD_FDC_STATE_RES;
    f->intrq = UPD_INTRQ_RESULT;
    f->main_status |= UPD_FDC_MAIN_DATA_READ;
  } else {			/* NO result state */
    f->state = UPD_FDC_STATE_CMD;
    f->main_status &= ~UPD_FDC_MAIN_DATADIR;
    f->main_status &= ~UPD_FDC_MAIN_BUSY;
  }
  event_remove_type( timeout_event );		/* remove timeouts... */
  if( f->head_load && f->cmd->id <= UPD_CMD_READ_ID ) {
    event_add_with_data( tstates + f->hut_time * 
			 machine_current->timings.processor_speed / 1000,
			 head_event, f );
  }
}
Ejemplo n.º 15
0
int
tape_record_stop( void )
{
  libspectrum_tape_block* block;

  /* put last sample into the recording buffer */
  rec_state.tape_buffer_used = write_rec_buffer( rec_state.tape_buffer,
                                                 rec_state.tape_buffer_used,
                                                 rec_state.last_level_count );

  /* stop scheduling events and turn buffer into a block and
     pop into the current tape */
  event_remove_type( record_event );

  block = libspectrum_tape_block_alloc( LIBSPECTRUM_TAPE_BLOCK_RLE_PULSE );

  libspectrum_tape_block_set_scale( block, rec_state.tstates_per_sample );
  libspectrum_tape_block_set_data_length( block, rec_state.tape_buffer_used );
  libspectrum_tape_block_set_data( block, rec_state.tape_buffer );

  libspectrum_tape_append_block( tape, block );

  rec_state.tape_buffer = NULL;
  rec_state.tape_buffer_size = 0;
  rec_state.tape_buffer_used = 0;

  tape_modified = 1;
  ui_tape_browser_update( UI_TAPE_BROWSER_NEW_BLOCK, block );

  tape_recording = 0;

  /* Also want to reenable other tape actions */
  ui_menu_activate( UI_MENU_ITEM_TAPE_RECORDING, 0 );

  return 0;
}
Ejemplo n.º 16
0
static void
do_acceleration( void )
{
  if( length_known1 ) {
    int set_b_high = length_long1;
    set_b_high ^= ( acceleration_mode == ACCELERATION_MODE_DECREASING );
    if( set_b_high ) {
      z80.bc.b.h = 0xfe;
    } else {
      z80.bc.b.h = 0x00;
    }
    z80.af.b.l |= 0x01;
    z80.pc.b.l = readbyte_internal( z80.sp.w ); z80.sp.w++;
    z80.pc.b.h = readbyte_internal( z80.sp.w ); z80.sp.w++;

    event_remove_type( tape_edge_event );
    tape_next_edge( tstates, 0, NULL );

    successive_reads = 0;
  }

  length_known1 = length_known2;
  length_long1 = length_long2;
}
Ejemplo n.º 17
0
libspectrum_byte
wd_fdc_dr_read( wd_fdc *f )
{
  fdd_t *d = f->current_drive;

  if( f->flags & WD_FLAG_DRQ &&
	f->status_register & WD_FDC_SR_BUSY )
    event_remove_type( fdc_event );

  if( f->state == WD_FDC_STATE_READ ) {
    f->data_offset++;				/* count read bytes */
    fdd_read_data( d ); crc_add(f, d);		/* read a byte */
    if( d->data > 0xff ) {			/* no data */
      f->status_register |= WD_FDC_SR_RNF;
      f->status_register &= ~WD_FDC_SR_BUSY;
      f->status_type = WD_FDC_STATUS_TYPE2;
      f->state = WD_FDC_STATE_NONE;
      wd_fdc_set_intrq( f );
      wd_fdc_reset_datarq( f );
    } else {
      f->data_register = d->data;
      if( f->data_offset == f->sector_length ) {	/* read the CRC */
	fdd_read_data( d ); crc_add(f, d);
	fdd_read_data( d ); crc_add(f, d);

	/* FIXME: make this per-FDC */
	event_remove_type( timeout_event );	/* clear the timeout */

	if( f->crc == 0x0000 && f->data_multisector ) {
	  f->sector_register++;
	  f->rev = 5;
	  wd_fdc_reset_datarq( f );
	  event_add_with_data( tstates +	 	/* 5 revolutions: 5 * 200 / 1000 */
			       machine_current->timings.processor_speed,
			       timeout_event, f );
	  event_add_with_data( tstates + 2 * 		/* 20 ms delay */
			       machine_current->timings.processor_speed / 100,
			       fdc_event, f );
	} else {
	  f->status_register &= ~WD_FDC_SR_BUSY;
	  if( f->crc == 0x0000 )
	    f->status_register &= ~WD_FDC_SR_CRCERR;
	  else
	    f->status_register |= WD_FDC_SR_CRCERR;
	  f->status_type = WD_FDC_STATUS_TYPE2;
	  f->state = WD_FDC_STATE_NONE;
	  wd_fdc_set_intrq( f );
	  wd_fdc_reset_datarq( f );
	}
      }
    }
  } else if( f->state == WD_FDC_STATE_READID ) {
    switch( f->data_offset ) {
    case 0:		/* track */
      f->data_register = f->id_track;
      break;
    case 1:		/* head */
      f->data_register = f->id_head;
      break;
    case 2:		/* sector */
      f->data_register = f->id_sector;
      break;
    case 3:		/* length */
      f->data_register = f->id_length;
      break;
    case 4:		/* crc1 */
      f->data_register = f->crc >> 8;
      break;
    case 5:		/* crc2 */
      f->sector_register = f->id_track;
      f->data_register = f->crc & 0xff;
      f->status_register &= ~WD_FDC_SR_BUSY;
      f->status_type = WD_FDC_STATUS_TYPE2;
      f->state = WD_FDC_STATE_NONE;
      event_remove_type( timeout_event );	/* clear the timeout */
      wd_fdc_set_intrq( f );
      wd_fdc_reset_datarq( f );
      break;
    default:
      break;
    }
    f->data_offset++;
  } else if( f->state == WD_FDC_STATE_READTRACK ) {
Ejemplo n.º 18
0
static void
start_write_data( upd_fdc *f )
{
  int i;
  fdd_t *d = f->current_drive;

multi_track_next:
  if( f->first_rw || f->read_id ||
      f->data_register[5] > f->data_register[3] ) {
    if( !f->read_id ) {
      if( !f->first_rw )
        f->data_register[3]++;
      f->first_rw = 0;

      f->rev = 2;
      f->read_id = 1;
    }
    while( f->rev ) {
      i = f->current_drive->disk.i >= f->current_drive->disk.bpt ?
    	  0 : f->current_drive->disk.i;			/* start position */
      if( seek_id( f ) == 0 )
        f->rev = 0;
      else
        f->id_mark = UPD_FDC_AM_NONE;
      i = f->current_drive->disk.bpt ? 
          ( f->current_drive->disk.i - i ) * 200 / f->current_drive->disk.bpt : 200;
      if( i > 0 ) {
        event_add_with_data( tstates + i *		/* i * 1/20 revolution */
			     machine_current->timings.processor_speed / 1000,
			     fdc_event, f );
        return;
      }
    }

    f->read_id = 0;
    if( f->id_mark == UPD_FDC_AM_NONE ) {	/* not found/crc error */
      f->status_register[0] |= UPD_FDC_ST0_INT_ABNORM;
      goto abort_write_data;
    }

    for( i = 11; i > 0; i-- )	/* "delay" 11 GAP byte */
      fdd_read_data( d );
    if( f->mf )					/* MFM */
      for( i = 11; i > 0; i-- )	/* "delay" another 11 GAP byte */
	fdd_read_data( d );

    d->data = 0x00;
    for( i = f->mf ? 12 : 6; i > 0; i-- )	/* write 6/12 zero */
      fdd_write_data( d );
    crc_preset( f );
    if( f->mf ) {				/* MFM */
      d->data = 0xffa1;
      for( i = 3; i > 0; i-- ) {		/* write 3 0xa1 with clock mark */
	fdd_write_data( d ); crc_add( f, d );
      }
    }
    d->data = ( f->del_data ? 0x00f8 : 0x00fb ) |
    			( f->mf ? 0x0000 : 0xff00 );	/* write data mark */
    fdd_write_data( d ); crc_add( f, d );
  } else {
    f->data_register[1]++;		/* next track */
    f->data_register[3] = 1;		/* first sector */
    if( f->mt ) {
      goto multi_track_next;
    }
abort_write_data:
    f->state = UPD_FDC_STATE_RES;	/* end of execution phase */
    f->cycle = f->cmd->res_length;
/* end of cylinder is set if:
* 1. sector data is read completely
*    (i.e. no other errors occur like no data.
* 2. sector being read is same specified by EOT
* 3. terminal count is not received
* note: in +3 uPD765 never got TC
*/
    f->status_register[0] |= UPD_FDC_ST0_INT_ABNORM;
    f->status_register[1] |= UPD_FDC_ST1_EOF_CYLINDER;
    f->main_status &= ~UPD_FDC_MAIN_EXECUTION;
    f->intrq = UPD_INTRQ_RESULT;
    cmd_result( f );
    return;
  }
  f->main_status |= UPD_FDC_MAIN_DATAREQ | UPD_FDC_MAIN_DATA_WRITE;
  f->data_offset = 0;
  event_remove_type( timeout_event );
  event_add_with_data( tstates + 4 *			/* 2 revolution: 2 * 200 / 1000 */
		       machine_current->timings.processor_speed / 10,
		       timeout_event, f );
}
Ejemplo n.º 19
0
static void
start_read_data( upd_fdc *f )
{
  int i;
skip_deleted_sector:
multi_track_next:
  if( f->first_rw || f->read_id || 
      f->data_register[5] > f->data_register[3] ) {
    if( !f->read_id ) {
      if( !f->first_rw )
        f->data_register[3]++;
      f->first_rw = 0;

      f->rev = 2;
      f->read_id = 1;
    }
    while( f->rev ) {
      i = f->current_drive->disk.i >= f->current_drive->disk.bpt ?
    	  0 : f->current_drive->disk.i;			/* start position */
      if( seek_id( f ) == 0 )
        f->rev = 0;
      else
        f->id_mark = UPD_FDC_AM_NONE;
      i = f->current_drive->disk.bpt ? 
          ( f->current_drive->disk.i - i ) * 200 / f->current_drive->disk.bpt : 200;
      if( i > 0 ) {
        event_add_with_data( tstates + i *		/* i * 1/20 revolution */
			     machine_current->timings.processor_speed / 1000,
			     fdc_event, f );
        return;
      }
    }

    f->read_id = 0;
    if( f->id_mark == UPD_FDC_AM_NONE ) {	/* not found/crc error */
      f->status_register[0] |= UPD_FDC_ST0_INT_ABNORM;
      goto abort_read_data;
    }

    if( read_datamark( f ) > 0 ) {	/* not found */
      f->status_register[0] |= UPD_FDC_ST0_INT_ABNORM;
      goto abort_read_data;
    }
    if( f->ddam != f->del_data ) {
      f->status_register[2] |= UPD_FDC_ST2_CONTROL_MARK;
      if( f->sk ) {
	f->data_register[3]++;
    	goto skip_deleted_sector;		/* or not deleted but we want to read deleted */
      }
    }
  } else {
    if( f->mt ) {
      f->data_register[1]++;		/* next track */
      f->data_register[3] = 1;		/* first sector */
      goto multi_track_next;
    }
abort_read_data:
    f->state = UPD_FDC_STATE_RES;	/* end of execution phase */
    f->cycle = f->cmd->res_length;
/* end of cylinder is set if:
* 1. sector data is read completely
*    (i.e. no other errors occur like no data.
* 2. sector being read is same specified by EOT
* 3. terminal count is not received
* note: in +3 uPD765 never got TC
*/
    if( !f->status_register[0] && !f->status_register[1] ) {
      f->status_register[0] |= UPD_FDC_ST0_INT_ABNORM;
      f->status_register[1] |= UPD_FDC_ST1_EOF_CYLINDER;
    }
    
    if( !( f->status_register[0] & 
	    ( UPD_FDC_ST0_INT_ABNORM | UPD_FDC_ST0_INT_READY ) ) ) {
      f->data_register[1]++;		/* next track */
      f->data_register[3] = 1;		/* first sector */
    }
    
    f->main_status &= ~UPD_FDC_MAIN_EXECUTION;
    f->intrq = UPD_INTRQ_RESULT;
    cmd_result( f );
    return;
  }
  f->main_status |= UPD_FDC_MAIN_DATAREQ;
  if( f->cmd->id != UPD_CMD_SCAN )
    f->main_status |= UPD_FDC_MAIN_DATA_READ;
  f->data_offset = 0;
  event_remove_type( timeout_event );
  event_add_with_data( tstates + 4 *			/* 2 revolution: 2 * 200 / 1000  */
		       machine_current->timings.processor_speed / 10,
		       timeout_event, f );
}
Ejemplo n.º 20
0
static void
wd_fdc_type_i( wd_fdc *f )
{
  libspectrum_byte b = f->command_register;
  fdd_t *d = f->current_drive;

  if( f->state == WD_FDC_STATE_SEEK_DELAY ) {	/* after delay */
    if( ( b & 0x60 ) != 0x00 )			/* STEP/STEP-IN/STEP-OUT */
      goto type_i_verify;
    goto type_i_loop;
  } else {					/* WD_FDC_STATE_SEEK */
    f->status_register |= WD_FDC_SR_SPINUP;
  }

  if( ( b & 0x60 ) != 0x00 ) {			/* STEP/STEP-IN/STEP-OUT */
    if( b & 0x40 )
      f->direction = b & 0x20 ? FDD_STEP_OUT : FDD_STEP_IN;
    if( b & 0x10 )				/* update? */
      goto type_i_update;
    goto type_i_noupdate;
  }
						/* SEEK or RESTORE */
  if ( !( b & 0x10 ) ) {				/* RESTORE */
    f->track_register = 0xff;
    f->data_register = 0;
  }

type_i_loop:
  if( f->track_register != f->data_register ) {
    f->direction = f->track_register < f->data_register ?
			FDD_STEP_IN : FDD_STEP_OUT;

type_i_update:
    f->track_register += f->direction == FDD_STEP_IN ? 1 : -1;

type_i_noupdate:
    if( d->tr00 && f->direction == FDD_STEP_OUT ) {
      f->track_register = 0;
    } else {
      fdd_step( d, f->direction );
      f->state = WD_FDC_STATE_SEEK_DELAY;
      event_remove_type( fdc_event );
      event_add_with_data( tstates + f->rates[ b & 0x03 ] *
			   machine_current->timings.processor_speed / 1000,
			   fdc_event, f );
      return;
    }
  }

type_i_verify:
  if( b & 0x04 ) {

    if( f->type == WD1773 || f->type == FD1793 || f->type == WD2797 ) {
      f->head_load = 1;
      event_remove_type( motor_off_event );
      if( f->flags & WD_FLAG_BETA128 )
        fdd_motoron( d, 1 );
      else
        fdd_head_load( d, 1 );
      event_remove_type( fdc_event );
      event_add_with_data( tstates + 15 * 				/* 15ms */
		    machine_current->timings.processor_speed / 1000,
			fdc_event, f );
    }

    f->state = WD_FDC_STATE_VERIFY;

    if( ( f->type == WD1770 || f->type == WD1772 ) &&
	!( f->status_register & WD_FDC_SR_MOTORON ) ) {
      f->status_register |= WD_FDC_SR_MOTORON;
      fdd_motoron( f->current_drive, 1 );
      event_remove_type( fdc_event );
      event_add_with_data( tstates + 12 * 		/* 6 revolution 6 * 200 / 1000 */
		    machine_current->timings.processor_speed / 10,
			fdc_event, f );
      return;
    }

    wd_fdc_seek_verify( f );
    return;
  }

  if( d->tr00 )
    f->status_register |= WD_FDC_SR_LOST;
  else
    f->status_register &= ~WD_FDC_SR_LOST;

  f->state = WD_FDC_STATE_NONE;
  f->status_register &= ~WD_FDC_SR_BUSY;
  wd_fdc_set_intrq( f );
}
Ejemplo n.º 21
0
static void
wd_fdc_type_ii_seek( wd_fdc *f )
{
  libspectrum_byte b = f->command_register;
  fdd_t *d = f->current_drive;
  int i;

  event_remove_type( fdc_event );
  if( f->id_mark == WD_FDC_AM_NONE ) {
    f->read_id = 1;
    while( f->rev ) {
      i = d->disk.i >= d->disk.bpt ? 0 : d->disk.i;	/* start position */
      if( !read_id( f ) ) {
        if( ( f->data_check_head != -1 && f->data_check_head != !!( f->id_head ) ) ||
	    ( f->id_track != f->track_register || f->id_sector != f->sector_register ) ) {
          f->id_mark = WD_FDC_AM_NONE;
	}
      } else {
        f->id_mark = WD_FDC_AM_NONE;
      }
      i = d->disk.bpt ?
	( d->disk.i - i ) * 200 / d->disk.bpt : 200;
      if( i > 0 ) {
        event_add_with_data( tstates + i *		/* i * 1/20 revolution */
			     machine_current->timings.processor_speed / 1000,
			     fdc_event, f );
        return;
      } else if( f->id_mark != WD_FDC_AM_NONE ) {
	break;
      }
    }
  }

  f->read_id = 0;

  if( f->id_mark == WD_FDC_AM_NONE ) {
    f->status_register |= WD_FDC_SR_RNF;
    f->status_register &= ~WD_FDC_SR_BUSY;
    f->state = WD_FDC_STATE_NONE;
    wd_fdc_set_intrq( f );
    return;
  }

  if( f->state == WD_FDC_STATE_READ ) {
    if( f->id_mark == WD_FDC_AM_ID )
      read_datamark( f );

    if( f->id_mark == WD_FDC_AM_NONE ) {		/* not found */
      f->status_register |= WD_FDC_SR_RNF;
      f->status_register &= ~WD_FDC_SR_BUSY;
      f->state = WD_FDC_STATE_NONE;
      wd_fdc_set_intrq( f );
      return;
    }
    if( f->ddam )
      f->status_register |= WD_FDC_SR_SPINUP;	/* set deleted data mark */
    f->data_offset = 0;
    wd_fdc_set_datarq( f );

  } else {
    f->ddam = b & 0x01;
    for( i = 11; i > 0; i-- )	/* "delay" 11 GAP byte */
      fdd_read_data( d );
    wd_fdc_set_datarq( f );
    f->data_offset = 0;
    if( f->dden )
      for( i = 11; i > 0; i-- )	/* "delay" another 11 GAP byte */
	fdd_read_data( d );

    d->data = 0x00;
    for( i = f->dden ? 12 : 6; i > 0; i-- )	/* write 6/12 zero */
      fdd_write_data( d );
    crc_preset( f );
    if( f->dden ) {				/* MFM */
      d->data = 0xffa1;
      for( i = 3; i > 0; i-- ) {		/* write 3 0xa1 with clock mark */
	fdd_write_data( d ); crc_add(f, d);
      }
    }
    d->data = ( f->ddam ? 0x00f8 : 0x00fb ) |
    			( f->dden ? 0x0000 : 0xff00 );	/* write data mark */
    fdd_write_data( d ); crc_add(f, d);
  }
  event_remove_type( timeout_event );
  event_add_with_data( tstates + 			/* 5 revolutions: 5 * 200 / 1000 */
		       machine_current->timings.processor_speed,
		       timeout_event, f );
}
Ejemplo n.º 22
0
void
upd_fdc_write_data( upd_fdc *f, libspectrum_byte data )
{
  int i, terminated = 0;
  unsigned int u;
  fdd_t *d;

  if( !( f->main_status & UPD_FDC_MAIN_DATAREQ ) || 
      ( f->main_status & UPD_FDC_MAIN_DATA_READ ) )
    return;

  if( f->main_status & UPD_FDC_MAIN_BUSY && 
      f->state == UPD_FDC_STATE_EXE ) {	/* execution phase WRITE/FORMAT */
    d = f->current_drive;
    if( f->cmd->id == UPD_CMD_WRITE_ID ) {	/* FORMAT */
		/* at the index hole... */
      f->data_register[f->data_offset + 5] = data;	/* read id fields */
      f->data_offset++;
      if( f->data_offset == 4 ) {			/* C, H, R, N done => format track */
	event_remove_type( timeout_event );

        d->data = 0x00;
        for( i = f->mf ? 12 : 6; i > 0; i-- )	/* write 6/12 zero */
          fdd_write_data( d );
        crc_preset( f );
        if( f->mf ) {				/* MFM */
          d->data = 0xffa1;
          for( i = 3; i > 0; i-- ) {		/* write 3 0xa1 with clock mark */
	    fdd_write_data( d ); crc_add( f, d );
          }
        }
        d->data = 0x00fe | ( f->mf ? 0x0000 : 0xff00 );	/* write id mark */
        fdd_write_data( d ); crc_add( f, d );
	for( i = 0; i < 4; i++ ) {
    	  d->data =  f->data_register[i + 5];	/* write id fields */
          fdd_write_data( d ); crc_add( f, d );
	}
        d->data = f->crc >> 8;
        fdd_write_data( d );			/* write crc1 */
        d->data = f->crc & 0xff;
        fdd_write_data( d );			/* write crc2 */

        d->data = f->mf ? 0x4e : 0xff;
        for( i = 11; i > 0; i-- )	/* write 11 GAP byte */
          fdd_write_data( d );
        if( f->mf )					/* MFM */
          for( i = 11; i > 0; i-- )	/* write another 11 GAP byte */
	    fdd_write_data( d );
        d->data = 0x00;
        for( i = f->mf ? 12 : 6; i > 0; i-- )	/* write 6/12 zero */
          fdd_write_data( d );
        crc_preset( f );
        if( f->mf ) {				/* MFM */
          d->data = 0xffa1;
          for( i = 3; i > 0; i-- ) {		/* write 3 0xa1 with clock mark */
	    fdd_write_data( d ); crc_add( f, d );
          }
        }
        d->data = 0x00fb | ( f->mf ? 0x0000 : 0xff00 );	/* write data mark */
        fdd_write_data( d ); crc_add( f, d );
	
    	d->data =  f->data_register[4];	/* write filler byte */
	for( i = f->rlen; i > 0; i-- ) {
          fdd_write_data( d ); crc_add( f, d );
	}
        d->data = f->crc >> 8;
        fdd_write_data( d );			/* write crc1 */
        d->data = f->crc & 0xff;
        fdd_write_data( d );			/* write crc2 */

        d->data = f->mf ? 0x4e : 0xff;
	for( i = f->data_register[3]; i > 0; i-- ) {	/* GAP */
          fdd_write_data( d );
	}
        f->data_offset = 0;
	f->data_register[2]--;		/* prepare next sector */
      }
Ejemplo n.º 23
0
static void
wd_fdc_type_iii( wd_fdc *f )
{
  int i;
  fdd_t *d = f->current_drive;

  event_remove_type( fdc_event );
  if( !f->read_id && ( f->type == WD1773 || f->type == FD1793 || f->type == WD2797) ) {
    if( !disk_ready( f ) ) {
      f->status_register &= ~WD_FDC_SR_BUSY;
      f->state = WD_FDC_STATE_NONE;
      wd_fdc_set_intrq( f );
      return;
    }
    if( !f->hlt ) {
      event_add_with_data( tstates + 5 *
    		    machine_current->timings.processor_speed / 1000,
			fdc_event, f );
      return;
    }
  }
  if( f->state == WD_FDC_STATE_WRITETRACK ) {		/* ----WRITE TRACK---- */
    if( d->wrprot ) {
      f->status_register |= WD_FDC_SR_WRPROT;
      f->status_register &= ~WD_FDC_SR_BUSY;
      f->state = WD_FDC_STATE_NONE;
      wd_fdc_set_intrq( f );
      return;
    }
    f->status_register &= ~WD_FDC_SR_WRPROT;

    f->data_offset = 0;
    fdd_wait_index_hole( d );
    wd_fdc_set_datarq( f );
  } else if( f->state == WD_FDC_STATE_READTRACK ) {	/* ----READ TRACK---- */
    fdd_wait_index_hole( d );
    wd_fdc_set_datarq( f );
  } else {						/* ----READID---- */
    if( !f->read_id ) {
      f->read_id = 1;
      f->rev = 5;
      f->id_mark = WD_FDC_AM_NONE;
    }
    if( f->id_mark == WD_FDC_AM_NONE ) {
      while( f->rev ) {
        i = d->disk.i >= d->disk.bpt ? 0 : d->disk.i;	/* start position */
        read_id( f );
        i = d->disk.bpt ?
	    ( d->disk.i - i ) * 200 / d->disk.bpt : 200;
	if( i > 0 ) {
          event_add_with_data( tstates + i *		/* i * 1/20 revolution */
			       machine_current->timings.processor_speed / 1000,
			       fdc_event, f );
          return;
	} else if( f->id_mark != WD_FDC_AM_NONE )
	  break;
      }
      if( f->id_mark == WD_FDC_AM_NONE ) {
        f->state = WD_FDC_STATE_NONE;
        f->status_register |= WD_FDC_SR_RNF;
        f->status_register &= ~WD_FDC_SR_BUSY;
        wd_fdc_set_intrq( f );
        f->read_id = 0;
        return;
      }
    }
    f->read_id = 0;
    f->data_offset = 0;
    wd_fdc_set_datarq( f );
  }
  event_remove_type( timeout_event );
  event_add_with_data( tstates + 2 * 20 *	/* 2 revolutions: 2 * 200 / 1000  */
		       machine_current->timings.processor_speed / 100,
		       timeout_event, f );
}
Ejemplo n.º 24
0
void
wd_fdc_cr_write( wd_fdc *f, libspectrum_byte b )
{
  fdd_t *d = f->current_drive;

  wd_fdc_reset_intrq( f );

  if( ( b & 0xf0 ) == 0xd0 ) {			/* Type IV - Force Interrupt */
    event_remove_type( fdc_event );
    f->status_register &= ~( WD_FDC_SR_BUSY   | WD_FDC_SR_WRPROT |
			     WD_FDC_SR_CRCERR | WD_FDC_SR_IDX_DRQ );
    f->state = WD_FDC_STATE_NONE;
    f->status_type = WD_FDC_STATUS_TYPE1;
    wd_fdc_reset_datarq( f );

    if( b & 0x08 )
      wd_fdc_set_intrq( f );
    else if( b & 0x04 ) {
      d->fdc_index = wd_fdc_wait_index;
      d->fdc = f;
    }

    if( d->tr00 )
      f->status_register |= WD_FDC_SR_LOST;
    else
      f->status_register &= ~WD_FDC_SR_LOST;

    wd_fdc_spinup( f, b & 0xf7 ); /* spinup motor, but we do not have a 'h' bit!  */

    return;
  }

  if( f->status_register & WD_FDC_SR_BUSY )
    return;

  f->command_register = b;
  f->status_register |= WD_FDC_SR_BUSY;

  /* keep spindle motor on: */
  event_remove_type( motor_off_event );

  if( !( b & 0x80 ) ) {                         /* Type I */
    f->state = WD_FDC_STATE_SEEK;
    f->status_type = WD_FDC_STATUS_TYPE1;
    f->status_register &= ~( WD_FDC_SR_CRCERR | WD_FDC_SR_RNF |
			     WD_FDC_SR_IDX_DRQ );
    wd_fdc_reset_datarq( f );

    f->rev = 5;
    if( wd_fdc_spinup( f, b ) )
      return;
    wd_fdc_type_i( f );
  } else if( !( b & 0x40 ) ) {                  /* Type II */
    if( f->type == WD1773 || f->type == FD1793 ) {
      if( !disk_ready( f ) ) {
        f->status_register &= ~WD_FDC_SR_BUSY;
        f->state = WD_FDC_STATE_NONE;
        wd_fdc_set_intrq( f );
        return;
      }
    }
    if( f->type == WD1773 && b & 0x02 )
      f->data_check_head = b & 0x08 ? 1 : 0;
    else if( f->type == WD2797 )
      f->data_check_head = b & 0x02 ? 1 : 0;
    else
      f->data_check_head = -1;

    /* WD2797 (and FD1797) can read sectors with non-IBM-compatible
       sector length codes */
    f->non_ibm_len_code = ( f->type == WD2797 && !( b & 0x08 ) ) ? 1 : 0;

    f->state = b & 0x20 ? WD_FDC_STATE_WRITE : WD_FDC_STATE_READ;
    f->status_type = WD_FDC_STATUS_TYPE2;
    f->status_register &= ~( WD_FDC_SR_WRPROT | WD_FDC_SR_RNF |
			     WD_FDC_SR_IDX_DRQ| WD_FDC_SR_LOST|
			     WD_FDC_SR_SPINUP );

    if( f->type == WD2797 ) fdd_set_head( d, b & 0x02 ? 1 : 0 );

    f->rev = 5;
    if( wd_fdc_spinup( f, b ) )
      return;
    wd_fdc_type_ii( f );
  } else if( ( b & 0x30 ) != 0x10 ) {           /* Type III */
    if( f->type == WD1773 || f->type == FD1793 || f->type == WD2797 ) {
      if( !disk_ready( f ) ) {
        f->status_register &= ~WD_FDC_SR_BUSY;
        f->state = WD_FDC_STATE_NONE;
        wd_fdc_set_intrq( f );
        return;
      }
    }

    f->state = b & 0x20 ? ( b & 0x10 ?
			    WD_FDC_STATE_WRITETRACK : WD_FDC_STATE_READTRACK ) :
		WD_FDC_STATE_READID;
    f->status_type = WD_FDC_STATUS_TYPE2;
    f->status_register &= ~( WD_FDC_SR_SPINUP | WD_FDC_SR_RNF |
			     WD_FDC_SR_IDX_DRQ| WD_FDC_SR_LOST );

    f->rev = 5;
    if( wd_fdc_spinup( f, b ) )
      return;
    wd_fdc_type_iii( f );
  }
}
Ejemplo n.º 25
0
void
wd_fdc_cr_write( wd_fdc *f, libspectrum_byte b )
{
  wd_fdc_drive *d = f->current_drive;

  wd_fdc_reset_intrq( f );

  if( ( b & 0xf0 ) == 0xd0 ) {			/* Type IV - Force Interrupt */
    event_remove_type( fdc_event );
    f->status_register &= ~( WD_FDC_SR_BUSY   | WD_FDC_SR_WRPROT |
			     WD_FDC_SR_CRCERR | WD_FDC_SR_IDX_DRQ );
    f->state = WD_FDC_STATE_NONE;
    f->status_type = WD_FDC_STATUS_TYPE1;
    wd_fdc_reset_datarq( f );

    if( b & 0x08 )
      wd_fdc_set_intrq( f );
    else if( b & 0x04 )
      d->index_interrupt = 1;

    if( d->fdd.tr00 )
      f->status_register |= WD_FDC_SR_LOST;
    else
      f->status_register &= ~WD_FDC_SR_LOST;

    return;
  }

  if( f->status_register & WD_FDC_SR_BUSY )
    return;

  f->command_register = b;
  f->status_register |= WD_FDC_SR_BUSY;

  /* keep spindle motor on: */
  event_remove_type( motor_off_event );

  if( !( b & 0x80 ) ) {                         /* Type I */
    f->state = WD_FDC_STATE_SEEK;
    f->status_type = WD_FDC_STATUS_TYPE1;
    f->status_register &= ~( WD_FDC_SR_CRCERR | WD_FDC_SR_RNF |
			     WD_FDC_SR_IDX_DRQ );
    wd_fdc_reset_datarq( f );

    f->rev = 5;
    if( wd_fdc_spinup( f, b ) )
      return;
    wd_fdc_type_i( f );
  } else if( !( b & 0x40 ) ) {                  /* Type II */
    if( f->type == WD1773 || f->type == FD1793 ) {
      if( ( ( f->flags & WD_FLAG_BETA128 ) && !f->head_load ) ||
        ( !( f->flags & WD_FLAG_BETA128 ) && !d->fdd.ready ) ) {
        f->status_register &= ~WD_FDC_SR_BUSY;
        f->state = WD_FDC_STATE_NONE;
        wd_fdc_set_intrq( f );
        return;
      }
    }
    if( f->type == WD1773 && b & 0x02 )
      f->data_check_head = b & 0x08 ? 1 : 0;
    else
      f->data_check_head = -1;

    f->state = b & 0x20 ? WD_FDC_STATE_WRITE : WD_FDC_STATE_READ;
    f->status_type = WD_FDC_STATUS_TYPE2;
    f->status_register &= ~( WD_FDC_SR_WRPROT | WD_FDC_SR_RNF |
			     WD_FDC_SR_IDX_DRQ| WD_FDC_SR_LOST|
			     WD_FDC_SR_SPINUP );
    f->rev = 5;
    if( wd_fdc_spinup( f, b ) )
      return;
    wd_fdc_type_ii( f );
  } else if( ( b & 0x30 ) != 0x10 ) {           /* Type III */
    if( f->type == WD1773 || f->type == FD1793 ) {
      if( ( ( f->flags & WD_FLAG_BETA128 ) && !f->head_load ) ||
        ( !( f->flags & WD_FLAG_BETA128 ) && !d->fdd.ready ) ) {
        f->status_register &= ~WD_FDC_SR_BUSY;
        f->state = WD_FDC_STATE_NONE;
        wd_fdc_set_intrq( f );
        return;
      }
    }
    f->state = b & 0x20 ? ( b & 0x10 ? 
			    WD_FDC_STATE_WRITETRACK : WD_FDC_STATE_READTRACK ) :
		WD_FDC_STATE_READID;
    f->status_type = WD_FDC_STATUS_TYPE2;
    f->status_register &= ~( WD_FDC_SR_SPINUP | WD_FDC_SR_RNF |
			     WD_FDC_SR_IDX_DRQ| WD_FDC_SR_LOST );

    f->rev = 5;
    if( wd_fdc_spinup( f, b ) )
      return;
    wd_fdc_type_iii( f );
  }
}