|
|
1.1 root 1: //
2: // nono
1.1.1.2 root 3: // Copyright (C) 2020 nono project
4: // Licensed under nono-license.txt
1.1 root 5: //
6:
1.1.1.7 root 7: //
1.1.1.8 ! root 8: // FDC (uPD72065B) + I/O コントローラ
1.1.1.7 root 9: //
10:
1.1 root 11: #pragma once
12:
1.1.1.8 ! root 13: #include "device.h"
1.1.1.7 root 14: #include "event.h"
1.1.1.8 ! root 15: #include "fixedqueue.h"
! 16: #include "monitor.h"
! 17: #include <array>
1.1 root 18:
1.1.1.8 ! root 19: class FDDDevice;
! 20:
! 21: struct FDCCmdBuf
! 22: {
! 23: union {
! 24: uint8 buf[10];
1.1 root 25:
1.1.1.8 ! root 26: struct {
! 27: uint8 code;
! 28: union {
! 29: // READ DATA, READ DELETED DATA
! 30: // WRITE DATA, WRITE DELETED DATA
! 31: // READ DIAGNOSTIC
! 32: struct {
! 33: uint8 hd_us;
! 34: uint8 c;
! 35: uint8 h;
! 36: uint8 r;
! 37: uint8 n;
! 38: uint8 eot;
! 39: uint8 gsl;
! 40: uint8 dtl;
! 41: } data;
! 42:
! 43: // SCAN EQUAL, SCAN LOW OR EQUAL, SCAN HIGH OR EQUAL
! 44: struct {
! 45: uint8 hd_us;
! 46: uint8 c;
! 47: uint8 h;
! 48: uint8 r;
! 49: uint8 n;
! 50: uint8 eot;
! 51: uint8 gsl;
! 52: uint8 dtl;
! 53: uint8 stp;
! 54: } scan;
! 55:
! 56: struct {
! 57: uint8 us;
! 58: uint8 ncn;
! 59: } seek;
! 60:
! 61: struct {
! 62: uint8 us;
! 63: } recalibrate;
! 64:
! 65: struct {
! 66: uint8 srt_hut;
! 67: uint8 hlt_nd;
! 68: } specify;
! 69:
! 70: // READ ID
! 71: struct {
! 72: uint8 hd_us;
! 73: } read_id, sense_device_status;
! 74:
! 75: struct {
! 76: uint8 hd_us;
! 77: uint8 n;
! 78: uint8 sc;
! 79: uint8 gpl;
! 80: uint8 d;
! 81: } write_id;
! 82: };
! 83: };
! 84: };
! 85:
! 86: int len;
! 87:
! 88: void Clear() {
! 89: len = 0;
! 90: }
1.1 root 91: };
92:
1.1.1.8 ! root 93: struct FDCResBuf
! 94: {
! 95: union {
! 96: uint8 buf[7];
! 97:
! 98: struct {
! 99: uint8 st0;
! 100: uint8 st1;
! 101: uint8 st2;
! 102: uint8 c;
! 103: uint8 h;
! 104: uint8 r;
! 105: uint8 n;
! 106: } data;
! 107:
! 108: struct {
! 109: uint8 st0;
! 110: uint8 pcn;
! 111: } interrupt_status;
! 112:
! 113: struct {
! 114: uint8 st3;
! 115: } device_status;
! 116:
! 117: struct {
! 118: uint8 st0;
! 119: } invalid;
! 120: };
! 121:
! 122: int len {};
! 123: int pos {};
! 124:
! 125: void Clear() {
! 126: len = 0;
! 127: pos = 0;
! 128: }
! 129:
! 130: uint8 Take() {
! 131: assert(pos < len);
! 132: return buf[pos++];
! 133: }
! 134:
! 135: uint8 Peek() {
! 136: assert(pos < len);
! 137: return buf[pos];
! 138: }
1.1 root 139: };
140:
1.1.1.8 ! root 141:
1.1.1.6 root 142: class FDCDevice : public IODevice
1.1 root 143: {
1.1.1.2 root 144: using inherited = IODevice;
1.1 root 145: static const int baseaddr = 0xe94000;
146:
147: public:
1.1.1.8 ! root 148: // サポートしているドライブ数上限
! 149: static const int MAX_DRIVE = 4;
! 150:
! 151: private:
! 152: // コマンド定義
! 153: struct FDCCmd
! 154: {
! 155: uint8 code;
! 156: uint8 mask;
! 157: int cmdlen;
! 158: void (FDCDevice::*func)();
! 159: const char *name;
! 160: };
! 161:
! 162: // ユニットのポーリング時の動作状態
! 163: enum class UnitState {
! 164: Idle,
! 165: Seek,
! 166: Recalibrate,
! 167: };
! 168:
! 169: // ユニットの状態
! 170: struct UnitInfo {
! 171: // FDC が記憶しているヘッドがいることになっているシリンダ番号。
! 172: // FDD の実際のヘッド位置とは必ずしも一致しない。
! 173: int pcn;
! 174: // シーク先のシリンダ番号
! 175: int ncn;
! 176: // ユニットごとの、前回調べた READY
! 177: bool ready;
! 178: // ポーリング時動作状態
! 179: UnitState state;
! 180:
! 181: uint64 ready_time; // READY になった時刻
! 182: };
! 183:
! 184: // FDC の動作フェーズ
! 185: enum fdc_phase_t {
! 186: PHASE_COMMAND,
! 187: PHASE_EXEC,
! 188: PHASE_RESULT,
! 189: };
! 190:
! 191: // マスタステータスレジスタ
! 192: static const uint32 MSR_RQM = 0x80;
! 193: static const uint32 MSR_DIO = 0x40;
! 194: static const uint32 MSR_NDM = 0x20;
! 195: static const uint32 MSR_CB = 0x10;
! 196: static const bool DIOtoFDC = false;
! 197: static const bool DIOtoHost = true;
! 198: struct MSR {
! 199: bool rqm; // Request For Master
! 200: bool dio; // Data Input/Output
! 201: bool ndm; // Non-DMA Mode
! 202: bool cb; // FDC Busy
! 203: std::array<bool, 4> db; // FDn Busy (注:seek中/割り込み保留中)
! 204: };
! 205:
! 206: // ST0 レジスタ
! 207: static const uint32 ST0_IC_NT = 0x00;
! 208: static const uint32 ST0_IC_AT = 0x40;
! 209: static const uint32 ST0_IC_IC = 0x80;
! 210: static const uint32 ST0_IC_AI = 0xc0;
! 211: static const uint32 ST0_SE = 0x20;
! 212: static const uint32 ST0_EC = 0x10;
! 213: static const uint32 ST0_NR = 0x08;
! 214: static const uint32 ST0_HD = 0x04;
! 215: static const uint32 ST0_US = 0x03;
! 216: struct ST0 {
! 217: uint8 ic; // Interrupt Code
! 218: bool se; // Seek End
! 219: bool ec; // Equipment Check
! 220: bool nr; // Not Ready
! 221: bool hd;
! 222: uint8 us;
! 223: };
! 224:
! 225: // ST1 レジスタ
! 226: static const uint32 ST1_EN = 0x80;
! 227: static const uint32 ST1_DE = 0x20;
! 228: static const uint32 ST1_OR = 0x10;
! 229: static const uint32 ST1_ND = 0x04;
! 230: static const uint32 ST1_NW = 0x02;
! 231: static const uint32 ST1_MA = 0x01;
! 232: struct ST1 {
! 233: bool en; // End of Cylinder
! 234: bool de; // Data Error
! 235: bool overrun; // Over Run
! 236: bool nd; // No Data
! 237: bool nw; // Not Writable
! 238: bool ma; // Missing Address Mark
! 239: };
! 240:
! 241: // ST2 レジスタ
! 242: static const uint32 ST2_CM = 0x40;
! 243: static const uint32 ST2_DD = 0x20;
! 244: static const uint32 ST2_NC = 0x10;
! 245: static const uint32 ST2_SH = 0x08;
! 246: static const uint32 ST2_SN = 0x04;
! 247: static const uint32 ST2_BC = 0x02;
! 248: static const uint32 ST2_MD = 0x01;
! 249: struct ST2 {
! 250: bool cm; // Control Mark
! 251: bool dd; // Data Error In Data Field
! 252: bool nc; // No Cylinder
! 253: bool sh; // Scan Equal Hit
! 254: bool sn; // Scan Not Satisfied
! 255: bool bc; // Bad Cylinder
! 256: bool md; // Missing Addrss Mark in Data Field
! 257: };
! 258:
! 259: // ST3 レジスタ
! 260: static const uint32 ST3_FT = 0x80;
! 261: static const uint32 ST3_WP = 0x40;
! 262: static const uint32 ST3_RY = 0x20;
! 263: static const uint32 ST3_T0 = 0x10;
! 264: static const uint32 ST3_TS = 0x08;
! 265: static const uint32 ST3_HD = 0x04;
! 266: static const uint32 ST3_US = 0x03;
! 267: struct ST3 {
! 268: bool ft; // Fault
! 269: bool wp; // Write Protect
! 270: bool ry; // Ready
! 271: bool t0; // Track 0
! 272: bool ts; // Two Side
! 273: bool hd;
! 274: uint8 us;
! 275: };
! 276:
! 277: public:
1.1 root 278: FDCDevice();
1.1.1.4 root 279: virtual ~FDCDevice() override;
1.1 root 280:
1.1.1.8 ! root 281: bool Create() override;
1.1.1.7 root 282: void ResetHard(bool poweron) override;
283:
1.1.1.8 ! root 284: // READY 信号が変化したことの通知 (FDD から呼ばれる)
! 285: void ReadyChanged(int unit, bool is_ready);
! 286:
! 287: // 強制レディ (OPM から呼ばれる)
1.1.1.7 root 288: void SetForceReady(bool force_ready_);
1.1 root 289:
1.1.1.8 ! root 290: // DACK と TC 信号 (DMA から呼ばれる)
! 291: void AssertDACK(bool tc);
! 292: void NegateDACK();
! 293:
! 294: // 接続されている FDD のリストを取得 (UI 用)
! 295: const std::vector<FDDDevice *>& GetFDD() const { return fdd_vector; }
! 296:
1.1.1.2 root 297: protected:
298: // BusIO インタフェース
299: static const uint32 NPORT = 4;
1.1.1.5 root 300: uint64 Read(uint32 offset);
301: uint64 Write(uint32 offset, uint32 data);
302: uint64 Peek(uint32 offset);
1.1 root 303:
304: private:
305: uint32 ReadData();
1.1.1.8 ! root 306: void WriteDataReg(uint32);
1.1 root 307: uint32 ReadDriveStatus();
308: void WriteCmd(uint32);
309:
1.1.1.8 ! root 310: uint32 GetDriveStatus() const;
! 311: void PushDreg(uint8);
! 312: int PopDreg();
! 313: void RequestDataByte();
! 314:
! 315: uint8 GetMSR() const;
! 316: uint8 GetST0() const;
! 317: uint8 GetST1() const;
! 318: uint8 GetST2() const;
! 319:
! 320: void CommandPhase();
! 321: void ExecPhase();
! 322: void ResultPhase();
! 323:
! 324: void CommandCallback(Event& ev);
! 325: void ResultCallback(Event&);
! 326:
! 327: void ChangeInterrupt();
! 328:
! 329: // シーク終了処理
! 330: void SeekEnd();
! 331:
! 332: // データ転送
! 333: void XferStart(bool is_write);
! 334: void XferStartCallback(Event&);
! 335: void XferDataCallback(Event&);
! 336: void XferEndCallback(Event&);
! 337:
! 338: // FDC コマンド
! 339: void CmdInvalid();
! 340: void CmdReadDiagnostic();
! 341: void CmdSpecify();
! 342: void CmdSenseDeviceStatus();
! 343: void CmdWriteData();
! 344: void CmdReadData();
! 345: void CmdRecalibrate();
! 346: void CmdSenseInterruptStatus();
! 347: void CmdWriteDeletedData();
! 348: void CmdReadID();
! 349: void CmdReadDeletedData();
! 350: void CmdWriteID();
! 351: void CmdSeek();
! 352: void CmdVersion();
! 353: void CmdScanEqual();
! 354: void CmdScanLowOrEqual();
! 355: void CmdScanHighOrEqual();
! 356: void CmdResetStandby();
! 357: void CmdSetStandby();
! 358: void CmdSoftwareReset();
! 359:
! 360: // 未実装コマンドの共通部
! 361: void CmdNotImplemented();
! 362:
! 363: // ユニット US0,US1 信号線の状態を変える
! 364: void UnitSelect(uint8);
! 365:
! 366: // ドライブセレクト信号線の状態を変える
! 367: void DriveSelect(uint8 sel);
! 368:
! 369: // READY 入力端子
! 370: bool IsReady() const;
! 371:
! 372: // ポーリング
! 373: void StartPoll();
! 374: void PollEventCallback(Event&);
! 375: bool PollReady(int);
! 376: bool ExecSeek(int);
! 377:
! 378: // モータ停止用
! 379: void MotorEventCallback(Event&);
! 380:
! 381: DECLARE_MONITOR_CALLBACK(MonitorUpdate);
! 382: void MonitorReg(TextScreen&,
! 383: int x, int y, uint8 reg, const char * const *names);
! 384:
! 385: // FDC が内部で記憶しているユニットごとの状態。
! 386: // こちらは US をインデックスとしてアクセスすること。
! 387: std::array<UnitInfo, MAX_DRIVE> unitinfo {};
! 388:
! 389: // 選択されている FDD
! 390: FDDDevice *fdd {};
! 391:
! 392: // ドライブ数
! 393: int ndrive {};
! 394:
! 395: // 接続されているドライブ。
! 396: // fdd_list[] は配列なので歯抜けをサポート出来るが、今の所そのような
! 397: // 設定をする方法がない (必要になったら考える)。
! 398: std::unique_ptr<FDDDevice> fdd_list[MAX_DRIVE] /*{}*/;
! 399: // 生ポインタを配列と同じ要領で格納したもの。
! 400: std::vector<FDDDevice *> fdd_vector {};
! 401:
! 402: // SPECIFY で設定(初期化)する項目
! 403: uint8 srt {};
! 404: uint8 hut {};
! 405: uint8 hlt {};
! 406: bool nd {}; // Non DMA
! 407: bool initialized {}; // SPECIFY で初期化されたかどうか
! 408:
! 409: // コマンド
! 410: const FDCCmd *cmd {}; // 現在選択中のコマンド
! 411: static const std::vector<FDCCmd> cmd_list;
! 412:
! 413: // FDC 内部状態
! 414: fdc_phase_t phase {}; // 動作フェーズ
! 415: FDCCmdBuf cmdbuf {};
! 416: FDCResBuf resbuf {};
! 417: FixedQueue<uint8, 1> dreg {}; // 内部データレジスタ
! 418:
! 419: bool hd {}; // Head address
! 420: uint8 us {}; // Unit Select
! 421: bool tc {}; // TC 入力信号
! 422: bool dack {}; // DACK 入力信号
! 423:
! 424: bool mt {}; // Multi Track
! 425: bool mf {}; // MFM
! 426: bool sk {}; // Skip
! 427:
! 428: bool xfer_start {};
! 429: bool xfer_enable {};
! 430: bool xfer_write {};
! 431: uint xfer_remain {};
! 432: uint sect_remain {};
! 433: int index_detected {};
! 434:
! 435: int seek_srt {}; // SEEK ステップレートタイマカウンタ
! 436:
! 437: MSR msr {};
! 438: ST0 st0 {};
! 439: ST1 st1 {};
! 440: ST2 st2 {};
! 441:
! 442: // I/O コントローラ部
! 443: uint8 drivectrl {}; // ドライブコントロールレジスタ
! 444: bool motor_on_bit {}; // アクセスドライブ選択レジスタの MOTOR_ON
! 445:
! 446: // OPM
! 447: bool force_ready {}; // 強制レディ
! 448:
! 449: Event phase_event { this }; // 状態遷移用
! 450: Event poll_event { this }; // ポーリング用
! 451: Event motor_event { this }; // モータ停止用
1.1 root 452:
1.1.1.8 ! root 453: Monitor monitor { this };
1.1 root 454: };
1.1.1.4 root 455:
1.1.1.7 root 456: extern FDCDevice *gFDC;
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.