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 );
  }
}
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 ) {
static void
wd_fdc_event( libspectrum_dword last_tstates GCC_UNUSED, int event,
	      void *user_data )
{
  wd_fdc *f = user_data;
  fdd_t *d = f->current_drive;

  if( event == timeout_event ) {
    if( f->state == WD_FDC_STATE_READ       ||
	f->state == WD_FDC_STATE_WRITE      ||
	f->state == WD_FDC_STATE_READTRACK  ||
	f->state == WD_FDC_STATE_WRITETRACK ||
	f->state == WD_FDC_STATE_READID        ) {
      f->state = WD_FDC_STATE_NONE;
      f->status_register |= WD_FDC_SR_LOST;
      f->status_register &= ~WD_FDC_SR_BUSY;
      wd_fdc_reset_datarq( f );
      wd_fdc_set_intrq( f );
    }
    return;
  }

  if( event == motor_off_event ) {
    if( f->type == WD1770 || f->type == WD1772 ) {
      f->status_register &= ~WD_FDC_SR_MOTORON;
      fdd_motoron( d, 0 );
    } else {						/* WD1773/FD1973 */
      f->head_load = 0;
      if( f->flags & WD_FLAG_BETA128 )
        fdd_motoron( d, 0 );
      else
        fdd_head_load( d, 0 );
    }
    return;
  }

  if( ( f->type == WD1773 || f->type == FD1793 || f->type == WD2797 ) &&
        f->hlt_time > 0 && f->head_load && !f->hlt )
    f->hlt = 1;

  if( ( ( f->type == WD1770 || f->type == WD1772 ) &&
	( f->status_register & WD_FDC_SR_MOTORON ) &&
	f->status_type == WD_FDC_STATUS_TYPE1 ) ||
      ( ( f->type == WD1773 || f->type == FD1793 || f->type == WD2797 ) &&
	( f->state == WD_FDC_STATE_SEEK ||
	  f->state == WD_FDC_STATE_SEEK_DELAY ) &&
	f->head_load ) ) {
    f->status_register |= WD_FDC_SR_SPINUP;
  }

  if( f->read_id ) {
    if( f->state == WD_FDC_STATE_VERIFY )
      wd_fdc_seek_verify_read_id( f );
    else if( ( f->state == WD_FDC_STATE_READ || f->state == WD_FDC_STATE_WRITE ) &&
	     f->datarq )
      f->datarq = 0, wd_fdc_set_datarq( f );
    else if( f->state == WD_FDC_STATE_READ || f->state == WD_FDC_STATE_WRITE )
      wd_fdc_type_ii_seek( f );
    else if( f->state == WD_FDC_STATE_READID )
      wd_fdc_type_iii( f );
  } else if( f->state == WD_FDC_STATE_SEEK || f->state == WD_FDC_STATE_SEEK_DELAY )
    wd_fdc_type_i( f );
  else if( f->state == WD_FDC_STATE_VERIFY )
    wd_fdc_seek_verify( f );
  else if( ( f->state == WD_FDC_STATE_READ || f->state == WD_FDC_STATE_WRITE ) &&
	   f->datarq )
    f->datarq = 0, wd_fdc_set_datarq( f );
  else if( f->state == WD_FDC_STATE_READ || f->state == WD_FDC_STATE_WRITE )
    wd_fdc_type_ii( f );
  else if( ( f->state == WD_FDC_STATE_READTRACK  ||
	     f->state == WD_FDC_STATE_READID     ||
	     f->state == WD_FDC_STATE_WRITETRACK   ) &&
	   f->datarq )
      f->datarq = 0, wd_fdc_set_datarq( f );
  else if( f->state == WD_FDC_STATE_READTRACK  ||
	   f->state == WD_FDC_STATE_READID     ||
	   f->state == WD_FDC_STATE_WRITETRACK    )
    wd_fdc_type_iii( f );
}
Exemple #4
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 );
  }
}