branches/alto2/src/emu/cpu/alto2/a2disk.c
| r26169 | r26170 | |
| 66 | 66 | #define GET_KCOM_SENDADR(kcom) A2_GET16(kcom,16,5,5) //!< get send address flag from controller command (hardware command register) |
| 67 | 67 | #define PUT_KCOM_SENDADR(kcom,val) A2_PUT16(kcom,16,5,5,val) //!< put send address flag into controller command (hardware command register) |
| 68 | 68 | |
| 69 | /** |
| 70 | * @brief callback is called by the drive timer whenever a new sector starts |
| 71 | * |
| 72 | * @param unit the unit number |
| 73 | */ |
| 74 | static void disk_sector_start(void* cookie, int unit) |
| 75 | { |
| 76 | alto2_cpu_device* cpu = reinterpret_cast<alto2_cpu_device *>(cookie); |
| 77 | cpu->next_sector(unit); |
| 78 | } |
| 79 | |
| 69 | 80 | /** @brief completion codes (only for documentation, since this is microcode defined) */ |
| 70 | 81 | enum { |
| 71 | 82 | STATUS_COMPLETION_GOOD, |
| r26169 | r26170 | |
| 125 | 136 | /* both J and K' are 0: set Q to 0, Q' to 1 */ |
| 126 | 137 | s1 = (s1 & ~JKFF_Q) | JKFF_Q0; |
| 127 | 138 | if (s0 & JKFF_Q) { |
| 128 | | LOG((LOG_DISK,5,"%s J:0 K':0 → Q:0\n", jkff_name)); |
| 139 | LOG((LOG_DISK,9,"%s J:0 K':0 → Q:0\n", jkff_name)); |
| 129 | 140 | } |
| 130 | 141 | break; |
| 131 | 142 | case JKFF_J: |
| r26169 | r26170 | |
| 134 | 145 | s1 = (s1 & ~JKFF_Q) | JKFF_Q0; |
| 135 | 146 | else |
| 136 | 147 | s1 = (s1 | JKFF_Q) & ~JKFF_Q0; |
| 137 | | LOG((LOG_DISK,5,"%s J:0 K':1 flip-flop Q:%d\n", jkff_name, (s1 & JKFF_Q) ? 1 : 0)); |
| 148 | LOG((LOG_DISK,9,"%s J:0 K':1 flip-flop Q:%d\n", jkff_name, (s1 & JKFF_Q) ? 1 : 0)); |
| 138 | 149 | break; |
| 139 | 150 | case JKFF_K: |
| 140 | 151 | if ((s0 ^ s1) & JKFF_Q) { |
| 141 | | LOG((LOG_DISK,5,"%s J:0 K':1 keep Q:%d\n", jkff_name, (s1 & JKFF_Q) ? 1 : 0)); |
| 152 | LOG((LOG_DISK,9,"%s J:0 K':1 keep Q:%d\n", jkff_name, (s1 & JKFF_Q) ? 1 : 0)); |
| 142 | 153 | } |
| 143 | 154 | /* J is 0, and K' is 1: keep Q as is */ |
| 144 | 155 | if (s0 & JKFF_Q) |
| r26169 | r26170 | |
| 150 | 161 | /* both J and K' are 1: set Q to 1 */ |
| 151 | 162 | s1 = (s1 | JKFF_Q) & ~JKFF_Q0; |
| 152 | 163 | if (!(s0 & JKFF_Q)) { |
| 153 | | LOG((LOG_DISK,5,"%s J:1 K':1 → Q:1\n", jkff_name)); |
| 164 | LOG((LOG_DISK,9,"%s J:1 K':1 → Q:1\n", jkff_name)); |
| 154 | 165 | } |
| 155 | 166 | break; |
| 156 | 167 | } |
| r26169 | r26170 | |
| 163 | 174 | /* S' is 1, C' is 0: set Q to 0, Q' to 1 */ |
| 164 | 175 | s1 = (s1 & ~JKFF_Q) | JKFF_Q0; |
| 165 | 176 | if (s0 & JKFF_Q) { |
| 166 | | LOG((LOG_DISK,5,"%s C':0 → Q:0\n", jkff_name)); |
| 177 | LOG((LOG_DISK,9,"%s C':0 → Q:0\n", jkff_name)); |
| 167 | 178 | } |
| 168 | 179 | break; |
| 169 | 180 | case JKFF_C: |
| 170 | 181 | /* S' is 0, C' is 1: set Q to 1, Q' to 0 */ |
| 171 | 182 | s1 = (s1 | JKFF_Q) & ~JKFF_Q0; |
| 172 | 183 | if (!(s0 & JKFF_Q)) { |
| 173 | | LOG((LOG_DISK,5,"%s S':0 → Q:1\n", jkff_name)); |
| 184 | LOG((LOG_DISK,9,"%s S':0 → Q:1\n", jkff_name)); |
| 174 | 185 | } |
| 175 | 186 | break; |
| 176 | 187 | case 0: |
| 177 | 188 | default: |
| 178 | 189 | /* unstable state (what to do?) */ |
| 179 | 190 | s1 = s1 | JKFF_Q | JKFF_Q0; |
| 180 | | LOG((LOG_DISK,5,"%s C':0 S':0 → Q:1 and Q':1 <unstable>\n", jkff_name)); |
| 191 | LOG((LOG_DISK,9,"%s C':0 S':0 → Q:1 and Q':1 <unstable>\n", jkff_name)); |
| 181 | 192 | break; |
| 182 | 193 | } |
| 183 | 194 | return static_cast<jkff_t>(s1); |
| r26169 | r26170 | |
| 770 | 781 | { |
| 771 | 782 | UINT8 result = jkff_lookup[s1 & 63][ s0 & 63]; |
| 772 | 783 | #if ALTO2_DEBUG |
| 773 | | LOG((LOG_DISK,8,"%s : ", jkff_name)); |
| 784 | LOG((LOG_DISK,9,"%s : ", jkff_name)); |
| 774 | 785 | if ((s0 ^ result) & JKFF_CLK) |
| 775 | | LOG((LOG_DISK,8," CLK%s", raise_lower[result & 1])); |
| 786 | LOG((LOG_DISK,9," CLK%s", raise_lower[result & 1])); |
| 776 | 787 | if ((s0 ^ result) & JKFF_J) |
| 777 | | LOG((LOG_DISK,8," J%s", raise_lower[(result >> 1) & 1])); |
| 788 | LOG((LOG_DISK,9," J%s", raise_lower[(result >> 1) & 1])); |
| 778 | 789 | if ((s0 ^ result) & JKFF_K) |
| 779 | | LOG((LOG_DISK,8," K'%s", raise_lower[(result >> 2) & 1])); |
| 790 | LOG((LOG_DISK,9," K'%s", raise_lower[(result >> 2) & 1])); |
| 780 | 791 | if ((s0 ^ result) & JKFF_S) |
| 781 | | LOG((LOG_DISK,8," S'%s", raise_lower[(result >> 3) & 1])); |
| 792 | LOG((LOG_DISK,9," S'%s", raise_lower[(result >> 3) & 1])); |
| 782 | 793 | if ((s0 ^ result) & JKFF_C) |
| 783 | | LOG((LOG_DISK,8," C'%s", raise_lower[(result >> 4) & 1])); |
| 794 | LOG((LOG_DISK,9," C'%s", raise_lower[(result >> 4) & 1])); |
| 784 | 795 | if ((s0 ^ result) & JKFF_Q) |
| 785 | | LOG((LOG_DISK,8," Q%s", raise_lower[(result >> 5) & 1])); |
| 796 | LOG((LOG_DISK,9," Q%s", raise_lower[(result >> 5) & 1])); |
| 786 | 797 | if ((s0 ^ result) & JKFF_Q0) |
| 787 | | LOG((LOG_DISK,8," Q'%s", raise_lower[(result >> 6) & 1])); |
| 788 | | LOG((LOG_DISK,8,"\n")); |
| 798 | LOG((LOG_DISK,9," Q'%s", raise_lower[(result >> 6) & 1])); |
| 799 | LOG((LOG_DISK,9,"\n")); |
| 789 | 800 | #endif |
| 790 | 801 | return static_cast<jkff_t>(result); |
| 791 | 802 | } |
| r26169 | r26170 | |
| 1044 | 1055 | */ |
| 1045 | 1056 | void alto2_cpu_device::kwd_timing(int bitclk, int datin, int block) |
| 1046 | 1057 | { |
| 1047 | | int wddone = m_dsk.wddone; |
| 1058 | diablo_hd_device* dhd = m_drive[m_dsk.drive]; |
| 1059 | int wddone = m_dsk.wddone; // get previous state of word-done |
| 1048 | 1060 | int i; |
| 1049 | 1061 | UINT8 s0, s1; |
| 1050 | 1062 | |
| 1051 | | diablo_hd_device* dhd = m_drive[m_dsk.drive]; |
| 1052 | | if (!dhd) { |
| 1053 | | LOG((LOG_DISK,3," unit #%d\n", m_dsk.drive)); |
| 1054 | | // FIXME: set all signals for a not connected drive |
| 1055 | | return; |
| 1063 | LOG((LOG_DISK,8," >>> KWD timing bitclk:%d datin:%d sect4:%d\n", bitclk, datin, m_dsk.sect4)); |
| 1064 | if (m_dsk.sect4 != dhd->get_sector_mark_0()) { |
| 1065 | // SECT[4] transition |
| 1066 | m_dsk.sect4 = dhd->get_sector_mark_0(); |
| 1067 | LOG((LOG_DISK,7," SECT[4]:%d changed\n", m_dsk.sect4)); |
| 1056 | 1068 | } |
| 1057 | | LOG((LOG_DISK,5," >>> KWD timing bitclk:%d datin:%d sect4:%d\n", bitclk, datin, dhd->get_sector_mark_0())); |
| 1058 | 1069 | |
| 1059 | 1070 | if (0 == m_dsk.seclate) { |
| 1060 | | /* If SECLATE is 0, WDDONE' never goes low (counter's clear has precedence). */ |
| 1061 | | LOG((LOG_DISK,3," SECLATE:0 clears bitcount:0\n")); |
| 1062 | | m_dsk.bitcount = 0; |
| 1063 | | m_dsk.carry = 0; |
| 1064 | | } else if (m_dsk.bitclk && !bitclk) { |
| 1065 | | /* |
| 1066 | | * If SECLATE is 1, the counter will count or load: |
| 1067 | | */ |
| 1071 | // if SECLATE is 0, WDDONE' never goes low (counter's clear has precedence). |
| 1072 | if (m_dsk.bitcount || m_dsk.carry) { |
| 1073 | LOG((LOG_DISK,7," SECLATE:0 clears bitcount:0\n")); |
| 1074 | m_dsk.bitcount = 0; |
| 1075 | m_dsk.carry = 0; |
| 1076 | } |
| 1077 | } |
| 1078 | if (0 != m_dsk.seclate && m_dsk.bitclk && !bitclk) { |
| 1079 | // if SECLATE is 1, the counter will count or load: |
| 1068 | 1080 | if ((m_dsk.shiftin & (1 << 16)) && !WFFO) { |
| 1069 | 1081 | /* |
| 1070 | 1082 | * If HIORDBIT is 1 at the falling edge of BITCLK, it sets the |
| r26169 | r26170 | |
| 1072 | 1084 | * counter. It has been loaded with 15, so it counts to 16 on |
| 1073 | 1085 | * the next rising edge and makes WDDONE' go to 0. |
| 1074 | 1086 | */ |
| 1075 | | LOG((LOG_DISK,3," HIORDBIT:1 sets WFFO:1\n")); |
| 1087 | LOG((LOG_DISK,7," HIORDBIT:1 sets WFFO:1\n")); |
| 1076 | 1088 | PUT_KCOM_WFFO(m_dsk.kcom, 1); |
| 1077 | 1089 | // TODO: show disk indicators |
| 1078 | 1090 | } |
| r26169 | r26170 | |
| 1089 | 1101 | */ |
| 1090 | 1102 | m_dsk.bitcount = (m_dsk.bitcount + 1) % 16; |
| 1091 | 1103 | m_dsk.carry = m_dsk.bitcount == 15; |
| 1092 | | LOG((LOG_DISK,3," WFFO:1 count bitcount:%2d\n", m_dsk.bitcount)); |
| 1104 | LOG((LOG_DISK,7," WFFO:1 count bitcount:%2d\n", m_dsk.bitcount)); |
| 1093 | 1105 | } else { |
| 1094 | 1106 | /* |
| 1095 | 1107 | * If BUS[4] (WFFO) was 0, both J and K' will be 0, and Q |
| r26169 | r26170 | |
| 1097 | 1109 | */ |
| 1098 | 1110 | m_dsk.bitcount = 15; |
| 1099 | 1111 | m_dsk.carry = 1; |
| 1100 | | LOG((LOG_DISK,3," WFFO:0 load bitcount:%2d\n", m_dsk.bitcount)); |
| 1112 | LOG((LOG_DISK,7," WFFO:0 load bitcount:%2d\n", m_dsk.bitcount)); |
| 1101 | 1113 | } |
| 1102 | 1114 | } else if (!m_dsk.bitclk && bitclk) { |
| 1103 | | // clock the shift register on the rising edge of bitclk |
| 1104 | | m_dsk.shiftin = (m_dsk.shiftin << 1) | datin; |
| 1105 | | // and the output shift register too |
| 1106 | | m_dsk.shiftout = m_dsk.shiftout << 1; |
| 1115 | m_dsk.shiftin = (m_dsk.shiftin << 1) | datin; // clock the shift register on the rising edge of bitclk |
| 1116 | m_dsk.shiftout = m_dsk.shiftout << 1; // and the output shift register too |
| 1107 | 1117 | } |
| 1108 | 1118 | |
| 1109 | 1119 | if (m_dsk.wddone != wddone) { |
| 1110 | | LOG((LOG_DISK,2," WDDONE':%d→%d\n", m_dsk.wddone, wddone)); |
| 1120 | LOG((LOG_DISK,8," WDDONE':%d→%d\n", m_dsk.wddone, wddone)); |
| 1111 | 1121 | } |
| 1112 | 1122 | |
| 1113 | 1123 | if (m_dsk.carry) { |
| 1114 | 1124 | /* CARRY = 1 -> WDDONE' = 0 */ |
| 1115 | 1125 | wddone = 0; |
| 1116 | | if (wddone == 0) { |
| 1126 | if (m_dsk.wddone == 0) { |
| 1117 | 1127 | /* |
| 1118 | 1128 | * Latch a new data word while WDDONE is 0 |
| 1119 | 1129 | * Note: The shifter outputs for bits 0 to 14 are connected |
| r26169 | r26170 | |
| 1124 | 1134 | m_dsk.datain = m_dsk.shiftin & 0177777; |
| 1125 | 1135 | /* load the output shift register */ |
| 1126 | 1136 | m_dsk.shiftout = m_dsk.dataout; |
| 1127 | | LOG((LOG_DISK,6," LATCH in:%06o (0x%04x) out:%06o (0x%04x)\n", m_dsk.datain, m_dsk.datain, m_dsk.dataout, m_dsk.dataout)); |
| 1137 | LOG((LOG_DISK,8," LATCH in:%06o (0x%04x) out:%06o (0x%04x)\n", m_dsk.datain, m_dsk.datain, m_dsk.dataout, m_dsk.dataout)); |
| 1128 | 1138 | } |
| 1129 | 1139 | } else { |
| 1130 | 1140 | /* CARRY = 0 -> WDDONE' = 1 */ |
| 1131 | 1141 | wddone = 1; |
| 1132 | 1142 | } |
| 1133 | 1143 | |
| 1134 | | /* remember previous state of wddone */ |
| 1144 | // remember previous state of word-done |
| 1135 | 1145 | m_dsk.wddone = wddone; |
| 1136 | 1146 | |
| 1137 | 1147 | /** |
| r26169 | r26170 | |
| 1160 | 1170 | for (i = 0; i < 4; i++) { |
| 1161 | 1171 | |
| 1162 | 1172 | if (m_sysclka0[i] != m_sysclka1[i]) { |
| 1163 | | LOG((LOG_DISK,7," SYSCLKA' %s\n", raise_lower[m_sysclka1[i]])); |
| 1173 | LOG((LOG_DISK,9," SYSCLKA' %s\n", raise_lower[m_sysclka1[i]])); |
| 1164 | 1174 | } |
| 1165 | 1175 | if (m_sysclkb0[i] != m_sysclkb1[i]) { |
| 1166 | | LOG((LOG_DISK,7," SYSCLKB' %s\n", raise_lower[m_sysclkb1[i]])); |
| 1176 | LOG((LOG_DISK,9," SYSCLKB' %s\n", raise_lower[m_sysclkb1[i]])); |
| 1167 | 1177 | } |
| 1168 | 1178 | |
| 1169 | 1179 | /** |
| r26169 | r26170 | |
| 1349 | 1359 | // rising edge immediately |
| 1350 | 1360 | if ((m_dsk.wdinit = WDINIT) == 1) |
| 1351 | 1361 | m_dsk.wdinit0 = 1; |
| 1352 | | LOG((LOG_DISK,2," WDINIT:%d\n", m_dsk.wdinit)); |
| 1362 | LOG((LOG_DISK,8," WDINIT:%d\n", m_dsk.wdinit)); |
| 1353 | 1363 | } |
| 1354 | 1364 | |
| 1355 | 1365 | /* |
| r26169 | r26170 | |
| 1373 | 1383 | } |
| 1374 | 1384 | } |
| 1375 | 1385 | |
| 1376 | | if (m_dsk.kfer) { |
| 1386 | if (0 != m_dsk.kfer) { |
| 1377 | 1387 | // no fatal error: ready AND not seqerr AND seekok |
| 1378 | 1388 | if (!RDYLAT && !SEQERR && SEEKOK) { |
| 1379 | | LOG((LOG_DISK,2," reset KFER\n")); |
| 1389 | LOG((LOG_DISK,6," reset KFER\n")); |
| 1380 | 1390 | m_dsk.kfer = 0; |
| 1381 | 1391 | } |
| 1382 | | } else { |
| 1392 | } |
| 1393 | if (0 == m_dsk.kfer) { |
| 1383 | 1394 | // fatal error: not ready OR seqerr OR not seekok |
| 1384 | 1395 | if (RDYLAT) { |
| 1385 | | LOG((LOG_DISK,2," RDYLAT sets KFER\n")); |
| 1396 | LOG((LOG_DISK,6," RDYLAT sets KFER\n")); |
| 1386 | 1397 | m_dsk.kfer = 1; |
| 1387 | 1398 | } |
| 1388 | 1399 | if (SEQERR) { |
| 1389 | | LOG((LOG_DISK,2," SEQERR sets KFER\n")); |
| 1400 | LOG((LOG_DISK,6," SEQERR sets KFER\n")); |
| 1390 | 1401 | m_dsk.kfer = 1; |
| 1391 | 1402 | } |
| 1392 | 1403 | if (!SEEKOK) { |
| 1393 | | LOG((LOG_DISK,2," not SEEKOK sets KFER\n")); |
| 1404 | LOG((LOG_DISK,6," not SEEKOK sets KFER\n")); |
| 1394 | 1405 | m_dsk.kfer = 1; |
| 1395 | 1406 | } |
| 1396 | 1407 | } |
| r26169 | r26170 | |
| 1401 | 1412 | */ |
| 1402 | 1413 | if (m_dsk.ff_22b & JKFF_Q) { |
| 1403 | 1414 | if (0 == (m_task_wakeup & (1 << task_ksec))) { |
| 1404 | | LOG((LOG_DISK,2," STSKENA:1; WAKEST':0 wake KSEC\n")); |
| 1415 | LOG((LOG_DISK,6," STSKENA:1; WAKEST':0 wake KSEC\n")); |
| 1405 | 1416 | m_task_wakeup |= 1 << task_kwd; |
| 1406 | 1417 | } |
| 1407 | 1418 | } else { |
| 1408 | 1419 | if (0 != (m_task_wakeup & (1 << task_ksec))) { |
| 1409 | | LOG((LOG_DISK,2," STSKENA:0; WAKEST':1\n")); |
| 1420 | LOG((LOG_DISK,6," STSKENA:0; WAKEST':1\n")); |
| 1410 | 1421 | m_task_wakeup &= ~(1 << task_kwd); |
| 1411 | 1422 | } |
| 1412 | 1423 | } |
| r26169 | r26170 | |
| 1424 | 1435 | */ |
| 1425 | 1436 | DEBUG_NAME("\t\t21a KSEC "); |
| 1426 | 1437 | s0 = m_dsk.ff_21a; |
| 1427 | | s1 = 0 == dhd->get_sector_mark_0() ? JKFF_CLK : JKFF_0; |
| 1438 | s1 = 0 == m_dsk.sect4 ? JKFF_CLK : JKFF_0; |
| 1428 | 1439 | if (m_dsk.ff_22b & JKFF_Q0) |
| 1429 | 1440 | s1 |= JKFF_J; |
| 1430 | 1441 | s1 |= JKFF_K; |
| r26169 | r26170 | |
| 1442 | 1453 | m_dsk.seclate_timer->adjust(attotime::from_nsec(TW_SECLATE), 1); |
| 1443 | 1454 | if (m_dsk.seclate) { |
| 1444 | 1455 | m_dsk.seclate = 0; |
| 1445 | | LOG((LOG_DISK,4," SECLATE -> 0 pulse until %lldns\n", ntime() + TW_SECLATE)); |
| 1456 | LOG((LOG_DISK,6," SECLATE -> 0 pulse until %lldns\n", ntime() + TW_SECLATE)); |
| 1446 | 1457 | } |
| 1447 | 1458 | } |
| 1448 | 1459 | |
| 1449 | | /* |
| 1450 | | * check if write and erase gate, or read gate are changed |
| 1451 | | */ |
| 1460 | // check if write and erase gate, or read gate are changed |
| 1452 | 1461 | if ((m_task_wakeup & (1 << task_ksec)) || GET_KCOM_XFEROFF(m_dsk.kcom) || m_dsk.kfer) { |
| 1453 | 1462 | // sector task is active OR xferoff is set OR fatal error |
| 1454 | 1463 | dhd->set_egate(1); |
| 1455 | 1464 | dhd->set_wrgate(1); |
| 1456 | 1465 | dhd->set_rdgate(1); |
| 1457 | 1466 | } else { |
| 1458 | | // assert either read or write gates depending on current record R/W |
| 1467 | // assert either erase and read or write gates depending on current record R/W |
| 1459 | 1468 | if (m_dsk.krwc & RWC_WRITE) { |
| 1460 | 1469 | // assert erase and write gates only if OKTORUN is high |
| 1461 | 1470 | if (m_dsk.ok_to_run) { |
| r26169 | r26170 | |
| 1471 | 1480 | m_dsk.ff_21a_old = m_dsk.ff_21a; |
| 1472 | 1481 | m_dsk.bitclk = bitclk; |
| 1473 | 1482 | m_dsk.datin = datin; |
| 1474 | | LOG((LOG_DISK,5," <<< KWD timing\n")); |
| 1483 | LOG((LOG_DISK,8," <<< KWD timing\n")); |
| 1475 | 1484 | } |
| 1476 | 1485 | |
| 1477 | 1486 | |
| r26169 | r26170 | |
| 1491 | 1500 | LOG((LOG_DISK,2," OK TO RUN -> %d\n", arg)); |
| 1492 | 1501 | m_dsk.ok_to_run = arg; |
| 1493 | 1502 | m_dsk.ok_to_run_timer->enable(false); |
| 1503 | |
| 1504 | for (int unit = 0; unit < diablo_hd_device::DIABLO_UNIT_MAX; unit++) { |
| 1505 | diablo_hd_device* dhd = m_drive[unit]; |
| 1506 | dhd->set_sector_callback(this, &disk_sector_start); |
| 1507 | } |
| 1494 | 1508 | } |
| 1495 | 1509 | |
| 1496 | 1510 | /** |
| r26169 | r26170 | |
| 2199 | 2213 | { |
| 2200 | 2214 | (void)ptr; |
| 2201 | 2215 | diablo_hd_device* dhd = m_drive[m_dsk.drive]; |
| 2202 | | int bits = dhd ? dhd->bits_per_sector() : 0; |
| 2216 | int bits = dhd->bits_per_sector(); |
| 2203 | 2217 | int clk = arg & 1; |
| 2204 | 2218 | int bit = 0; |
| 2205 | 2219 | |
| r26169 | r26170 | |
| 2221 | 2235 | /* do anything, if the transfer is off? */ |
| 2222 | 2236 | } else { |
| 2223 | 2237 | LOG((LOG_DISK,7," BITCLK#%d bit:%d (write) @%lldns\n", arg, bit, ntime())); |
| 2224 | | if (dhd) { |
| 2225 | | if (clk) |
| 2226 | | dhd->wr_data(arg, bit); |
| 2227 | | else |
| 2228 | | dhd->wr_data(arg, 1); |
| 2229 | | } |
| 2238 | if (clk) |
| 2239 | dhd->wr_data(arg, bit); |
| 2240 | else |
| 2241 | dhd->wr_data(arg, 1); |
| 2230 | 2242 | } |
| 2231 | 2243 | } else if (GET_KCOM_BCLKSRC(m_dsk.kcom)) { |
| 2232 | 2244 | /* always select the crystal clock */ |
| 2233 | | if (dhd) |
| 2234 | | bit = dhd->rd_data(arg); |
| 2245 | bit = dhd->rd_data(arg); |
| 2235 | 2246 | LOG((LOG_DISK,7," BITCLK#%d bit:%d (read, crystal) @%lldns\n", arg, bit, ntime())); |
| 2236 | 2247 | kwd_timing(clk, bit, 0); |
| 2237 | 2248 | } else { |
| 2238 | 2249 | /* if XFEROFF is set, keep the bit at 1 (RDGATE' is high) */ |
| 2239 | 2250 | if (GET_KCOM_XFEROFF(m_dsk.kcom)) { |
| 2251 | clk = dhd->rd_clock(arg); |
| 2240 | 2252 | bit = 1; |
| 2241 | 2253 | } else { |
| 2242 | | if (dhd) { |
| 2243 | | clk = dhd->rd_clock(arg & ~1); |
| 2244 | | bit = dhd->rd_data(arg | 1); |
| 2245 | | } |
| 2254 | bit = dhd->rd_data(arg); |
| 2246 | 2255 | LOG((LOG_DISK,7," BITCLK#%d bit:%d (read, driveclk) @%lldns\n", arg, bit, ntime())); |
| 2247 | 2256 | } |
| 2248 | 2257 | kwd_timing(clk, bit, 0); |
| r26169 | r26170 | |
| 2250 | 2259 | |
| 2251 | 2260 | /* more bits to clock? */ |
| 2252 | 2261 | if (++arg < bits) { |
| 2253 | | assert(dhd != NULL); |
| 2262 | #if USE_BITCLK_TIMER |
| 2254 | 2263 | m_dsk.bitclk_timer->adjust(dhd->bit_time(), arg); |
| 2264 | #else |
| 2265 | if (!m_dsk.bitclk_time) |
| 2266 | m_dsk.bitclk_time = static_cast<int>(dhd->bit_time().as_double() * ATTOSECONDS_PER_NANOSECOND); |
| 2267 | m_bitclk_time += m_dsk.bitclk_time; |
| 2268 | #endif |
| 2255 | 2269 | } |
| 2256 | 2270 | } |
| 2257 | 2271 | |
| r26169 | r26170 | |
| 2264 | 2278 | { |
| 2265 | 2279 | diablo_hd_device* dhd = m_drive[unit]; |
| 2266 | 2280 | LOG((LOG_DISK,0,"%s dhd=%p\n", __FUNCTION__, dhd)); |
| 2281 | #if USE_BITCLK_TIMER |
| 2267 | 2282 | if (m_dsk.bitclk_timer) { |
| 2268 | | LOG((LOG_DISK,0," unit #%d stop bitclk\n", m_dsk.bitclk)); |
| 2283 | LOG((LOG_DISK,0," unit #%d stop bitclk\n", unit)); |
| 2269 | 2284 | m_dsk.bitclk_timer->reset(); |
| 2270 | 2285 | } |
| 2286 | #else |
| 2287 | if (m_bitclk_time >= 0) { |
| 2288 | LOG((LOG_DISK,0," unit #%d stop bitclk\n", unit)); |
| 2289 | m_bitclk_time = -1; |
| 2290 | } |
| 2291 | #endif |
| 2271 | 2292 | |
| 2272 | 2293 | /* KSTAT[0-3] update the current sector in the kstat field */ |
| 2273 | | PUT_KSTAT_SECTOR(m_dsk.kstat, dhd ? dhd->get_sector() : 017); |
| 2294 | PUT_KSTAT_SECTOR(m_dsk.kstat, dhd->get_sector()); |
| 2274 | 2295 | |
| 2275 | 2296 | /* clear input and output shift registers (?) */ |
| 2276 | 2297 | m_dsk.shiftin = 0; |
| r26169 | r26170 | |
| 2278 | 2299 | |
| 2279 | 2300 | LOG((LOG_DISK,1," unit #%d sector %d start\n", unit, GET_KSTAT_SECTOR(m_dsk.kstat))); |
| 2280 | 2301 | |
| 2281 | | /* HACK: no command, no bit clock */ |
| 2282 | | // if (debug_read_mem(0521)) |
| 2283 | | /* start a timer chain for the bit clock */ |
| 2284 | | disk_bitclk(0, 0); |
| 2285 | | } |
| 2286 | 2302 | |
| 2287 | | /** |
| 2288 | | * @brief callback is called by the drive timer whenever a new sector starts |
| 2289 | | * |
| 2290 | | * @param unit the unit number |
| 2291 | | */ |
| 2292 | | static void disk_sector_start(void* cookie, int unit) |
| 2293 | | { |
| 2294 | | alto2_cpu_device* cpu = reinterpret_cast<alto2_cpu_device *>(cookie); |
| 2295 | | cpu->next_sector(unit); |
| 2303 | #if USE_BITCLK_TIMER |
| 2304 | // HACK: no command, no bit clock |
| 2305 | if (debug_read_mem(0521)) |
| 2306 | /* start a timer chain for the bit clock */ |
| 2307 | disk_bitclk(0, 0); |
| 2308 | #else |
| 2309 | // TODO: verify current sector == requested sector and only then run the bitclk? |
| 2310 | // HACK: no command, no bit clock |
| 2311 | if (debug_read_mem(0521)) { |
| 2312 | // Make the CPU execution loop call disk_bitclk |
| 2313 | m_bitclk_time = 0; |
| 2314 | m_bitclk_index = 0; |
| 2315 | } |
| 2316 | #endif |
| 2296 | 2317 | } |
| 2297 | 2318 | |
| 2298 | 2319 | /** |
| r26169 | r26170 | |
| 2333 | 2354 | m_dsk.seclate = 0; |
| 2334 | 2355 | m_dsk.ok_to_run = 0; |
| 2335 | 2356 | |
| 2357 | #if USE_BITCLK_TIMER |
| 2336 | 2358 | m_dsk.bitclk_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(alto2_cpu_device::disk_bitclk),this)); |
| 2359 | #endif |
| 2337 | 2360 | |
| 2338 | 2361 | m_dsk.seclate_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(alto2_cpu_device::disk_seclate),this)); |
| 2339 | 2362 | m_dsk.seclate_timer->adjust(attotime::from_nsec(TW_SECLATE), 1); |
| r26169 | r26170 | |
| 2343 | 2366 | |
| 2344 | 2367 | m_dsk.ready_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(alto2_cpu_device::disk_ready_mf31a),this)); |
| 2345 | 2368 | m_dsk.ready_timer->reset(); |
| 2346 | | |
| 2347 | | diablo_hd_device* dhd; |
| 2348 | | for (int unit = 0; unit < diablo_hd_device::DIABLO_UNIT_MAX; unit++) { |
| 2349 | | dhd = m_drive[unit]; |
| 2350 | | if (!dhd) |
| 2351 | | continue; |
| 2352 | | dhd->set_sector_callback(this, &disk_sector_start); |
| 2353 | | } |
| 2354 | 2369 | } |
| 2355 | 2370 | |
branches/alto2/src/emu/machine/diablo_hd.c
| r26169 | r26170 | |
| 123 | 123 | |
| 124 | 124 | void diablo_hd_device::set_sector_callback(void *cookie, void (*callback)(void *, int)) |
| 125 | 125 | { |
| 126 | LOG_DRIVE((0,"[DHD] %s cookie=%p callback=%p\n", __FUNCTION__, cookie, callback)); |
| 126 | 127 | m_sector_callback_cookie = cookie; |
| 127 | 128 | m_sector_callback = callback; |
| 128 | 129 | } |
| r26169 | r26170 | |
| 826 | 827 | |
| 827 | 828 | /** |
| 828 | 829 | * @brief return the seek/read/write status of a drive |
| 829 | | * @return the seek/read/write status for the drive unit (0: active, 1: inactive) |
| 830 | * @return the seek/read/write status for the drive unit (0:active 1:inactive) |
| 830 | 831 | */ |
| 831 | 832 | int diablo_hd_device::get_seek_read_write_0() const |
| 832 | 833 | { |
| r26169 | r26170 | |
| 835 | 836 | |
| 836 | 837 | /** |
| 837 | 838 | * @brief return the ready status of a drive |
| 838 | | * @return the ready status for the drive unit (0: ready, 1: not ready) |
| 839 | * @return the ready status for the drive unit (0:ready 1:not ready) |
| 839 | 840 | */ |
| 840 | 841 | int diablo_hd_device::get_ready_0() const |
| 841 | 842 | { |
| r26169 | r26170 | |
| 861 | 862 | |
| 862 | 863 | /** |
| 863 | 864 | * @brief return the address acknowledge state |
| 864 | | * @return the address acknowledge state |
| 865 | * @return the address acknowledge state (0:active 1:inactive) |
| 865 | 866 | */ |
| 866 | 867 | int diablo_hd_device::get_addx_acknowledge_0() const |
| 867 | 868 | { |
| r26169 | r26170 | |
| 889 | 890 | /** |
| 890 | 891 | * @brief return the current cylinder of a drive unit |
| 891 | 892 | * |
| 892 | | * Note: the bus lines are active low, thus the XOR with DRIVE_CYLINDER_MASK. |
| 893 | * Note: The bus lines are active low |
| 894 | * The value on the BUS needs an XOR with DIABLO_CYLINDER_MASK |
| 893 | 895 | * |
| 894 | 896 | * @return the current cylinder number for the drive |
| 895 | 897 | */ |
| 896 | 898 | int diablo_hd_device::get_cylinder() const |
| 897 | 899 | { |
| 898 | | return m_cylinder ^ DIABLO_CYLINDER_MASK; |
| 900 | return m_cylinder; |
| 899 | 901 | } |
| 900 | 902 | |
| 901 | 903 | /** |
| 902 | 904 | * @brief return the current head of a drive unit |
| 903 | 905 | * |
| 904 | | * Note: the bus lines are active low, thus the XOR with DRIVE_HEAD_MASK. |
| 906 | * Note: The bus lines are active low |
| 907 | * The value on the BUS needs an XOR with DIABLO_HEAD_MASK |
| 905 | 908 | * |
| 906 | 909 | * @return the currently selected head for the drive |
| 907 | 910 | */ |
| 908 | 911 | int diablo_hd_device::get_head() const |
| 909 | 912 | { |
| 910 | | return m_head ^ DIABLO_HEAD_MASK; |
| 913 | return m_head; |
| 911 | 914 | } |
| 912 | 915 | |
| 913 | 916 | /** |
| r26169 | r26170 | |
| 915 | 918 | * |
| 916 | 919 | * The current sector number is derived from the time since the |
| 917 | 920 | * most recent track rotation started. |
| 921 | * It counts modulo DIABLO_SPT |
| 918 | 922 | * |
| 919 | | * Note: the bus lines are active low, thus the XOR with DRIVE_SECTOR_MASK. |
| 923 | * Note: The bus lines are active low |
| 924 | * The value on the BUS needs an XOR with DIABLO_SECTOR_MASK |
| 920 | 925 | * |
| 921 | 926 | * @return the current sector for the drive |
| 922 | 927 | */ |
| 923 | 928 | int diablo_hd_device::get_sector() const |
| 924 | 929 | { |
| 925 | | return m_sector ^ DIABLO_SECTOR_MASK; |
| 930 | return m_sector; |
| 926 | 931 | } |
| 927 | 932 | |
| 928 | 933 | /** |
| r26169 | r26170 | |
| 950 | 955 | /* this drive is selected */ |
| 951 | 956 | if ((head & DIABLO_HEAD_MASK) != m_head) { |
| 952 | 957 | m_head = head & DIABLO_HEAD_MASK; |
| 953 | | printf("select unit:%d head:%d\n", unit, head); |
| 958 | LOG_DRIVE((0,"[DHD] %s: unit:%d head:%d\n", __FUNCTION__, unit, head)); |
| 954 | 959 | } |
| 955 | 960 | |
| 956 | 961 | if (m_image) { |
| r26169 | r26170 | |
| 978 | 983 | /** |
| 979 | 984 | * @brief strobe a seek operation |
| 980 | 985 | * |
| 981 | | * Seek to the cylinder cylinder, or restore. |
| 986 | * Seek to the cylinder %cylinder, or restore to cylinder 0. |
| 982 | 987 | * |
| 983 | 988 | * @param unit unit number |
| 984 | 989 | * @param cylinder cylinder number to seek to |
| r26169 | r26170 | |
| 990 | 995 | int seekto = restore ? 0 : cylinder; |
| 991 | 996 | if (strobe) { |
| 992 | 997 | LOG_DRIVE((1,"[DHD] %s: STROBE end of interlock\n", __FUNCTION__, seekto)); |
| 993 | | /* deassert the log address interlock */ |
| 998 | // deassert the log address interlock |
| 994 | 999 | m_log_addx_interlock_0 = 1; |
| 995 | 1000 | return; |
| 996 | 1001 | } |
| 997 | 1002 | |
| 998 | | /* assert the log address interlock */ |
| 1003 | // assert the log address interlock |
| 999 | 1004 | m_log_addx_interlock_0 = 0; |
| 1000 | 1005 | |
| 1001 | 1006 | if (seekto == m_cylinder) { |
| 1002 | 1007 | LOG_DRIVE((1,"[DHD] %s: STROBE to cylinder %d acknowledge\n", __FUNCTION__, seekto)); |
| 1003 | | m_addx_acknowledge_0 = 0; /* address acknowledge, if cylinder is reached */ |
| 1004 | | m_seek_incomplete_0 = 1; /* reset seek incomplete */ |
| 1008 | m_addx_acknowledge_0 = 0; // address acknowledge, if cylinder is reached |
| 1009 | m_seek_incomplete_0 = 1; // reset seek incomplete |
| 1005 | 1010 | return; |
| 1006 | 1011 | } |
| 1007 | | |
| 1012 | // assert the seek-read-write signal |
| 1008 | 1013 | m_s_r_w_0 = 0; |
| 1009 | 1014 | |
| 1010 | 1015 | if (seekto < m_cylinder) { |
| 1011 | | /* decrement cylinder */ |
| 1012 | | m_cylinder--; |
| 1016 | m_cylinder--; // previous cylinder |
| 1013 | 1017 | if (m_cylinder < 0) { |
| 1014 | 1018 | m_cylinder = 0; |
| 1015 | | m_log_addx_interlock_0 = 1; /* deassert the log address interlock */ |
| 1016 | | m_seek_incomplete_0 = 1; /* deassert seek incomplete */ |
| 1017 | | m_addx_acknowledge_0 = 0; /* assert address acknowledge */ |
| 1019 | m_log_addx_interlock_0 = 1; // deassert the log address interlock signal |
| 1020 | m_seek_incomplete_0 = 1; // deassert seek incomplete signal |
| 1021 | m_addx_acknowledge_0 = 0; // assert address acknowledge signal |
| 1018 | 1022 | LOG_DRIVE((1,"[DHD] %s: STROBE to cylinder %d incomplete\n", __FUNCTION__, seekto)); |
| 1019 | 1023 | return; |
| 1020 | 1024 | } |
| 1021 | | } else { |
| 1025 | } |
| 1026 | if (seekto > m_cylinder) { |
| 1022 | 1027 | /* increment cylinder */ |
| 1023 | 1028 | m_cylinder++; |
| 1024 | 1029 | if (m_cylinder >= DIABLO_CYLINDERS) { |
| 1025 | 1030 | m_cylinder = DIABLO_CYLINDERS - 1; |
| 1026 | | m_log_addx_interlock_0 = 1; /* deassert the log address interlock */ |
| 1027 | | m_seek_incomplete_0 = 1; /* deassert seek incomplete */ |
| 1028 | | m_addx_acknowledge_0 = 0; /* assert address acknowledge */ |
| 1031 | m_log_addx_interlock_0 = 1; // deassert the log address interlock signal |
| 1032 | m_seek_incomplete_0 = 1; // deassert seek incomplete signal |
| 1033 | m_addx_acknowledge_0 = 0; // assert address acknowledge signal |
| 1029 | 1034 | LOG_DRIVE((1,"[DHD] %s: STROBE to cylinder %d incomplete\n", __FUNCTION__, seekto)); |
| 1030 | 1035 | return; |
| 1031 | 1036 | } |
| 1032 | 1037 | } |
| 1033 | 1038 | LOG_DRIVE((1,"[DHD] %s: STROBE to cylinder %d (now %d) - interlock\n", __FUNCTION__, seekto, m_cylinder)); |
| 1034 | 1039 | |
| 1035 | | m_addx_acknowledge_0 = 1; /* deassert address acknowledge */ |
| 1036 | | m_seek_incomplete_0 = 1; /* deassert seek incomplete */ |
| 1040 | m_addx_acknowledge_0 = 1; // deassert address acknowledge signal |
| 1041 | m_seek_incomplete_0 = 1; // deassert seek incomplete signal |
| 1037 | 1042 | read_sector(); |
| 1038 | 1043 | } |
| 1039 | 1044 | |
| r26169 | r26170 | |
| 1083 | 1088 | */ |
| 1084 | 1089 | void diablo_hd_device::wr_data(int index, int wrdata) |
| 1085 | 1090 | { |
| 1086 | | if (m_wrgate_0) { |
| 1087 | | /* write gate is not asserted (active 0) */ |
| 1088 | | return; |
| 1089 | | } |
| 1091 | if (m_wrgate_0) |
| 1092 | return; // write gate is not asserted (active 0) |
| 1090 | 1093 | |
| 1091 | | /* don't write before or beyond the sector */ |
| 1092 | 1094 | if (index < 0 || index >= bits_per_sector()) |
| 1093 | | return; |
| 1095 | return; // don't write before or beyond the sector |
| 1094 | 1096 | |
| 1095 | | if (-1 == m_page) { |
| 1096 | | /* invalid page */ |
| 1097 | | return; |
| 1098 | | } |
| 1097 | if (-1 == m_page) |
| 1098 | return; // invalid page |
| 1099 | 1099 | |
| 1100 | 1100 | UINT32 *bits = expand_sector(); |
| 1101 | 1101 | if (-1 == m_wrfirst) |
| r26169 | r26170 | |
| 1124 | 1124 | { |
| 1125 | 1125 | int bit = 0; |
| 1126 | 1126 | |
| 1127 | | if (m_rdgate_0) { |
| 1128 | | /* read gate is not asserted (active 0) */ |
| 1129 | | return 0; |
| 1130 | | } |
| 1127 | if (m_rdgate_0) |
| 1128 | return 0; // read gate is not asserted (active 0) |
| 1131 | 1129 | |
| 1132 | | /* don't read before or beyond the sector */ |
| 1133 | 1130 | if (index < 0 || index >= bits_per_sector()) |
| 1134 | | return 1; |
| 1131 | return 1; // don't read before or beyond the sector |
| 1135 | 1132 | |
| 1136 | | /* no data while sector mark is low (?) */ |
| 1137 | 1133 | if (0 == m_sector_mark_0) |
| 1138 | | return 1; |
| 1134 | return 1; // no data while sector mark is low (?) |
| 1139 | 1135 | |
| 1140 | | if (-1 == m_page) { |
| 1141 | | /* invalid page */ |
| 1142 | | return 1; |
| 1143 | | } |
| 1136 | if (-1 == m_page) |
| 1137 | return 1; // invalid page |
| 1144 | 1138 | |
| 1145 | 1139 | UINT32 *bits = expand_sector(); |
| 1146 | | |
| 1147 | 1140 | if (-1 == m_rdfirst) |
| 1148 | 1141 | m_rdfirst = index; |
| 1149 | 1142 | |
| r26169 | r26170 | |
| 1166 | 1159 | { |
| 1167 | 1160 | int clk = 0; |
| 1168 | 1161 | |
| 1169 | | /* don't read before or beyond the sector */ |
| 1170 | 1162 | if (index < 0 || index >= bits_per_sector()) |
| 1171 | | return 1; |
| 1163 | return 1; // don't read before or beyond the sector |
| 1172 | 1164 | |
| 1173 | | /* no clock while sector mark is low (?) */ |
| 1174 | 1165 | if (0 == m_sector_mark_0) |
| 1175 | | return 1; |
| 1166 | return 1; // no clock while sector mark is low (?) |
| 1176 | 1167 | |
| 1177 | | if (-1 == m_page) { |
| 1178 | | /* invalid page */ |
| 1179 | | return 1; |
| 1180 | | } |
| 1168 | if (-1 == m_page) |
| 1169 | return 1; // invalid page |
| 1181 | 1170 | |
| 1182 | 1171 | UINT32 *bits = expand_sector(); |
| 1183 | | |
| 1184 | 1172 | if (-1 == m_rdfirst) |
| 1185 | 1173 | m_rdfirst = index; |
| 1186 | 1174 | |
| r26169 | r26170 | |
| 1218 | 1206 | { |
| 1219 | 1207 | LOG_DRIVE((9,"[DHD] %s: unit #%d C/H/S:%d/%d/%d\n", __FUNCTION__, m_unit, m_cylinder, m_head, m_sector)); |
| 1220 | 1208 | |
| 1221 | | /* squeeze previous sector, if it was written to */ |
| 1209 | // squeeze previous sector bits, if it was written to |
| 1222 | 1210 | squeeze_sector(); |
| 1223 | 1211 | |
| 1224 | 1212 | m_sector_mark_0 = 0; |
| 1225 | 1213 | |
| 1226 | | /* reset read and write bit locations */ |
| 1214 | // reset read and write bit locations |
| 1227 | 1215 | m_rdfirst = -1; |
| 1228 | 1216 | m_rdlast = -1; |
| 1229 | 1217 | m_wrfirst = -1; |
| 1230 | 1218 | m_wrlast = -1; |
| 1231 | 1219 | |
| 1232 | | /* count sectors */ |
| 1220 | // count up the sector number |
| 1233 | 1221 | m_sector = (m_sector + 1) % DIABLO_SPT; |
| 1234 | | /* read the sector */ |
| 1235 | 1222 | read_sector(); |
| 1236 | 1223 | } |
| 1237 | 1224 | |
| r26169 | r26170 | |
| 1277 | 1264 | LOG_DRIVE((0,"[DHD] %s: sector mark 1 time : %.0fns\n", __FUNCTION__, 1e9 * m_sector_mark_1_time.as_double())); |
| 1278 | 1265 | LOG_DRIVE((0,"[DHD] %s: bit time : %.0fns\n", __FUNCTION__, 1e9 * m_bit_time.as_double())); |
| 1279 | 1266 | |
| 1280 | | m_s_r_w_0 = 1; /* seek/read/write not ready */ |
| 1281 | | m_ready_0 = 1; /* drive is not ready */ |
| 1282 | | m_sector_mark_0 = 1; /* sector mark clear */ |
| 1283 | | m_addx_acknowledge_0 = 1; /* drive address acknowledge is not active */ |
| 1284 | | m_log_addx_interlock_0 = 1; /* drive log address interlock is not active */ |
| 1285 | | m_seek_incomplete_0 = 1; /* drive seek incomplete is not active */ |
| 1267 | m_s_r_w_0 = 1; // deassert seek/read/write ready |
| 1268 | m_ready_0 = 1; // deassert drive ready |
| 1269 | m_sector_mark_0 = 1; // deassert sector mark |
| 1270 | m_addx_acknowledge_0 = 1; // deassert drive address acknowledge |
| 1271 | m_log_addx_interlock_0 = 1; // deassert drive log address interlock |
| 1272 | m_seek_incomplete_0 = 1; // deassert drive seek incomplete |
| 1286 | 1273 | |
| 1287 | | /* reset the disk drive's address */ |
| 1288 | | m_cylinder = 0; |
| 1289 | | m_head = 0; |
| 1290 | | m_sector = DIABLO_SPT - 1; |
| 1274 | // reset the disk drive's address |
| 1275 | m_cylinder = -1; |
| 1276 | m_head = -1; |
| 1277 | m_sector = -1; |
| 1291 | 1278 | m_page = -1; |
| 1292 | 1279 | |
| 1293 | | /* disable the gates */ |
| 1280 | // disable the erase, write and read gates |
| 1294 | 1281 | m_egate_0 = 1; |
| 1295 | 1282 | m_wrgate_0 = 1; |
| 1296 | 1283 | m_rdgate_0 = 1; |
| 1297 | 1284 | |
| 1298 | | /* reset read/write first and last indices */ |
| 1285 | // reset read and write first and last indices |
| 1299 | 1286 | m_wrfirst = -1; |
| 1300 | 1287 | m_wrlast = -1; |
| 1301 | 1288 | m_rdfirst = -1; |
| 1302 | 1289 | m_rdlast = -1; |
| 1303 | 1290 | |
| 1291 | // for units with a CHD assigned to them start the timer |
| 1304 | 1292 | if (m_handle) |
| 1305 | 1293 | timer_set(m_sector_time - m_sector_mark_0_time, 1, 0); |
| 1306 | 1294 | } |