1 /*****************************************************************************
2 ** $Source: /cygdrive/d/Private/_SVNROOT/bluemsx/blueMSX/Src/IoDevice/TC8566AF.c,v $
3 **
4 ** $Revision: 1.16 $
5 **
6 ** $Date: 2009-07-18 15:08:04 $
7 **
8 ** More info: http://www.bluemsx.com
9 **
10 ** Copyright (C) 2003-2006 Daniel Vik
11 **
12 ** This program is free software; you can redistribute it and/or modify
13 ** it under the terms of the GNU General Public License as published by
14 ** the Free Software Foundation; either version 2 of the License, or
15 ** (at your option) any later version.
16 **
17 ** This program is distributed in the hope that it will be useful,
18 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
19 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 ** GNU General Public License for more details.
21 **
22 ** You should have received a copy of the GNU General Public License
23 ** along with this program; if not, write to the Free Software
24 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 **
26 ******************************************************************************
27 */
28 #include "TC8566AF.h"
29 #include "Board.h"
30 #include "SaveState.h"
31 #include "Disk.h"
32 #include "Led.h"
33 #include "FdcAudio.h"
34 #include <stdlib.h>
35 #include <string.h>
36 
37 
38 extern int diskOffset;
39 
40 struct TC8566AF {
41     UInt8 drive;
42 
43     UInt8 mainStatus;
44     UInt8 status0;
45     UInt8 status1;
46     UInt8 status2;
47     UInt8 status3;
48     UInt8 commandCode;
49 
50     int command;
51     int phase;
52     int phaseStep;
53 
54     UInt8 fillerByte;
55 
56     UInt8 cylinderNumber;
57     UInt8 side;
58     UInt8 sectorNumber;
59     UInt8 number;
60     UInt8 currentTrack;
61     UInt8 sectorsPerCylinder;
62 
63     int    sectorOffset;
64     UInt32 dataTransferTime;
65 
66     UInt8 sectorBuf[512];
67 
68     FdcAudio* fdcAudio;
69 };
70 
71 #define CMD_UNKNOWN                 0
72 #define CMD_READ_DATA               1
73 #define CMD_WRITE_DATA              2
74 #define CMD_WRITE_DELETED_DATA      3
75 #define CMD_READ_DELETED_DATA       4
76 #define CMD_READ_DIAGNOSTIC         5
77 #define CMD_READ_ID                 6
78 #define CMD_FORMAT                  7
79 #define CMD_SCAN_EQUAL              8
80 #define CMD_SCAN_LOW_OR_EQUAL       9
81 #define CMD_SCAN_HIGH_OR_EQUAL      10
82 #define CMD_SEEK                    11
83 #define CMD_RECALIBRATE             12
84 #define CMD_SENSE_INTERRUPT_STATUS  13
85 #define CMD_SPECIFY                 14
86 #define CMD_SENSE_DEVICE_STATUS     15
87 
88 #define PHASE_IDLE                  0
89 #define PHASE_COMMAND               1
90 #define PHASE_DATATRANSFER          2
91 #define PHASE_RESULT                3
92 
93 #define STM_DB0    0x01
94 #define STM_DB1    0x02
95 #define STM_DB2    0x04
96 #define STM_DB3    0x08
97 #define STM_CB     0x10
98 #define STM_NDM    0x20
99 #define STM_DIO    0x40
100 #define STM_RQM    0x80
101 
102 #define ST0_DS0    0x01
103 #define ST0_DS1    0x02
104 #define ST0_HD     0x04
105 #define ST0_NR     0x08
106 #define ST0_EC     0x10
107 #define ST0_SE     0x20
108 #define ST0_IC0    0x40
109 #define ST0_IC1    0x80
110 
111 #define ST1_MA     0x01
112 #define ST1_NW     0x02
113 #define ST1_ND     0x04
114 #define ST1_OR     0x10
115 #define ST1_DE     0x20
116 #define ST1_EN     0x80
117 
118 #define ST2_MD     0x01
119 #define ST2_BC     0x02
120 #define ST2_SN     0x04
121 #define ST2_SH     0x08
122 #define ST2_NC     0x10
123 #define ST2_DD     0x20
124 #define ST2_CM     0x40
125 
126 #define ST3_DS0    0x01
127 #define ST3_DS1    0x02
128 #define ST3_HD     0x04
129 #define ST3_2S     0x08
130 #define ST3_TK0    0x10
131 #define ST3_RDY    0x20
132 #define ST3_WP     0x40
133 #define ST3_FLT    0x80
134 
tc8566afExecutionPhasePeek(TC8566AF * tc)135 static UInt8 tc8566afExecutionPhasePeek(TC8566AF* tc)
136 {
137 	switch (tc->command) {
138 	case CMD_READ_DATA:
139 		if (tc->sectorOffset < 512) {
140 			return tc->sectorBuf[tc->sectorOffset];
141         }
142         break;
143     }
144     return 0xff;
145 }
146 
147 
tc8566afExecutionPhaseRead(TC8566AF * tc)148 static UInt8 tc8566afExecutionPhaseRead(TC8566AF* tc)
149 {
150 	switch (tc->command) {
151 	case CMD_READ_DATA:
152 		if (tc->sectorOffset < 512) {
153 			UInt8 value = tc->sectorBuf[tc->sectorOffset++];
154     		if (tc->sectorOffset == 512) {
155                 tc->phase = PHASE_RESULT;
156                 tc->phaseStep = 0;
157             }
158             return value;
159         }
160         break;
161     }
162 
163     return 0xff;
164 }
165 
tc8566afResultsPhasePeek(TC8566AF * tc)166 static UInt8 tc8566afResultsPhasePeek(TC8566AF* tc)
167 {
168 	switch (tc->command) {
169 	case CMD_READ_DATA:
170 	case CMD_WRITE_DATA:
171     case CMD_FORMAT:
172 		switch(tc->phaseStep) {
173 		case 0:
174             return tc->status0;
175 		case 1:
176             return tc->status1;
177 		case 2:
178             return tc->status2;
179 		case 3:
180             return tc->cylinderNumber;
181 		case 4:
182             return tc->side;
183 		case 5:
184             return tc->sectorNumber;
185 		case 6:
186             return tc->number;
187 		}
188 		break;
189 
190     case CMD_SENSE_INTERRUPT_STATUS:
191 		switch (tc->phaseStep) {
192 		case 0:
193             return tc->status0;
194 		case 1:
195             return tc->currentTrack;
196 		}
197 		break;
198 
199     case CMD_SENSE_DEVICE_STATUS:
200 		switch (tc->phaseStep) {
201 		case 0:
202             return tc->status3;
203 		}
204 		break;
205     }
206 
207     return 0xff;
208 }
209 
tc8566afResultsPhaseRead(TC8566AF * tc)210 static UInt8 tc8566afResultsPhaseRead(TC8566AF* tc)
211 {
212 	switch (tc->command) {
213 	case CMD_READ_DATA:
214 	case CMD_WRITE_DATA:
215     case CMD_FORMAT:
216 		switch	(tc->phaseStep++) {
217 		case 0:
218             return tc->status0;
219 		case 1:
220             return tc->status1;
221 		case 2:
222             return tc->status2;
223 		case 3:
224             return tc->cylinderNumber;
225 		case 4:
226             return tc->side;
227 		case 5:
228             return tc->sectorNumber;
229 		case 6:
230 			tc->phase       = PHASE_IDLE;
231             tc->mainStatus &= ~STM_CB;
232             tc->mainStatus &= ~STM_DIO;
233 
234             return tc->number;
235 		}
236 		break;
237 
238     case CMD_SENSE_INTERRUPT_STATUS:
239 		switch (tc->phaseStep++) {
240 		case 0:
241             return tc->status0;
242 		case 1:
243 			tc->phase       = PHASE_IDLE;
244             tc->mainStatus &= ~(STM_CB | STM_DIO);
245 
246             return tc->currentTrack;
247 		}
248 		break;
249 
250     case CMD_SENSE_DEVICE_STATUS:
251 		switch (tc->phaseStep++) {
252 		case 0:
253 			tc->phase       = PHASE_IDLE;
254             tc->mainStatus &= ~(STM_CB | STM_DIO);
255 
256             return tc->status3;
257 		}
258 		break;
259     }
260 
261     return 0xff;
262 }
263 
tc8566afIdlePhaseWrite(TC8566AF * tc,UInt8 value)264 void tc8566afIdlePhaseWrite(TC8566AF* tc, UInt8 value)
265 {
266 	tc->command = CMD_UNKNOWN;
267 	if ((value & 0x1f) == 0x06) tc->command = CMD_READ_DATA;
268 	if ((value & 0x3f) == 0x05) tc->command = CMD_WRITE_DATA;
269 	if ((value & 0x3f) == 0x09) tc->command = CMD_WRITE_DELETED_DATA;
270 	if ((value & 0x1f) == 0x0c) tc->command = CMD_READ_DELETED_DATA;
271 	if ((value & 0xbf) == 0x02) tc->command = CMD_READ_DIAGNOSTIC;
272 	if ((value & 0xbf) == 0x0a) tc->command = CMD_READ_ID;
273 	if ((value & 0xbf) == 0x0d) tc->command = CMD_FORMAT;
274 	if ((value & 0x1f) == 0x11) tc->command = CMD_SCAN_EQUAL;
275 	if ((value & 0x1f) == 0x19) tc->command = CMD_SCAN_LOW_OR_EQUAL;
276 	if ((value & 0x1f) == 0x1d) tc->command = CMD_SCAN_HIGH_OR_EQUAL;
277 	if ((value & 0xff) == 0x0f) tc->command = CMD_SEEK;
278 	if ((value & 0xff) == 0x07) tc->command = CMD_RECALIBRATE;
279 	if ((value & 0xff) == 0x08) tc->command = CMD_SENSE_INTERRUPT_STATUS;
280 	if ((value & 0xff) == 0x03) tc->command = CMD_SPECIFY;
281 	if ((value & 0xff) == 0x04) tc->command = CMD_SENSE_DEVICE_STATUS;
282 
283     tc->commandCode = value;
284 
285 	tc->phase       = PHASE_COMMAND;
286 	tc->phaseStep   = 0;
287     tc->mainStatus |= STM_CB;
288 
289     switch (tc->command) {
290 	case CMD_READ_DATA:
291 	case CMD_WRITE_DATA:
292 	case CMD_FORMAT:
293         tc->status0 &= ~(ST0_IC0 | ST0_IC1);
294         tc->status1 &= ~(ST1_ND | ST1_NW);
295         tc->status2 &= ~ST2_DD;
296 		break;
297 
298 	case CMD_RECALIBRATE:
299         tc->status0 &= ~ST0_SE;
300 		break;
301 
302 	case CMD_SENSE_INTERRUPT_STATUS:
303 		tc->phase       = PHASE_RESULT;
304         tc->mainStatus |= STM_DIO;
305         break;
306 
307     case CMD_SEEK:
308 	case CMD_SPECIFY:
309 	case CMD_SENSE_DEVICE_STATUS:
310         break;
311 
312     default:
313         tc->mainStatus &= ~STM_CB;
314 		tc->phase       = PHASE_IDLE;
315     }
316 }
317 
tc8566afCommandPhaseWrite(TC8566AF * tc,UInt8 value)318 static void tc8566afCommandPhaseWrite(TC8566AF* tc, UInt8 value)
319 {
320     switch (tc->command) {
321 	case CMD_READ_DATA:
322 	case CMD_WRITE_DATA:
323 		switch (tc->phaseStep++) {
324 		case 0:
325             tc->status0 &= ~(ST0_DS0 | ST0_DS1 | ST0_IC0 | ST0_IC1);
326             tc->status0 |= (diskPresent(tc->drive) ? 0 : ST0_DS0) | (value & (ST0_DS0 | ST0_DS1)) |
327                            (diskEnabled(tc->drive) ? 0 : ST0_IC1);
328             tc->status3  = (value & (ST3_DS0 | ST3_DS1)) |
329                            (tc->currentTrack == 0        ? ST3_TK0 : 0) |
330                            (diskGetSides(tc->drive) == 2 ? ST3_HD  : 0) |
331                            (diskReadOnly(tc->drive)      ? ST3_WP  : 0) |
332                            (diskPresent(tc->drive)       ? ST3_RDY : 0);
333 			break;
334 		case 1:
335             tc->cylinderNumber = value;
336 			break;
337 		case 2:
338             tc->side = value & 1;
339 			break;
340 		case 3:
341             tc->sectorNumber = value;
342 			break;
343 		case 4:
344             tc->number = value;
345             tc->sectorOffset = (value == 2 && (tc->commandCode & 0xc0) == 0x40) ? 0 : 512;
346 			break;
347 		case 7:
348             if (tc->command == CMD_READ_DATA) {
349                 int sectorSize;
350         		DSKE rv = diskReadSector(tc->drive, tc->sectorBuf, tc->sectorNumber, tc->side,
351                                          tc->currentTrack, 0, &sectorSize);
352                 fdcAudioSetReadWrite(tc->fdcAudio);
353                 boardSetFdcActive();
354                 if (rv == DSKE_NO_DATA) {
355                     tc->status0 |= ST0_IC0;
356                     tc->status1 |= ST1_ND;
357                 }
358                 if (rv == DSKE_CRC_ERROR) {
359                     tc->status0 |= ST0_IC0;
360                     tc->status1 |= ST1_DE;
361                     tc->status2 |= ST2_DD;
362                 }
363                 tc->mainStatus |= STM_DIO;
364             }
365             else {
366                 tc->mainStatus &= ~STM_DIO;
367             }
368 			tc->phase = PHASE_DATATRANSFER;
369 			tc->phaseStep = 0;
370 			break;
371 		}
372 		break;
373 
374 	case CMD_FORMAT:
375 		switch (tc->phaseStep++) {
376 		case 0:
377             tc->status0 &= ~(ST0_DS0 | ST0_DS1 | ST0_IC0 | ST0_IC1);
378             tc->status0 |= (diskPresent(tc->drive) ? 0 : ST0_DS0) | (value & (ST0_DS0 | ST0_DS1)) |
379                            (diskEnabled(tc->drive) ? 0 : ST0_IC1);
380             tc->status3  = (value & (ST3_DS0 | ST3_DS1)) |
381                            (tc->currentTrack == 0        ? ST3_TK0 : 0) |
382                            (diskGetSides(tc->drive) == 2 ? ST3_HD  : 0) |
383                            (diskReadOnly(tc->drive)      ? ST3_WP  : 0) |
384                            (diskPresent(tc->drive)       ? ST3_RDY : 0);
385 			break;
386 		case 1:
387             tc->number = value;
388 			break;
389 		case 2:
390             tc->sectorsPerCylinder = value;
391             tc->sectorNumber       = value;
392 			break;
393 		case 4:
394             tc->fillerByte   = value;
395             tc->sectorOffset = 0;
396             tc->mainStatus  &= ~STM_DIO;
397 			tc->phase        = PHASE_DATATRANSFER;
398 			tc->phaseStep    = 0;
399 			break;
400         }
401         break;
402 
403 	case CMD_SEEK:
404 		switch (tc->phaseStep++) {
405 		case 0:
406             tc->status0 &= ~(ST0_DS0 | ST0_DS1 | ST0_IC0 | ST0_IC1);
407             tc->status0 |= (diskPresent(tc->drive) ? 0 : ST0_DS0) | (value & (ST0_DS0 | ST0_DS1)) |
408                            (diskEnabled(tc->drive) ? 0 : ST0_IC1);
409             tc->status3  = (value & (ST3_DS0 | ST3_DS1)) |
410                            (tc->currentTrack == 0        ? ST3_TK0 : 0) |
411                            (diskGetSides(tc->drive) == 2 ? ST3_HD  : 0) |
412                            (diskReadOnly(tc->drive)      ? ST3_WP  : 0) |
413                            (diskPresent(tc->drive)       ? ST3_RDY : 0);
414 			break;
415 		case 1:
416             tc->currentTrack = value;
417             tc->status0     |= ST0_SE;
418             tc->mainStatus  &= ~STM_CB;
419 			tc->phase        = PHASE_IDLE;
420 			break;
421 		}
422 		break;
423 
424 	case CMD_RECALIBRATE:
425 		switch (tc->phaseStep++) {
426 		case 0:
427             tc->status0 &= ~(ST0_DS0 | ST0_DS1 | ST0_IC0 | ST0_IC1);
428             tc->status0 |= (diskPresent(tc->drive) ? 0 : ST0_DS0) | (value & (ST0_DS0 | ST0_DS1)) |
429                            (diskEnabled(tc->drive) ? 0 : ST0_IC1);
430             tc->status3  = (value & (ST3_DS0 | ST3_DS1)) |
431                            (tc->currentTrack == 0        ? ST3_TK0 : 0) |
432                            (diskGetSides(tc->drive) == 2 ? ST3_HD  : 0) |
433                            (diskReadOnly(tc->drive)      ? ST3_WP  : 0) |
434                            (diskPresent(tc->drive)       ? ST3_RDY : 0);
435 
436             tc->currentTrack = 0;
437             tc->status0     |= ST0_SE;
438             tc->mainStatus  &= ~STM_CB;
439 			tc->phase        = PHASE_IDLE;
440 			break;
441 		}
442 		break;
443 
444 	case CMD_SPECIFY:
445 		switch (tc->phaseStep++) {
446 		case 1:
447             tc->mainStatus &= ~STM_CB;
448 			tc->phase       = PHASE_IDLE;
449 			break;
450 		}
451 		break;
452 
453 	case CMD_SENSE_DEVICE_STATUS:
454 		switch (tc->phaseStep++) {
455 		case 0:
456             tc->status0 &= ~(ST0_DS0 | ST0_DS1 | ST0_IC0 | ST0_IC1);
457             tc->status0 |= (diskPresent(tc->drive) ? 0 : ST0_DS0) | (value & (ST0_DS0 | ST0_DS1)) |
458                            (diskEnabled(tc->drive) ? 0 : ST0_IC1);
459             tc->status3  = (value & (ST3_DS0 | ST3_DS1)) |
460                            (tc->currentTrack == 0        ? ST3_TK0 : 0) |
461                            (diskGetSides(tc->drive) == 2 ? ST3_HD  : 0) |
462                            (diskReadOnly(tc->drive)      ? ST3_WP  : 0) |
463                            (diskPresent(tc->drive)       ? ST3_RDY : 0);
464 
465 		    tc->phase       = PHASE_RESULT;
466             tc->phaseStep   = 0;
467             tc->mainStatus |= STM_DIO;
468 			break;
469 		}
470 		break;
471 	}
472 }
473 
tc8566afExecutionPhaseWrite(TC8566AF * tc,UInt8 value)474 static void tc8566afExecutionPhaseWrite(TC8566AF* tc, UInt8 value)
475 {
476     int rv;
477 
478 	switch (tc->command) {
479 	case CMD_WRITE_DATA:
480 		if (tc->sectorOffset < 512) {
481 			tc->sectorBuf[tc->sectorOffset++] = value;
482 
483     		if (tc->sectorOffset == 512) {
484                 rv = diskWriteSector(tc->drive, tc->sectorBuf, tc->sectorNumber, tc->side,
485                                      tc->currentTrack, 0);
486                 if (!rv) {
487                     tc->status1 |= ST1_NW;
488                 }
489 
490                 fdcAudioSetReadWrite(tc->fdcAudio);
491 
492                 boardSetFdcActive();
493 
494                 tc->phase       = PHASE_RESULT;
495                 tc->phaseStep   = 0;
496                 tc->mainStatus |= STM_DIO;
497             }
498         }
499 		break;
500 
501     case CMD_FORMAT:
502         switch(tc->phaseStep & 3) {
503         case 0:
504             tc->currentTrack = value;
505             break;
506         case 1:
507             memset(tc->sectorBuf, tc->fillerByte, 512);
508             rv = diskWrite(tc->drive, tc->sectorBuf, tc->sectorNumber - 1 +
509                       diskGetSectorsPerTrack(tc->drive) * (tc->currentTrack * diskGetSides(tc->drive) + value));
510             if (!rv) {
511                 tc->status1 |= ST1_NW;
512             }
513             boardSetFdcActive();
514             break;
515         case 2:
516             tc->sectorNumber = value;
517             break;
518         }
519 
520         if (++tc->phaseStep == 4 * tc->sectorsPerCylinder - 2) {
521             tc->phase       = PHASE_RESULT;
522             tc->phaseStep   = 0;
523             tc->mainStatus |= STM_DIO;
524         }
525         break;
526 	}
527 }
528 
tc8566afCreate()529 TC8566AF* tc8566afCreate()
530 {
531     TC8566AF* tc = malloc(sizeof(TC8566AF));
532 
533     tc->fdcAudio = fdcAudioCreate(FA_PANASONIC);
534 
535     tc8566afReset(tc);
536 
537     return tc;
538 }
539 
tc8566afDestroy(TC8566AF * tc)540 void tc8566afDestroy(TC8566AF* tc)
541 {
542     fdcAudioDestroy(tc->fdcAudio);
543     free(tc);
544 }
545 
tc8566afReset(TC8566AF * tc)546 void tc8566afReset(TC8566AF* tc)
547 {
548     FdcAudio* fdcAudio = tc->fdcAudio;
549     memset(tc, 0, sizeof(TC8566AF));
550     tc->fdcAudio = fdcAudio;
551 
552     tc->mainStatus = STM_NDM | STM_RQM;
553 
554     ledSetFdd1(0); /* 10:10 2004/10/09 FDD LED PATCH */
555     ledSetFdd2(0); /* 10:10 2004/10/09 FDD LED PATCH */
556 
557     fdcAudioReset(tc->fdcAudio);
558 }
559 
tc8566afReadRegister(TC8566AF * tc,UInt8 reg)560 UInt8 tc8566afReadRegister(TC8566AF* tc, UInt8 reg)
561 {
562     switch (reg) {
563     case 4:
564         if (~tc->mainStatus & STM_RQM) {
565             UInt32 elapsed = boardSystemTime() - tc->dataTransferTime;
566             if (elapsed > boardFrequency() * 60 / 1000000) {
567                 tc->mainStatus |= STM_RQM;
568             }
569         }
570 //        return tc->mainStatus;
571   return (tc->mainStatus & ~ STM_NDM) | (tc->phase == PHASE_DATATRANSFER ? STM_NDM : 0);
572 
573 	case 5:
574         switch (tc->phase) {
575 		case PHASE_DATATRANSFER:
576             reg = tc8566afExecutionPhaseRead(tc);
577             tc->dataTransferTime = boardSystemTime();
578             tc->mainStatus &= ~STM_RQM;
579             return reg;
580 
581 		case PHASE_RESULT:
582             return tc8566afResultsPhaseRead(tc);
583         }
584     }
585 
586     return 0x00;
587 }
588 
tc8566afPeekRegister(TC8566AF * tc,UInt8 reg)589 UInt8 tc8566afPeekRegister(TC8566AF* tc, UInt8 reg)
590 {
591     switch (reg) {
592     case 4:
593         return tc->mainStatus;
594 	case 5:
595         switch (tc->phase) {
596 		case PHASE_DATATRANSFER:
597             return tc8566afExecutionPhasePeek(tc);
598 		case PHASE_RESULT:
599             return tc8566afResultsPhasePeek(tc);
600         }
601     }
602     return 0xff;
603 }
604 
tc8566afWriteRegister(TC8566AF * tc,UInt8 reg,UInt8 value)605 void tc8566afWriteRegister(TC8566AF* tc, UInt8 reg, UInt8 value)
606 {
607     switch (reg) {
608 	case 2:
609         fdcAudioSetMotor(tc->fdcAudio, ((value & 0x10) && diskEnabled(0)) || ((value & 0x20) && diskEnabled(1)));
610 
611         ledSetFdd1((value & 0x10) && diskEnabled(0)); /* 10:10 2004/10/09 FDD LED PATCH */
612         ledSetFdd2((value & 0x20) && diskEnabled(1)); /* 10:10 2004/10/09 FDD LED PATCH */
613 
614         tc->drive = value & 0x03;
615         break;
616 
617 	case 5:
618         switch (tc->phase) {
619 	    case PHASE_IDLE:
620             tc8566afIdlePhaseWrite(tc, value);
621             break;
622 
623         case PHASE_COMMAND:
624             tc8566afCommandPhaseWrite(tc, value);
625             break;
626 
627 		case PHASE_DATATRANSFER:
628             tc8566afExecutionPhaseWrite(tc, value);
629             tc->dataTransferTime = boardSystemTime();
630             tc->mainStatus &= ~STM_RQM;
631         	break;
632         }
633 		break;
634     }
635 }
636 
tc8566afDiskChanged(TC8566AF * tc,int drive)637 int tc8566afDiskChanged(TC8566AF* tc, int drive)
638 {
639     return diskChanged(drive);
640 }
641 
tc8566afLoadState(TC8566AF * tc)642 void tc8566afLoadState(TC8566AF* tc)
643 {
644     SaveState* state = saveStateOpenForRead("tc8566af");
645 
646     tc->drive               = (UInt8) saveStateGet(state, "drive",              0);
647     tc->mainStatus          = (UInt8) saveStateGet(state, "mainStatus",         STM_NDM | STM_RQM);
648     tc->status0             = (UInt8) saveStateGet(state, "status0",            0);
649     tc->status1             = (UInt8) saveStateGet(state, "status1",            0);
650     tc->status2             = (UInt8) saveStateGet(state, "status2",            0);
651     tc->status3             = (UInt8) saveStateGet(state, "status3",            0);
652     tc->commandCode         = (UInt8) saveStateGet(state, "commandCode",        0);
653     tc->command             =         saveStateGet(state, "command",            0);
654     tc->phase               =         saveStateGet(state, "phase",              0);
655     tc->phaseStep           =         saveStateGet(state, "phaseStep",          0);
656     tc->cylinderNumber      = (UInt8) saveStateGet(state, "cylinderNumber",     0);
657     tc->side                = (UInt8) saveStateGet(state, "side",               0);
658     tc->sectorNumber        = (UInt8) saveStateGet(state, "sectorNumber",       0);
659     tc->number              = (UInt8) saveStateGet(state, "number",             0);
660     tc->currentTrack        = (UInt8) saveStateGet(state, "currentTrack",       0);
661     tc->sectorsPerCylinder  = (UInt8) saveStateGet(state, "sectorsPerCylinder", 0);
662     tc->sectorOffset        =         saveStateGet(state, "sectorOffset",       0);
663     tc->dataTransferTime    =         saveStateGet(state, "dataTransferTime",   0);
664 
665     saveStateGetBuffer(state, "sectorBuf", tc->sectorBuf, 512);
666 
667     saveStateClose(state);
668 }
669 
tc8566afSaveState(TC8566AF * tc)670 void tc8566afSaveState(TC8566AF* tc)
671 {
672     SaveState* state = saveStateOpenForWrite("tc8566af");
673 
674     saveStateSet(state, "drive",              tc->drive);
675     saveStateSet(state, "mainStatus",         tc->mainStatus);
676     saveStateSet(state, "status0",            tc->status0);
677     saveStateSet(state, "status1",            tc->status1);
678     saveStateSet(state, "status2",            tc->status2);
679     saveStateSet(state, "status3",            tc->status3);
680     saveStateSet(state, "commandCode",        tc->commandCode);
681     saveStateSet(state, "command",            tc->command);
682     saveStateSet(state, "phase",              tc->phase);
683     saveStateSet(state, "phaseStep",          tc->phaseStep);
684     saveStateSet(state, "cylinderNumber",     tc->cylinderNumber);
685     saveStateSet(state, "side",               tc->side);
686     saveStateSet(state, "sectorNumber",       tc->sectorNumber);
687     saveStateSet(state, "number",             tc->number);
688     saveStateSet(state, "currentTrack",       tc->currentTrack);
689     saveStateSet(state, "sectorsPerCylinder", tc->sectorsPerCylinder);
690     saveStateSet(state, "sectorOffset",       tc->sectorOffset);
691     saveStateSet(state, "dataTransferTime",   tc->dataTransferTime);
692 
693     saveStateSetBuffer(state, "sectorBuf", tc->sectorBuf, 512);
694 
695     saveStateClose(state);
696 }
697