2 Skelton for retropc emulator
4 Author : Takeda.Toshiya
14 // TODO: check status in data lost
15 #define FDC_STA_FDC_READY 0x08 // 1=Ready, 0=Busy
16 #define FDC_STA_CMD_ERROR 0x06 // Execute command other than Seek to Zero when the drive is not ready, or execute write command when the disk is write protected
17 #define FDC_STA_ID_MISSING 0x02 // ID field is missing
18 #define FDC_STA_ID_ERROR 0x05 // Track address in ID field is 0xff (defective track)
19 #define FDC_STA_SEEK_ERROR 0x07 // Seek error
20 #define FDC_STA_DATA_ERROR 0x01 // Find error in data field
21 #define FDC_STA_LAST_SECTOR 0x03 // Terminate read/write command at the last sector in the track when tnd signal is active (low)
22 #define FDC_STA_SUCCESS 0x00 // Command is successfully executed
23 #define FDC_STA_SUCCESS_DDM 0x04 // Command is successfully executed and detect the deleted data address mark
25 #define FDC_CMD_SEEK_ZERO 0x00 // Seek to Zero
26 #define FDC_CMD_SEEK 0x03 // Seek
27 #define FDC_CMD_WRITE_ID 0x08 // Write Index/ID
28 #define FDC_CMD_SEEK_WRITE_ID 0x0a // Seek and Write Index/ID
29 #define FDC_CMD_READ 0x05 // Read Data
30 #define FDC_CMD_SEEK_READ 0x07 // Seek and Read Data
31 #define FDC_CMD_WRITE 0x09 // Write Data
32 #define FDC_CMD_WRITE_DDM 0x0d // Write Data with Deleted Data Address Mark
33 #define FDC_CMD_SEEK_WRITE 0x0b // Seek and Write Data
34 #define FDC_CMD_SEEK_WRITE_DDM 0x0f // Seek and Write Data with Deleted Data Address Mark
35 #define FDC_CMD_SENCE_DRV_STAT 0x01 // Sence Drive Status
38 #define EVENT_SEARCH 1
43 void T3444A::cancel_my_event(int event)
45 if(register_id[event] != -1) {
46 cancel_event(this, register_id[event]);
47 register_id[event] = -1;
51 void T3444A::register_my_event(int event, double usec)
53 cancel_my_event(event);
54 register_event(this, event, usec, false, ®ister_id[event]);
57 void T3444A::register_seek_event()
59 cancel_my_event(EVENT_SEEK);
60 if(fdc[drvreg].track == seektrk) {
61 register_event(this, EVENT_SEEK, 1, false, ®ister_id[EVENT_SEEK]);
63 register_event(this, EVENT_SEEK, timerflag ? 40000 : 25000, false, ®ister_id[EVENT_SEEK]);
67 void T3444A::register_rqm_event(int bytes)
69 double usec = disk[drvreg]->get_usec_per_bytes(bytes) - get_passed_usec(prev_rqm_clock);
73 cancel_my_event(EVENT_RQM);
74 register_event(this, EVENT_RQM, usec, false, ®ister_id[EVENT_RQM]);
77 void T3444A::register_lost_event(int bytes)
79 cancel_my_event(EVENT_LOST);
80 register_event(this, EVENT_LOST, disk[drvreg]->get_usec_per_bytes(bytes), false, ®ister_id[EVENT_LOST]);
83 void T3444A::initialize()
86 _max_drive = osd->get_feature_int_value(_T("MAX_DRIVE"));
87 if((_max_drive <= 0) || (_max_drive >= 4)) _max_drive = 4;
88 _has_t3444m = osd->check_feature(_T("HAS_T3444M"));
89 //_fdc_debug_log = osd->check_feature(_T("_FDC_DEBUG_LOG"));
90 _fdc_debug_log = config.special_debug_fdc;
92 _sectors_in_track = (_has_t3444m) ? 16 : 26;
93 // initialize d88 handler
94 for(int i = 0; i < 4; i++) {
95 disk[i] = new DISK(emu);
96 disk[i]->set_device_name(_T("%s/Disk #%d"), this_device_name, i + 1);
100 if(d_noise_seek != NULL) {
101 d_noise_seek->set_device_name(_T("Noise Player (FDD Seek)"));
102 if(!d_noise_seek->load_wav_file(_T("FDDSEEK.WAV"))) {
103 if(!d_noise_seek->load_wav_file(_T("FDDSEEK1.WAV"))) {
104 d_noise_seek->load_wav_file(_T("SEEK.WAV"));
107 d_noise_seek->set_mute(!config.sound_noise_fdd);
109 if(d_noise_head_down != NULL) {
110 d_noise_head_down->set_device_name(_T("Noise Player (FDD Head Load)"));
111 d_noise_head_down->load_wav_file(_T("HEADDOWN.WAV"));
112 d_noise_head_down->set_mute(!config.sound_noise_fdd);
114 if(d_noise_head_up != NULL) {
115 d_noise_head_up->set_device_name(_T("Noise Player (FDD Head Unload)"));
116 d_noise_head_up->load_wav_file(_T("HEADUP.WAV"));
117 d_noise_head_up->set_mute(!config.sound_noise_fdd);
121 memset(fdc, 0, sizeof(fdc));
125 status = FDC_STA_FDC_READY | FDC_STA_SUCCESS;
126 cmdreg = trkreg = secreg = datareg = 0;
127 drvreg = sidereg = 0;
132 void T3444A::release()
134 // release d88 handler
135 for(int i = 0; i < 4; i++) {
145 for(int i = 0; i < 4; i++) {
148 fdc[i].access = false;
150 for(long unsigned int i = 0; i < array_length(register_id); i++) {
157 void T3444A::write_io8(uint32_t addr, uint32_t data)
162 cmdreg = data & 0x0f;
167 trkreg = data & 0x7f;
168 timerflag = ((data & 0x80) != 0);
172 secreg = data & 0x7f;
174 if(_has_t3444m) sidereg = (data >> 7) & 1;
180 if(motor_on && rqm && !now_search) {
181 if(cmdreg == FDC_CMD_WRITE || cmdreg == FDC_CMD_WRITE_DDM) {
183 if(fdc[drvreg].index < disk[drvreg]->sector_size.sd) {
184 disk[drvreg]->sector[fdc[drvreg].index++] = datareg;
185 disk[drvreg]->set_deleted(cmdreg == FDC_CMD_WRITE_DDM);
186 fdc[drvreg].access = true;
189 cancel_my_event(EVENT_LOST);
191 if(fdc[drvreg].index >= disk[drvreg]->sector_size.sd) {
192 //#ifdef _FDC_DEBUG_LOG
193 if(_fdc_debug_log) this->out_debug_log(_T("FDC\tWRITE DATA FINISHED\n"));
195 // 2S: 300rpm, 3100bytes/track -> 0.0155bytes/us
196 register_my_event(EVENT_TND, 100); // 0.0155bytes/us * 100us = 1.55bytes < GAP3
198 if(fdc[drvreg].index == 1) {
199 register_rqm_event(fdc[drvreg].bytes_before_2nd_rqm);
201 register_rqm_event(1);
204 } else if(cmdreg == FDC_CMD_WRITE_ID) {
206 if(fdc[drvreg].index < _sectors_in_track * 4) {
207 sector_id[fdc[drvreg].index++] = datareg;
210 cancel_my_event(EVENT_LOST);
212 if(fdc[drvreg].index >= _sectors_in_track * 4) {
213 // format in single-density
214 bool drive_mfm = disk[drvreg]->drive_mfm;
215 disk[drvreg]->drive_mfm = false;
216 disk[drvreg]->format_track(fdc[drvreg].track, sidereg);
217 disk[drvreg]->drive_mfm = drive_mfm;
218 for(int i = 0; i < _sectors_in_track; i++) {
219 disk[drvreg]->insert_sector(sector_id[i * 4], sector_id[i * 4 + 1], sector_id[i * 4 + 2], sector_id[i * 4 + 3], false, false, 0xff, 128);
221 status |= FDC_STA_FDC_READY;
223 register_rqm_event(1);
231 uint32_t T3444A::read_io8(uint32_t addr)
236 //#ifdef _FDC_DEBUG_LOG
237 if(_fdc_debug_log) this->out_debug_log(_T("FDC\tSTATUS=%02x\n"),status);
242 if(motor_on && rqm && !now_search) {
243 if(cmdreg == FDC_CMD_READ) {
245 if(fdc[drvreg].index < disk[drvreg]->sector_size.sd) {
246 datareg = disk[drvreg]->sector[fdc[drvreg].index++];
247 fdc[drvreg].access = true;
250 cancel_my_event(EVENT_LOST);
252 if(fdc[drvreg].index >= disk[drvreg]->sector_size.sd) {
253 //#ifdef _FDC_DEBUG_LOG
254 if(_fdc_debug_log) this->out_debug_log(_T("FDC\tREAD DATA FINISHED\n"));
256 // if(status == FDC_STA_DATA_ERROR) {
257 // status |= FDC_STA_FDC_READY;
259 register_my_event(EVENT_TND, 100);
262 register_rqm_event(1);
271 void T3444A::write_dma_io8(uint32_t addr, uint32_t data)
276 uint32_t T3444A::read_dma_io8(uint32_t addr)
281 void T3444A::write_signal(int id, uint32_t data, uint32_t mask)
283 if(id == SIG_T3444A_DRIVE) {
287 } else if(id == SIG_T3444A_TND) {
288 tnd = ((data & mask) != 0);
289 } else if(id == SIG_T3444A_MOTOR) {
290 motor_on = ((data & mask) != 0);
294 uint32_t T3444A::read_signal(int ch)
296 if(ch == SIG_T3444A_DRDY) {
297 return (disk[drvreg]->inserted && motor_on) ? 1 : 0;
298 } else if(ch == SIG_T3444A_CRDY) {
299 return (status & FDC_STA_FDC_READY) ? 1 : 0;
300 } else if(ch == SIG_T3444A_RQM) {
301 // this is negative signal
307 for(int i = 0; i < 4; i++) {
311 fdc[i].access = false;
319 void T3444A::event_callback(int event_id, int err)
321 register_id[event_id] = -1;
325 if(seektrk > fdc[drvreg].track) {
327 if(d_noise_seek != NULL) d_noise_seek->play();
328 } else if(seektrk < fdc[drvreg].track) {
330 if(d_noise_seek != NULL) d_noise_seek->play();
332 if(seektrk != fdc[drvreg].track) {
333 register_seek_event();
336 if(cmdreg == FDC_CMD_SEEK_READ) {
337 cmdreg = FDC_CMD_READ;
339 } else if(cmdreg == FDC_CMD_SEEK_WRITE) {
340 cmdreg = FDC_CMD_WRITE;
342 } else if(cmdreg == FDC_CMD_SEEK_WRITE_DDM) {
343 cmdreg = FDC_CMD_WRITE_DDM;
346 status |= FDC_STA_FDC_READY;
350 if(status == FDC_STA_SUCCESS || status == FDC_STA_SUCCESS_DDM || status == FDC_STA_DATA_ERROR) {
351 if(cmdreg == FDC_CMD_WRITE || cmdreg == FDC_CMD_WRITE_DDM) {
352 register_lost_event(8);
353 } else if(cmdreg == FDC_CMD_SEEK_WRITE_ID) {
354 register_lost_event(1); // is this okay ???
356 register_lost_event(1);
358 fdc[drvreg].cur_position = fdc[drvreg].next_trans_position;
359 fdc[drvreg].prev_clock = prev_rqm_clock = get_current_clock();
362 status |= FDC_STA_FDC_READY;
367 if(!(status & FDC_STA_FDC_READY)) {
368 if((cmdreg == FDC_CMD_WRITE || cmdreg == FDC_CMD_WRITE_DDM) && fdc[drvreg].index == 0) {
369 fdc[drvreg].cur_position = (fdc[drvreg].cur_position + fdc[drvreg].bytes_before_2nd_rqm) % disk[drvreg]->get_track_size();
371 fdc[drvreg].cur_position = (fdc[drvreg].cur_position + 1) % disk[drvreg]->get_track_size();
373 fdc[drvreg].prev_clock = prev_rqm_clock = get_current_clock();
375 if(cmdreg == FDC_CMD_SEEK_WRITE_ID) {
376 register_lost_event(1); // is this okay ???
378 register_lost_event(1);
383 status |= FDC_STA_FDC_READY;
387 if(secreg < _sectors_in_track) {
389 //#ifdef _FDC_DEBUG_LOG
390 if(_fdc_debug_log) this->out_debug_log(_T("FDC\tTND AND CONTINUE SEC=%d\n"), secreg);
395 //#ifdef _FDC_DEBUG_LOG
396 if(_fdc_debug_log) this->out_debug_log(_T("FDC\tTND BUT TERMINATED SEC=%d\n"), secreg);
398 status = FDC_STA_FDC_READY | FDC_STA_LAST_SECTOR;
401 status |= FDC_STA_FDC_READY;
407 // ----------------------------------------------------------------------------
409 // ----------------------------------------------------------------------------
411 void T3444A::process_cmd()
413 //#ifdef _FDC_DEBUG_LOG
414 static const _TCHAR *cmdstr[0x10] = {
416 _T("Sence Drive Status"),
422 _T("Seek and Read Data"),
423 _T("Write Index/ID"),
425 _T("Seek and Write Index/ID"),
426 _T("Seek and Write Data"),
428 _T("Write Data with Deleted Data Address Mark"),
430 _T("Seek and Write Data with Deleted Data Address Mark"),
433 //if(cmdreg == cmdreg) {
434 this->out_debug_log(_T("FDC\tCMD=%2xh (%s) DATA=%2xh DRV=%d TRK=%3d SIDE=%d SEC=%2d\n"), cmdreg, cmdstr[cmdreg], datareg, drvreg, trkreg, sidereg, secreg);
438 status = 0; // FDC is busy
441 case FDC_CMD_SEEK_ZERO:
443 update_head_flag(drvreg, false);
446 case FDC_CMD_SEEK_READ:
447 case FDC_CMD_SEEK_WRITE:
448 case FDC_CMD_SEEK_WRITE_DDM:
449 case FDC_CMD_SEEK_WRITE_ID:
451 update_head_flag(drvreg, false);
455 case FDC_CMD_WRITE_DDM:
457 update_head_flag(drvreg, true);
459 case FDC_CMD_WRITE_ID:
461 update_head_flag(drvreg, true);
463 case FDC_CMD_SENCE_DRV_STAT:
467 status = FDC_STA_FDC_READY | FDC_STA_CMD_ERROR; // is this okay ???
472 void T3444A::cmd_seek_zero()
474 if(!disk[drvreg]->inserted || !motor_on) {
475 // status = FDC_STA_FDC_READY | FDC_STA_SEEK_ERROR;
476 status = FDC_STA_FDC_READY | FDC_STA_SUCCESS;
477 seektrk = trkreg = 0;
479 status = FDC_STA_SUCCESS;
480 seektrk = trkreg = 0;
481 register_seek_event();
485 void T3444A::cmd_seek()
487 if(!disk[drvreg]->inserted || !motor_on) {
488 status = FDC_STA_FDC_READY | FDC_STA_CMD_ERROR;
489 } else if(trkreg > 34) {
490 status = FDC_STA_FDC_READY | FDC_STA_SEEK_ERROR;
492 status = FDC_STA_SUCCESS;
494 register_seek_event();
498 void T3444A::cmd_read_write()
500 if(!((status = search_sector()) & FDC_STA_FDC_READY)) {
502 if(status == FDC_STA_SUCCESS || status == FDC_STA_SUCCESS_DDM || status == FDC_STA_DATA_ERROR) {
503 time = get_usec_to_start_trans();
505 time = get_usec_to_detect_index_hole(3);
508 register_my_event(EVENT_SEARCH, time);
509 cancel_my_event(EVENT_LOST);
513 void T3444A::cmd_write_id()
515 if(!disk[drvreg]->inserted || !motor_on || disk[drvreg]->write_protected) {
516 status = FDC_STA_FDC_READY | FDC_STA_CMD_ERROR;
518 // raise first rqm soon
519 fdc[drvreg].next_trans_position = (get_cur_position() + 1) % disk[drvreg]->get_track_size();
520 fdc[drvreg].index = 0;
521 status = FDC_STA_SUCCESS;
523 register_my_event(EVENT_SEARCH, disk[drvreg]->get_usec_per_bytes(1));
524 cancel_my_event(EVENT_LOST);
528 void T3444A::cmd_sence()
530 if(!disk[drvreg]->inserted || !motor_on) {
531 status = FDC_STA_FDC_READY | FDC_STA_CMD_ERROR;
533 trkreg = fdc[drvreg].track;
534 status = FDC_STA_FDC_READY | FDC_STA_SUCCESS;
538 void T3444A::update_head_flag(int drv, bool head_load)
540 if(fdc[drv].head_load != head_load) {
542 if(d_noise_head_down != NULL) d_noise_head_down->play();
544 if(d_noise_head_up != NULL) d_noise_head_up->play();
546 fdc[drv].head_load = head_load;
550 // ----------------------------------------------------------------------------
552 // ----------------------------------------------------------------------------
554 uint8_t T3444A::search_sector()
557 if(!disk[drvreg]->inserted || !motor_on) {
558 return FDC_STA_FDC_READY | FDC_STA_CMD_ERROR;
562 if(cmdreg == FDC_CMD_WRITE || cmdreg == FDC_CMD_WRITE_DDM || cmdreg == FDC_CMD_WRITE_ID) {
563 if(disk[drvreg]->write_protected) {
564 return FDC_STA_FDC_READY | FDC_STA_CMD_ERROR;
569 if(!disk[drvreg]->get_track(fdc[drvreg].track, sidereg)) {
570 return FDC_STA_ID_MISSING;
573 // get current position
574 int sector_num = disk[drvreg]->sector_num.sd;
575 int position = get_cur_position();
577 if(position > disk[drvreg]->sync_position[sector_num - 1]) {
578 position -= disk[drvreg]->get_track_size();
581 // first scanned sector
582 int first_sector = 0;
583 for(int i = 0; i < sector_num; i++) {
584 if(position < disk[drvreg]->sync_position[i]) {
591 for(int i = 0; i < sector_num; i++) {
593 int index = (first_sector + i) % sector_num;
594 disk[drvreg]->get_sector(-1, -1, index);
597 if(disk[drvreg]->id[0] == 0xff) {
598 return FDC_STA_ID_ERROR;
600 if(disk[drvreg]->id[0] != trkreg) {
601 trkreg = disk[drvreg]->id[0];
602 return FDC_STA_SEEK_ERROR;
604 if(disk[drvreg]->id[2] != secreg) {
607 if(disk[drvreg]->sector_size.sd == 0) {
610 if(disk[drvreg]->addr_crc_error && !disk[drvreg]->ignore_crc()) {
612 disk[drvreg]->sector_size.sd = 0;
613 return FDC_STA_ID_MISSING; // is this okay ???
617 if(cmdreg == FDC_CMD_WRITE || cmdreg == FDC_CMD_WRITE_DDM) {
618 fdc[drvreg].next_trans_position = disk[drvreg]->id_position[index] + 4 + 2;
619 fdc[drvreg].bytes_before_2nd_rqm = disk[drvreg]->data_position[index] - fdc[drvreg].next_trans_position;
621 fdc[drvreg].next_trans_position = disk[drvreg]->data_position[index] + 1;
623 fdc[drvreg].next_sync_position = disk[drvreg]->sync_position[index];
624 fdc[drvreg].index = 0;
625 //#ifdef _FDC_DEBUG_LOG
626 if(_fdc_debug_log) this->out_debug_log(_T("FDC\tSECTOR FOUND SIZE=$%04x ID=%02x %02x %02x %02x CRC=%02x %02x CRC_ERROR=%d\n"),
627 disk[drvreg]->sector_size.sd,
628 disk[drvreg]->id[0], disk[drvreg]->id[1], disk[drvreg]->id[2], disk[drvreg]->id[3],
629 disk[drvreg]->id[4], disk[drvreg]->id[5],
630 disk[drvreg]->data_crc_error ? 1 : 0);
632 if(disk[drvreg]->data_crc_error && !disk[drvreg]->ignore_crc()) {
633 return FDC_STA_DATA_ERROR;
634 } else if(disk[drvreg]->deleted || cmdreg == FDC_CMD_WRITE_DDM) {
635 return FDC_STA_SUCCESS_DDM;
637 return FDC_STA_SUCCESS;
642 disk[drvreg]->sector_size.sd = 0;
643 return FDC_STA_ID_MISSING;
646 // ----------------------------------------------------------------------------
648 // ----------------------------------------------------------------------------
650 int T3444A::get_cur_position()
652 return (fdc[drvreg].cur_position + disk[drvreg]->get_bytes_per_usec(get_passed_usec(fdc[drvreg].prev_clock))) % disk[drvreg]->get_track_size();
655 double T3444A::get_usec_to_start_trans()
657 // get time from current position
658 double time = get_usec_to_next_trans_pos();
662 double T3444A::get_usec_to_next_trans_pos()
664 int position = get_cur_position();
666 if(disk[drvreg]->invalid_format) {
667 // XXX: this track is invalid format and the calculated sector position may be incorrect.
668 // so use the constant period
670 } else if(/*disk[drvreg]->no_skew &&*/ !disk[drvreg]->correct_timing()) {
671 // XXX: this image may be a standard image or coverted from a standard image and skew may be incorrect,
672 // so use the period to search the next sector from the current position
673 int sector_num = disk[drvreg]->sector_num.sd;
676 if(position > disk[drvreg]->sync_position[sector_num - 1]) {
677 position -= disk[drvreg]->get_track_size();
679 for(int i = 0; i < sector_num; i++) {
680 if(position < disk[drvreg]->sync_position[i]) {
681 if(cmdreg == FDC_CMD_WRITE || cmdreg == FDC_CMD_WRITE_DDM) {
682 bytes = (disk[drvreg]->id_position[i] + 4 + 2) - position;
684 bytes = (disk[drvreg]->data_position[i] + 1) - position;
687 bytes += disk[drvreg]->get_track_size(); // to make sure
693 return disk[drvreg]->get_usec_per_bytes(bytes);
697 int bytes = fdc[drvreg].next_trans_position - position;
698 if(fdc[drvreg].next_sync_position < position || bytes < 0) {
699 bytes += disk[drvreg]->get_track_size();
701 return disk[drvreg]->get_usec_per_bytes(bytes);
704 double T3444A::get_usec_to_detect_index_hole(int count)
706 int position = get_cur_position();
707 int bytes = disk[drvreg]->get_track_size() * count - position;
709 bytes += disk[drvreg]->get_track_size();
711 return disk[drvreg]->get_usec_per_bytes(bytes);
714 // ----------------------------------------------------------------------------
716 // ----------------------------------------------------------------------------
718 void T3444A::set_rqm(bool val)
720 write_signals(&outputs_rqm, (rqm = val) ? 0xffffffff : 0);
723 // ----------------------------------------------------------------------------
725 // ----------------------------------------------------------------------------
727 void T3444A::open_disk(int drv, const _TCHAR* file_path, int bank)
729 if(drv < 4 && drv < _max_drive) {
730 disk[drv]->open(file_path, bank);
734 void T3444A::close_disk(int drv)
736 if(drv < 4 && drv < _max_drive) {
738 update_head_flag(drvreg, false);
742 bool T3444A::is_disk_inserted(int drv)
744 if(drv < 4 && drv < _max_drive) {
745 return disk[drv]->inserted;
750 void T3444A::is_disk_protected(int drv, bool value)
752 if(drv < 4 && drv < _max_drive) {
753 disk[drv]->write_protected = value;
757 bool T3444A::is_disk_protected(int drv)
759 if(drv < 4 && drv < _max_drive) {
760 return disk[drv]->write_protected;
765 void T3444A::set_drive_type(int drv, uint8_t type)
767 if(drv < 4 && drv < _max_drive) {
768 disk[drv]->drive_type = type;
772 uint8_t T3444A::get_drive_type(int drv)
774 if(drv < 4 && drv < _max_drive) {
775 return disk[drv]->drive_type;
777 return DRIVE_TYPE_UNK;
780 void T3444A::set_drive_rpm(int drv, int rpm)
782 if(drv < 4 && drv < _max_drive) {
783 disk[drv]->drive_rpm = rpm;
787 void T3444A::set_drive_mfm(int drv, bool mfm)
789 if(drv < 4 && drv < _max_drive) {
790 disk[drv]->drive_mfm = mfm;
794 void T3444A::update_config()
796 if(d_noise_seek != NULL) {
797 d_noise_seek->set_mute(!config.sound_noise_fdd);
799 _fdc_debug_log = config.special_debug_fdc;
802 #define STATE_VERSION 2
804 bool T3444A::process_state(FILEIO* state_fio, bool loading)
806 if(!state_fio->StateCheckUint32(STATE_VERSION)) {
809 if(!state_fio->StateCheckInt32(this_device_id)) {
813 for(int i = 0; i < array_length(fdc); i++) {
814 state_fio->StateValue(fdc[i].track);
815 state_fio->StateValue(fdc[i].index);
816 state_fio->StateValue(fdc[i].access);
817 state_fio->StateValue(fdc[i].head_load);
818 state_fio->StateValue(fdc[i].cur_position);
819 state_fio->StateValue(fdc[i].next_trans_position);
820 state_fio->StateValue(fdc[i].bytes_before_2nd_rqm);
821 state_fio->StateValue(fdc[i].next_sync_position);
822 state_fio->StateValue(fdc[i].prev_clock);
824 for(int i = 0; i < array_length(disk); i++) {
825 if(disk[i] == NULL) continue;
826 if(!disk[i]->process_state(state_fio, loading)) {
830 state_fio->StateValue(status);
831 state_fio->StateValue(cmdreg);
832 state_fio->StateValue(trkreg);
833 state_fio->StateValue(secreg);
834 state_fio->StateValue(datareg);
835 state_fio->StateValue(drvreg);
836 state_fio->StateValue(sidereg);
837 state_fio->StateValue(timerflag);
838 state_fio->StateArray(sector_id, sizeof(sector_id), 1);
839 state_fio->StateArray(register_id, sizeof(register_id), 1);
840 state_fio->StateValue(now_search);
841 state_fio->StateValue(seektrk);
842 state_fio->StateValue(rqm);
843 state_fio->StateValue(tnd);
844 state_fio->StateValue(motor_on);
845 state_fio->StateValue(prev_rqm_clock);