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, §orSize);
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