|
|
1.1 ! root 1: // ! 2: // nono ! 3: // Copyright (C) 2017 [email protected] ! 4: // ! 5: ! 6: #include "fdc.h" ! 7: #include "iocon.h" ! 8: #include "scheduler.h" ! 9: ! 10: // コンストラクタ ! 11: FDCDevice::FDCDevice() ! 12: { ! 13: logname = "fdc"; ! 14: devname = "FDC"; ! 15: devaddr = baseaddr; ! 16: devlen = 0x2000; ! 17: ! 18: event.dev = this; ! 19: event.func = (DeviceCallback_t)&FDCDevice::Callback; ! 20: event.name = "FDC"; ! 21: } ! 22: ! 23: // デストラクタ ! 24: FDCDevice::~FDCDevice() ! 25: { ! 26: } ! 27: ! 28: void ! 29: FDCDevice::ResetHard() ! 30: { ! 31: // XXX 他には ! 32: idle_phase(); ! 33: } ! 34: ! 35: uint64 ! 36: FDCDevice::Read8(uint32 addr) ! 37: { ! 38: uint32 offset = addr - baseaddr; ! 39: switch (offset) { ! 40: case 1: ! 41: return ReadStatus(); ! 42: case 3: ! 43: return ReadData(); ! 44: case 5: ! 45: return ReadDriveStatus(); ! 46: default: ! 47: break; ! 48: } ! 49: PANIC("not impl"); ! 50: } ! 51: ! 52: uint64 ! 53: FDCDevice::Read16(uint32 addr) ! 54: { ! 55: return 0xff00 | Read8(addr + 1); ! 56: } ! 57: ! 58: uint64 ! 59: FDCDevice::Write8(uint32 addr, uint32 data) ! 60: { ! 61: uint32 offset = addr - baseaddr; ! 62: switch (offset) { ! 63: case 3: ! 64: WriteCmd(data); ! 65: return 0; ! 66: case 5: ! 67: if ((data & 0x0f) != 0) { ! 68: fdc.drivesel = data & 0x0f; ! 69: putlog(1, "ドライブ選択%s%s%s%s", ! 70: (fdc.drivesel & 1) ? " #0" : "", ! 71: (fdc.drivesel & 2) ? " #1" : "", ! 72: (fdc.drivesel & 4) ? " #2" : "", ! 73: (fdc.drivesel & 8) ? " #3" : ""); ! 74: } ! 75: if ((data & 0xe0) != 0) { ! 76: putlog(0, "未実装ビット書き込み $%06x <- $%02x", addr, data); ! 77: } ! 78: return 0; ! 79: ! 80: case 7: ! 81: fdc.is2DD = ((data & 0x10) != 0); ! 82: fdc.accdrive = data & 3; ! 83: putlog(1, "アクセスドライブ %s #%d", ! 84: fdc.is2DD ? "2DD" : "2HD", ! 85: fdc.accdrive); ! 86: fdd[fdc.accdrive].motor = (data & 0x80); ! 87: if (fdd[fdc.accdrive].motor) { ! 88: putlog(1, "ドライブ #%d モーターオン", fdc.accdrive); ! 89: } else { ! 90: putlog(1, "ドライブ #%d モーターオフ", fdc.accdrive); ! 91: } ! 92: return 0; ! 93: ! 94: default: ! 95: break; ! 96: } ! 97: PANIC("FDC 未実装書き込み $%06x <- $%02x", addr, data); ! 98: return 0; ! 99: } ! 100: ! 101: uint64 ! 102: FDCDevice::Write16(uint32 addr, uint32 data) ! 103: { ! 104: return Write8(addr + 1, data); ! 105: } ! 106: ! 107: uint64 ! 108: FDCDevice::Peek8(uint32 addr) ! 109: { ! 110: return 0xff; ! 111: } ! 112: ! 113: // FDC ステータスレジスタ読み込み ! 114: uint32 ! 115: FDCDevice::ReadStatus() ! 116: { ! 117: uint8 stat = 0; ! 118: ! 119: if (fdc.RQM) { ! 120: stat |= FDC::STAT_RQM; ! 121: } ! 122: if (fdc.DIO == DIOtoHost) { ! 123: stat |= FDC::STAT_DIO; ! 124: } ! 125: if (fdc.NDM) { ! 126: stat |= FDC::STAT_NDM; ! 127: } ! 128: if (fdc.CB) { ! 129: stat |= FDC::STAT_CB; ! 130: } ! 131: for (int i = 0; i < 4; i++) { ! 132: if (fdd[i].seek) { ! 133: stat |= (1 << i); ! 134: } ! 135: } ! 136: ! 137: putlog(2, "STAT -> $%02x", stat); ! 138: return stat; ! 139: } ! 140: ! 141: // FDC データレジスタ読み込み ! 142: uint32 ! 143: FDCDevice::ReadData() ! 144: { ! 145: uint8 data; ! 146: ! 147: data = 0xff; ! 148: if (fdc.respos < fdc.reslen) { ! 149: data = fdc.resbuf[fdc.respos++]; ! 150: } ! 151: putlog(2, "DATA -> $%02x", data); ! 152: ! 153: if (fdc.respos == fdc.reslen) { ! 154: idle_phase(); ! 155: } ! 156: return data; ! 157: } ! 158: ! 159: // ドライブステータスレジスタ読み込み ! 160: uint32 ! 161: FDCDevice::ReadDriveStatus() ! 162: { ! 163: uint8 data; ! 164: ! 165: // ディスク非挿入しかサポートしていない ! 166: data = 0x00; ! 167: putlog(1, "ドライブステータスレジスタ読み込み; ディスク非挿入"); ! 168: return data; ! 169: } ! 170: ! 171: // FDC コマンドレジスタ書き込み ! 172: void ! 173: FDCDevice::WriteCmd(uint32 data) ! 174: { ! 175: // cmdpos のインクリメントはログ表示の後で行なっている ! 176: fdc.cmdbuf[fdc.cmdpos] = data; ! 177: ! 178: // 1バイト目はコマンドで、それによって長さが変わる。 ! 179: // コマンド名をログに表示したい。 ! 180: if (fdc.cmdpos == 0) { ! 181: // コマンドはまず下位5ビットであたりをつける ! 182: switch (data & FDC::CMD_MASK) { ! 183: case FDC::CMD_SPECIFY: ! 184: fdc.cmdlen = 3; ! 185: break; ! 186: case FDC::CMD_SENSE_DEVICE_STATUS: ! 187: fdc.cmdlen = 2; ! 188: break; ! 189: case FDC::CMD_SENSE_INTERRUPT_STATUS: ! 190: fdc.cmdlen = 1; ! 191: break; ! 192: case FDC::CMD_RECALIBRATE: ! 193: fdc.cmdlen = 2; ! 194: break; ! 195: case FDC::CMD_SEEK: ! 196: fdc.cmdlen = 3; ! 197: break; ! 198: ! 199: default: ! 200: // 未実装コマンド ! 201: fdc.cmdlen = 1; ! 202: } ! 203: ! 204: const char *cmdname = cmd2name(data & FDC::CMD_MASK); ! 205: putlog(2, "CMD[%d] <- $%02x(%s)", fdc.cmdpos, data, cmdname); ! 206: } else { ! 207: putlog(2, "CMD[%d] <- $%02x", fdc.cmdpos, data); ! 208: // CB は2バイト目から ! 209: fdc.CB = true; ! 210: } ! 211: // ここでインクリメント ! 212: fdc.cmdpos++; ! 213: ! 214: // 全部受け取ったらフェーズ遷移 ! 215: if (fdc.cmdpos >= fdc.cmdlen) { ! 216: exec_phase(); ! 217: } ! 218: } ! 219: ! 220: // idle フェーズに移行 ! 221: void ! 222: FDCDevice::idle_phase() ! 223: { ! 224: fdc.phase = PHASE_IDLE; ! 225: fdc.RQM = true; ! 226: fdc.DIO = DIOtoFDC; ! 227: fdc.NDM = false; ! 228: fdc.CB = false; ! 229: fdc.cmdpos = 0; ! 230: fdc.cmdlen = 0; ! 231: fdc.respos = 0; ! 232: fdc.reslen = 0; ! 233: putlog(2, "Idle フェーズ"); ! 234: } ! 235: ! 236: // Exec フェーズに移行 ! 237: void ! 238: FDCDevice::exec_phase() ! 239: { ! 240: fdc.phase = PHASE_EXEC; ! 241: fdc.DIO = DIOtoFDC; ! 242: fdc.CB = true; ! 243: if (fdc.nd) { ! 244: fdc.NDM = true; // XXX ? ! 245: } ! 246: ! 247: switch (fdc.cmdbuf[0] & FDC::CMD_MASK) { ! 248: case FDC::CMD_SPECIFY: ! 249: putlog(1, "Exec フェーズ: SPECIFY"); ! 250: fdc.srt = fdc.cmdbuf[1] >> 4; ! 251: fdc.hut = fdc.cmdbuf[1] & 15; ! 252: fdc.hlt = fdc.cmdbuf[2] >> 1; ! 253: fdc.nd = (fdc.cmdbuf[2] & 1); ! 254: idle_phase(); ! 255: break; ! 256: ! 257: case FDC::CMD_SENSE_DEVICE_STATUS: ! 258: putlog(1, "Exec フェーズ: SENSE DEVICE STATUS"); ! 259: fdc.resbuf[0] = fdc.cmdbuf[1] & 0x07; ! 260: fdc.resbuf[0] |= 0x00; ! 261: fdc.reslen = 1; ! 262: result_phase(); ! 263: break; ! 264: ! 265: case FDC::CMD_SENSE_INTERRUPT_STATUS: ! 266: { ! 267: putlog(1, "Exec フェーズ: SENSE INTERRUPT STATUS"); ! 268: // XXX まだフロッピー挿入はない ! 269: uint8 st0 = 0; ! 270: st0 |= FDC::ST0_IC_NT; ! 271: st0 |= FDC::ST0_EC; ! 272: st0 |= FDC::ST0_NR; ! 273: st0 |= fdc.accdrive; ! 274: fdc.resbuf[0] = st0; ! 275: fdc.resbuf[1] = 0; // XXX PCN ! 276: fdc.reslen = 2; ! 277: result_phase(); ! 278: break; ! 279: } ! 280: ! 281: case FDC::CMD_RECALIBRATE: ! 282: putlog(1, "Exec フェーズ: RECALIBRATE"); ! 283: fdd[fdc.accdrive].seek = true; ! 284: // SEEK/RECALIBRATE では CB はセットされない ! 285: fdc.CB = false; ! 286: idle_phase(); ! 287: // XXX ヘッドの位置という概念がまだない ! 288: event.time = 0; ! 289: event.code = FDC::CMD_RECALIBRATE; // XXX コマンドをメンバ変数にするとか ! 290: gScheduler->AddEvent(&event); ! 291: break; ! 292: ! 293: case FDC::CMD_SEEK: ! 294: putlog(1, "Exec フェーズ: SEEK (未実装)"); ! 295: // SEEK/RECALIBRATE では CB はセットされない ! 296: fdc.CB = false; ! 297: idle_phase(); ! 298: break; ! 299: ! 300: default: ! 301: putlog(0, "未実装 Exec フェーズ $%02x", fdc.cmdbuf[0]); ! 302: break; ! 303: } ! 304: } ! 305: ! 306: // Result フェーズに移行 ! 307: void ! 308: FDCDevice::result_phase() ! 309: { ! 310: putlog(1, "Result フェーズ"); ! 311: fdc.phase = PHASE_RESULT; ! 312: fdc.RQM = true; ! 313: fdc.DIO = DIOtoHost; ! 314: fdc.NDM = false; ! 315: fdc.CB = true; ! 316: } ! 317: ! 318: // イベントコールバック ! 319: void ! 320: FDCDevice::Callback(int arg) ! 321: { ! 322: switch (arg) { ! 323: case FDC::CMD_RECALIBRATE: ! 324: fdd[fdc.accdrive].seek = false; ! 325: fdc.DIO = DIOtoHost; ! 326: Interrupt(); ! 327: break; ! 328: } ! 329: } ! 330: ! 331: // 割り込みを上げる ! 332: void ! 333: FDCDevice::Interrupt() ! 334: { ! 335: gIOCon->IntFDC(); ! 336: } ! 337: ! 338: // コマンド名 ! 339: /* static */ const char * ! 340: FDCDevice::cmdnames_str[] = { ! 341: NULL, // 0x00 ! 342: NULL, // 0x01 ! 343: "READ DIAGNOSTIC", // 0x02 ! 344: "SPECIFY", // 0x03 ! 345: "SENSE DEVICE STATUS", // 0x04 ! 346: "WRITE DATA", // 0x05 ! 347: "READ", // 0x06 ! 348: "RECALIBRATE", // 0x07 ! 349: "SENSE INTERRUPT STATUS", // 0x08 ! 350: "WRITE DELETED DATA", // 0x09 ! 351: "READ ID", // 0x0a ! 352: NULL, // 0x0b ! 353: "READ DELETED DATA", // 0x0c ! 354: "WRITE ID", // 0x0d ! 355: NULL, // 0x0e ! 356: "SEEK", // 0x0f ! 357: NULL, // 0x10 ! 358: "SCAN EQUAL", // 0x11 ! 359: NULL, // 0x12 ! 360: NULL, // 0x13 ! 361: "RESET STANDBY", // 0x14 ! 362: "SET STANDBY", // 0x15 ! 363: "SOFTWARE RESET", // 0x16 ! 364: NULL, // 0x17 ! 365: NULL, // 0x18 ! 366: "SCAN LOW OR EQUAL", // 0x19 ! 367: NULL, // 0x1a ! 368: NULL, // 0x1b ! 369: NULL, // 0x1c ! 370: "SCAN HIGH OR EQUAL", // 0x1d ! 371: }; ! 372: ! 373: // コマンドを名前に変換 ! 374: /* static */ const char * ! 375: FDCDevice::cmd2name(uint32 cmd) ! 376: { ! 377: if (cmd < countof(cmdnames_str) && cmdnames_str[cmd]) { ! 378: return cmdnames_str[cmd]; ! 379: } else { ! 380: return "?"; ! 381: } ! 382: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.