static void start_write_id( upd_fdc *f ) { int i; fdd_t *d = f->current_drive; d->data = f->mf ? 0x4e : 0xff; for( i = 40; i > 0; i-- ) /* write 40 GAP byte */ fdd_write_data( d ); if( f->mf ) /* MFM */ for( i = 40; i > 0; i-- ) /* write another 40 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 = 0xffc2; for( i = 3; i > 0; i-- ) { /* write 3 0xc2 with clock mark */ fdd_write_data( d ); } } d->data = 0x00fc | ( f->mf ? 0x0000 : 0xff00 ); /* write index mark */ fdd_write_data( d ); d->data = f->mf ? 0x4e : 0xff; /* postindex GAP */ for( i = 26; i > 0; i-- ) /* write 26 GAP byte */ fdd_write_data( d ); if( f->mf ) /* MFM */ for( i = 24; i > 0; i-- ) /* write another 24 GAP byte */ fdd_write_data( d ); f->main_status |= UPD_FDC_MAIN_DATAREQ | UPD_FDC_MAIN_DATA_WRITE; f->data_offset = 0; event_add_with_data( tstates + 2 * /* 1/10 revolution: 1 * 200 / 1000 */ machine_current->timings.processor_speed / 100, timeout_event, f ); }
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 ); }
/* Read next ID into f->id_* return 0 if found an ID return 1 if found but with CRC error return 2 if not found ID */ static int read_id( upd_fdc *f ) { int i; fdd_t *d = f->current_drive; f->status_register[1] &= ~( UPD_FDC_ST1_CRC_ERROR | UPD_FDC_ST1_MISSING_AM | UPD_FDC_ST1_NO_DATA ); f->id_mark = UPD_FDC_AM_NONE; i = f->rev; while( i == f->rev && d->ready ) { fdd_read_data( d ); if( d->index ) f->rev--; crc_preset( f ); if( f->mf ) { /* double density (MFM) */ if( d->data == 0xffa1 ) { crc_add( f, d ); fdd_read_data( d ); crc_add( f, d ); if( d->index ) f->rev--; if( d->data != 0xffa1 ) continue; fdd_read_data( d ); crc_add( f, d ); if( d->index ) f->rev--; if( d->data != 0xffa1 ) continue; } else { /* no 0xa1 with missing clock... */ continue; } } fdd_read_data( d ); if( d->index ) f->rev--; if( f->mf ) { /* double density (MFM) */ if( d->data != 0x00fe ) continue; } else { /* single density (FM) */ if( d->data != 0xfffe ) continue; } crc_add( f, d ); fdd_read_data( d ); crc_add( f, d ); if( d->index ) f->rev--; f->id_track = d->data; fdd_read_data( d ); crc_add( f, d ); if( d->index ) f->rev--; f->id_head = d->data; fdd_read_data( d ); crc_add( f, d ); if( d->index ) f->rev--; f->id_sector = d->data; fdd_read_data( d ); crc_add( f, d ); if( d->index ) f->rev--; f->id_length = d->data > MAX_SIZE_CODE ? MAX_SIZE_CODE : d->data; f->sector_length = 0x80 << f->id_length; fdd_read_data( d ); crc_add( f, d ); if( d->index ) f->rev--; fdd_read_data( d ); crc_add( f, d ); if( d->index ) f->rev--; if( f->crc != 0x0000 ) { f->status_register[1] |= UPD_FDC_ST1_CRC_ERROR | UPD_FDC_ST1_NO_DATA; f->id_mark = UPD_FDC_AM_ID; return 1; /* found but CRC error */ } else { f->id_mark = UPD_FDC_AM_ID; return 0; /* found and OK */ } } if(!d->ready) f->rev = 0; f->status_register[1] |= UPD_FDC_ST1_MISSING_AM | UPD_FDC_ST1_NO_DATA; /*FIXME _NO_DATA? */ return 2; /* not found */ }
static int read_datamark( upd_fdc *f ) { fdd_t *d = f->current_drive; int i; if( f->mf ) { /* double density (MFM) */ for( i = 40; i > 0; i-- ) { fdd_read_data( d ); if( d->data == 0x4e ) /* read next */ continue; if( d->data == 0x00 ) /* go to PLL sync */ break; f->status_register[2] |= UPD_FDC_ST2_MISSING_DM; return 1; /* something wrong... */ } for( ; i > 0; i-- ) { crc_preset( f ); fdd_read_data( d ); crc_add( f, d ); if( d->data == 0x00 ) continue; if( d->data == 0xffa1 ) /* got to a1 mark */ break; f->status_register[2] |= UPD_FDC_ST2_MISSING_DM; return 1; } for( i = d->data == 0xffa1 ? 2 : 3; i > 0; i-- ) { fdd_read_data( d ); crc_add( f, d ); if( d->data != 0xffa1 ) { f->status_register[2] |= UPD_FDC_ST2_MISSING_DM; return 1; } } fdd_read_data( d ); crc_add( f, d ); if( d->data < 0x00f8 || d->data > 0x00fb ) { /* !fb deleted mark */ f->status_register[2] |= UPD_FDC_ST2_MISSING_DM; return 1; } if( d->data != 0x00fb ) f->ddam = 1; else f->ddam = 0; return 0; } else { /* SD -> FM */ for( i = 30; i > 0; i-- ) { fdd_read_data( d ); if( d->data == 0xff ) /* read next */ continue; if( d->data == 0x00 ) /* go to PLL sync */ break; f->status_register[2] |= UPD_FDC_ST2_MISSING_DM; return 1; /* something wrong... */ } for( ; i > 0; i-- ) { crc_preset( f ); fdd_read_data( d ); crc_add( f, d ); if( d->data == 0x00 ) continue; if( d->data >= 0xfff8 && d->data <= 0xfffb ) /* !fb deleted mark */ break; f->status_register[2] |= UPD_FDC_ST2_MISSING_DM; return 1; } if( i == 0 ) { fdd_read_data( d ); crc_add( f, d ); if( d->data < 0xfff8 || d->data > 0xfffb ) { /* !fb deleted mark */ f->status_register[2] |= UPD_FDC_ST2_MISSING_DM; return 1; } } if( d->data != 0x00fb ) f->ddam = 1; else f->ddam = 0; return 0; } f->status_register[2] |= UPD_FDC_ST2_MISSING_DM; return 1; }
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 */ }
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 ); }
static int read_datamark( wd_fdc *f ) { fdd_t *d = f->current_drive; int i; f->id_mark = WD_FDC_AM_NONE; if( f->dden ) { /* double density (MFM) */ for( i = 40; i > 0; i-- ) { fdd_read_data( d ); if( d->data == 0x4e ) /* read next */ continue; if( d->data == 0x00 ) /* go to PLL sync */ break; return 1; /* something wrong... */ } for( ; i > 0; i-- ) { crc_preset( f ); fdd_read_data( d ); crc_add(f, d); if( d->data == 0x00 ) continue; if( d->data == 0xffa1 ) /* got to a1 mark */ break; return 1; } for( i = d->data == 0xffa1 ? 2 : 3; i > 0; i-- ) { fdd_read_data( d ); crc_add(f, d); if( d->data != 0xffa1 ) return 1; } fdd_read_data( d ); crc_add(f, d); if( d->data < 0x00f8 || d->data > 0x00fb ) /* !fb deleted mark */ return 1; if( d->data != 0x00fb ) f->ddam = 1; else f->ddam = 0; f->id_mark = WD_FDC_AM_DATA; return 0; } else { /* SD -> FM */ for( i = 30; i > 0; i-- ) { fdd_read_data( d ); if( d->data == 0xff ) /* read next */ continue; if( d->data == 0x00 ) /* go to PLL sync */ break; return 1; /* something wrong... */ } for( ; i > 0; i-- ) { crc_preset( f ); fdd_read_data( d ); crc_add(f, d); if( d->data == 0x00 ) continue; if( d->data >= 0xfff8 && d->data <= 0xfffb ) /* !fb deleted mark */ break; return 1; } if( i == 0 ) { fdd_read_data( d ); crc_add(f, d); if( d->data < 0xfff8 || d->data > 0xfffb ) /* !fb deleted mark */ return 1; } if( d->data != 0x00fb ) f->ddam = 1; else f->ddam = 0; f->id_mark = WD_FDC_AM_DATA; return 0; } return 1; }
/* return 0 if found an ID return 1 if not found ID return 2 if found but with CRC error (READ ADDRESS command) what we can do, if disk not rotating, or head not loaded? */ static int read_id( wd_fdc *f ) { int i = f->rev; fdd_t *d = f->current_drive; f->id_mark = WD_FDC_AM_NONE; if( f->rev <= 0 ) return 1; while( i == f->rev ) { /* **FIXME d->motoron? */ crc_preset( f ); if( f->dden ) { /* double density (MFM) */ fdd_read_data( d ); if( d->index ) f->rev--; crc_add(f, d); if( d->data == 0xffa1 ) { fdd_read_data( d ); crc_add(f, d); if( d->index ) f->rev--; if( d->data != 0xffa1 ) continue; fdd_read_data( d ); crc_add(f, d); if( d->index ) f->rev--; if( d->data != 0xffa1 ) continue; } else { /* no 0xa1 with missing clock... */ continue; } } fdd_read_data( d ); crc_add(f, d); if( d->index ) f->rev--; if( f->dden ) { /* double density (MFM) */ if( d->data != 0x00fe ) continue; } else { /* single density (FM) */ if( d->data != 0xfffe ) continue; } fdd_read_data( d ); crc_add(f, d); if( d->index ) f->rev--; f->id_track = d->data; fdd_read_data( d ); crc_add(f, d); if( d->index ) f->rev--; f->id_head = d->data; fdd_read_data( d ); crc_add(f, d); if( d->index ) f->rev--; f->id_sector = d->data; fdd_read_data( d ); crc_add(f, d); if( d->index ) f->rev--; f->id_length = d->data; if( f->non_ibm_len_code ) { /* 00->256 01->512 10->1024 11->128 */ f->sector_length = 0x80 << ( ( d->data + 1 ) & 0x03 ); } else { /* 00->128 01->256 10->512 11->1024 */ f->sector_length = 0x80 << ( d->data & 0x03 ); } fdd_read_data( d ); crc_add(f, d); if( d->index ) f->rev--; fdd_read_data( d ); crc_add(f, d); if( d->index ) f->rev--; if( f->crc != 0x0000 ) { f->status_register |= WD_FDC_SR_CRCERR; f->id_mark = WD_FDC_AM_ID; return 2; } else { f->status_register &= ~WD_FDC_SR_CRCERR; f->id_mark = WD_FDC_AM_ID; return 0; } } return 1; }
/* return 0 if found an ID return 1 if not found ID return 2 if found but with CRC error (READ ADDRESS command) */ static int read_id( wd_fdc *f ) { int i = f->rev; wd_fdc_drive *d = f->current_drive; f->id_mark = WD_FDC_AM_NONE; if( f->rev <= 0 ) return 1; while( i == f->rev ) { crc_preset( f ); if( f->dden ) { /* double density (MFM) */ fdd_read_write_data( &d->fdd, FDD_READ ); if( d->fdd.index ) f->rev--; crc_add(f, d); if( d->fdd.data == 0xffa1 ) { fdd_read_write_data( &d->fdd, FDD_READ ); crc_add(f, d); if( d->fdd.index ) f->rev--; if( d->fdd.data != 0xffa1 ) continue; fdd_read_write_data( &d->fdd, FDD_READ ); crc_add(f, d); if( d->fdd.index ) f->rev--; if( d->fdd.data != 0xffa1 ) continue; } else { /* no 0xa1 with missing clock... */ continue; } } fdd_read_write_data( &d->fdd, FDD_READ ); crc_add(f, d); if( d->fdd.index ) f->rev--; if( f->dden ) { /* double density (MFM) */ if( d->fdd.data != 0x00fe ) continue; } else { /* single density (FM) */ if( d->fdd.data != 0xfffe ) continue; } fdd_read_write_data( &d->fdd, FDD_READ ); crc_add(f, d); if( d->fdd.index ) f->rev--; f->id_track = d->fdd.data; fdd_read_write_data( &d->fdd, FDD_READ ); crc_add(f, d); if( d->fdd.index ) f->rev--; f->id_head = d->fdd.data; fdd_read_write_data( &d->fdd, FDD_READ ); crc_add(f, d); if( d->fdd.index ) f->rev--; f->id_sector = d->fdd.data; fdd_read_write_data( &d->fdd, FDD_READ ); crc_add(f, d); if( d->fdd.index ) f->rev--; f->id_length = d->fdd.data; f->sector_length = 0x80 << d->fdd.data; fdd_read_write_data( &d->fdd, FDD_READ ); crc_add(f, d); if( d->fdd.index ) f->rev--; fdd_read_write_data( &d->fdd, FDD_READ ); crc_add(f, d); if( d->fdd.index ) f->rev--; if( f->crc != 0x0000 ) { f->status_register |= WD_FDC_SR_CRCERR; f->id_mark = WD_FDC_AM_ID; return 2; } else { f->status_register &= ~WD_FDC_SR_CRCERR; f->id_mark = WD_FDC_AM_ID; return 0; } } return 1; }