16 static const byte STM_DB0 = 0x01;
17 static const byte STM_DB1 = 0x02;
18 static const byte STM_DB2 = 0x04;
19 static const byte STM_DB3 = 0x08;
20 static const byte STM_CB = 0x10;
21 static const byte STM_NDM = 0x20;
22 static const byte STM_DIO = 0x40;
23 static const byte STM_RQM = 0x80;
25 static const byte ST0_DS0 = 0x01;
26 static const byte ST0_DS1 = 0x02;
27 static const byte ST0_HD = 0x04;
28 static const byte ST0_NR = 0x08;
29 static const byte ST0_EC = 0x10;
30 static const byte ST0_SE = 0x20;
31 static const byte ST0_IC0 = 0x40;
32 static const byte ST0_IC1 = 0x80;
34 static const byte ST1_MA = 0x01;
35 static const byte ST1_NW = 0x02;
36 static const byte ST1_ND = 0x04;
38 static const byte ST1_OR = 0x10;
39 static const byte ST1_DE = 0x20;
41 static const byte ST1_EN = 0x80;
43 static const byte ST2_MD = 0x01;
44 static const byte ST2_BC = 0x02;
45 static const byte ST2_SN = 0x04;
46 static const byte ST2_SH = 0x08;
47 static const byte ST2_NC = 0x10;
48 static const byte ST2_DD = 0x20;
49 static const byte ST2_CM = 0x40;
52 static const byte ST3_DS0 = 0x01;
53 static const byte ST3_DS1 = 0x02;
54 static const byte ST3_HD = 0x04;
55 static const byte ST3_2S = 0x08;
56 static const byte ST3_TK0 = 0x10;
57 static const byte ST3_RDY = 0x20;
58 static const byte ST3_WP = 0x40;
59 static const byte ST3_FLT = 0x80;
104 sectorsPerCylinder = 0;
112 mainStatus = STM_RQM;
122 return peekDataPort(time);
131 return readStatus(time);
133 return readDataPort(time);
138 byte TC8566AF::peekStatus()
const
140 bool nonDMAMode = specifyData[1] & 1;
142 return mainStatus | (dma ? STM_NDM : 0);
147 if (delayTime.
before(time)) {
148 mainStatus |= STM_RQM;
153 void TC8566AF::setDrqRate()
162 return executionPhasePeek(time);
164 return resultsPhasePeek();
175 if (delayTime.
before(time)) {
176 return executionPhaseRead(time);
181 return resultsPhaseRead(time);
191 if (delayTime.
before(time)) {
192 assert(dataAvailable);
193 return trackData.
read(dataCurrent);
206 assert(dataAvailable);
207 byte result = trackData.
read(dataCurrent++);
211 mainStatus &= ~STM_RQM;
212 if (delayTime.
before(time)) {
217 }
else if (!dataAvailable) {
219 word diskCrc = 256 * trackData.
read(dataCurrent++);
220 diskCrc += trackData.
read(dataCurrent++);
235 byte TC8566AF::resultsPhasePeek()
const
249 return cylinderNumber;
283 byte result = resultsPhasePeek();
288 switch (phaseStep++) {
296 switch (phaseStep++) {
304 switch (phaseStep++) {
321 drive[3]->
setMotor((data & 0x80) != 0, time);
322 drive[2]->
setMotor((data & 0x40) != 0, time);
323 drive[1]->
setMotor((data & 0x20) != 0, time);
324 drive[0]->
setMotor((data & 0x10) != 0, time);
327 driveSelect = data & 0x03;
335 writeDataPort(data, time);
344 idlePhaseWrite(value, time);
348 commandPhaseWrite(value, time);
352 executionPhaseWrite(value, time);
369 if ((commandCode & 0xbf) == 0x0a) command =
CMD_READ_ID;
370 if ((commandCode & 0xbf) == 0x0d) command =
CMD_FORMAT;
374 if ((commandCode & 0xff) == 0x0f) command =
CMD_SEEK;
377 if ((commandCode & 0xff) == 0x03) command =
CMD_SPECIFY;
382 mainStatus |= STM_CB;
388 status0 &= ~(ST0_IC0 | ST0_IC1);
414 void TC8566AF::commandPhase1(
byte value)
416 drive[driveSelect]->
setSide((value & 0x04) != 0);
417 status0 &= ~(ST0_DS0 | ST0_DS1 | ST0_IC0 | ST0_IC1);
419 (value & (ST0_DS0 | ST0_DS1)) |
421 status3 = (value & (ST3_DS0 | ST3_DS1)) |
422 (drive[driveSelect]->
isTrack00() ? ST3_TK0 : 0) |
423 (drive[driveSelect]->isDoubleSided() ? ST3_HD : 0) |
424 (drive[driveSelect]->isWriteProtected() ? ST3_WP : 0) |
425 (drive[driveSelect]->isDiskInserted() ? ST3_RDY : 0);
430 RawTrack::Sector sectorInfo;
436 next, trackData, sectorInfo);
438 }
catch (MSXException& ) {
442 (sectorInfo.addrIdx == lastIdx)) {
446 if (lastIdx == -1) lastIdx = sectorInfo.addrIdx;
447 if (sectorInfo.addrCrcErr)
continue;
448 if (sectorInfo.track != cylinderNumber)
continue;
449 if (sectorInfo.head != headNumber)
continue;
450 if (sectorInfo.sector != sectorNumber)
continue;
454 dataAvailable = 128 << (sectorInfo.sizeCode & 7);
455 dataCurrent = sectorInfo.dataIdx;
464 switch (phaseStep++) {
466 commandPhase1(value);
469 cylinderNumber = value;
475 sectorNumber = value;
491 if (!isHeadLoaded(time)) {
492 ready += getHeadLoadDelay();
499 ready = locateSector(ready);
507 mainStatus |= STM_DIO;
509 mainStatus &= ~STM_DIO;
513 crc.
init<0xA1, 0xA1, 0xA1, 0xFB>();
517 delayTime.
reset(ready);
518 mainStatus &= ~STM_RQM;
524 switch (phaseStep++) {
526 commandPhase1(value);
532 sectorsPerCylinder = value;
533 sectorNumber = value;
540 mainStatus &= ~STM_DIO;
544 initTrackHeader(time);
550 switch (phaseStep++) {
552 commandPhase1(value);
562 switch (phaseStep++) {
564 commandPhase1(value);
572 specifyData[phaseStep] = value;
573 switch (phaseStep++) {
581 switch (phaseStep++) {
583 commandPhase1(value);
598 drive[driveSelect]->
readTrack(trackData);
599 }
catch (MSXException& ) {
607 for (
int i = 0; i < 80; ++i) trackData.
write(dataCurrent++, 0x4E);
608 for (
int i = 0; i < 12; ++i) trackData.
write(dataCurrent++, 0x00);
609 for (
int i = 0; i < 3; ++i) trackData.
write(dataCurrent++, 0xC2);
610 for (
int i = 0; i < 1; ++i) trackData.
write(dataCurrent++, 0xFC);
611 for (
int i = 0; i < 50; ++i) trackData.
write(dataCurrent++, 0x4E);
614 void TC8566AF::formatSector()
616 for (
int i = 0; i < 12; ++i) trackData.
write(dataCurrent++, 0x00);
618 for (
int i = 0; i < 3; ++i) trackData.
write(dataCurrent++, 0xA1);
619 trackData.
addIdam(dataCurrent);
620 for (
int i = 0; i < 1; ++i) trackData.
write(dataCurrent++, 0xFE);
621 trackData.
write(dataCurrent++, currentTrack);
622 trackData.
write(dataCurrent++, headNumber);
623 trackData.
write(dataCurrent++, sectorNumber);
624 trackData.
write(dataCurrent++, number);
625 word addrCrc = trackData.
calcCrc(dataCurrent - 8, 8);
626 trackData.
write(dataCurrent++, addrCrc >> 8);
627 trackData.
write(dataCurrent++, addrCrc & 0xff);
629 for (
int i = 0; i < 22; ++i) trackData.
write(dataCurrent++, 0x4E);
630 for (
int i = 0; i < 12; ++i) trackData.
write(dataCurrent++, 0x00);
632 for (
int i = 0; i < 3; ++i) trackData.
write(dataCurrent++, 0xA1);
633 for (
int i = 0; i < 1; ++i) trackData.
write(dataCurrent++, 0xFB);
635 int sectorSize = 128 << (number & 7);
636 for (
int i = 0; i < sectorSize; ++i) trackData.
write(dataCurrent++, fillerByte);
638 word dataCrc = trackData.
calcCrc(dataCurrent - (sectorSize + 4), sectorSize + 4);
639 trackData.
write(dataCurrent++, dataCrc >> 8);
640 trackData.
write(dataCurrent++, dataCrc & 0xff);
642 for (
int i = 0; i < gapLength; ++i) trackData.
write(dataCurrent++, 0x4E);
647 DiskDrive& currentDrive = *drive[driveSelect];
649 bool direction =
false;
652 if (seekValue > currentTrack) {
655 }
else if (seekValue < currentTrack) {
659 assert(seekValue == currentTrack);
666 if (currentDrive.isTrack00() || (seekValue == 0)) {
667 if (seekValue == 0) {
682 currentDrive.step(direction, time);
695 void TC8566AF::writeSector()
707 assert(dataAvailable);
708 trackData.
write(dataCurrent++, value);
712 mainStatus &= ~STM_RQM;
713 if (delayTime.
before(time)) {
718 }
else if (!dataAvailable) {
721 }
catch (MSXException&) {
731 mainStatus &= ~STM_RQM;
732 switch (phaseStep & 3) {
734 currentTrack = value;
740 sectorNumber = value;
749 if (phaseStep == 4 * sectorsPerCylinder) {
753 }
catch (MSXException&) {
766 void TC8566AF::resultPhase()
768 mainStatus |= STM_DIO | STM_RQM;
777 mainStatus &= ~(STM_CB | STM_DIO);
778 delayTime.
reset(time);
780 headUnloadTime = time + getHeadUnloadDelay();
786 assert(driveNum < 4);
792 assert(driveNum < 4);
799 return time < headUnloadTime;
816 static enum_string<TC8566AF::Command> commandInfo[] = {
836 static enum_string<TC8566AF::Phase> phaseInfo[] = {
852 template<
typename Archive>
855 if (ar.versionAtLeast(version, 4)) {
856 ar.serialize(
"delayTime", delayTime);
858 assert(ar.isLoader());
860 ar.serialize(
"delayTime", c);
861 delayTime.
reset(c.getTime());
864 ar.serialize(
"command", command);
865 ar.serialize(
"phase", phase);
866 ar.serialize(
"phaseStep", phaseStep);
867 ar.serialize(
"driveSelect", driveSelect);
868 ar.serialize(
"mainStatus", mainStatus);
869 ar.serialize(
"status0", status0);
870 ar.serialize(
"status1", status1);
871 ar.serialize(
"status2", status2);
872 ar.serialize(
"status3", status3);
873 ar.serialize(
"commandCode", commandCode);
874 ar.serialize(
"cylinderNumber", cylinderNumber);
875 ar.serialize(
"headNumber", headNumber);
876 ar.serialize(
"sectorNumber", sectorNumber);
877 ar.serialize(
"number", number);
878 ar.serialize(
"currentTrack", currentTrack);
879 ar.serialize(
"sectorsPerCylinder", sectorsPerCylinder);
880 ar.serialize(
"fillerByte", fillerByte);
881 if (ar.versionAtLeast(version, 2)) {
882 ar.template serializeBase<Schedulable>(*this);
883 ar.serialize(
"specifyData", specifyData);
884 ar.serialize(
"headUnloadTime", headUnloadTime);
885 ar.serialize(
"seekValue", seekValue);
887 assert(ar.isLoader());
888 specifyData[0] = 0xDF;
889 specifyData[1] = 0x03;
893 if (ar.versionAtLeast(version, 3)) {
894 ar.serialize(
"dataAvailable", dataAvailable);
895 ar.serialize(
"dataCurrent", dataCurrent);
896 ar.serialize(
"trackData", trackData);
897 ar.serialize(
"gapLength", gapLength);
899 ar.serialize(
"crc", crcVal);
916 "Loading an old savestate that had an "
917 "in-progress TC8566AF data-transfer command. "
918 "This is not fully backwards-compatible and "
919 "could cause wrong emulation behavior.");