|
|
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 <array>
1.1 root 17:
1.1.1.9 root 18: class DMACDevice;
1.1.1.8 root 19: class FDDDevice;
1.1.1.9 root 20: class PEDECDevice;
1.1.1.8 root 21:
22: struct FDCCmdBuf
23: {
24: union {
25: uint8 buf[10];
1.1 root 26:
1.1.1.8 root 27: struct {
28: uint8 code;
29: union {
30: // READ DATA, READ DELETED DATA
31: // WRITE DATA, WRITE DELETED DATA
32: // READ DIAGNOSTIC
33: struct {
34: uint8 hd_us;
35: uint8 c;
36: uint8 h;
37: uint8 r;
38: uint8 n;
39: uint8 eot;
40: uint8 gsl;
41: uint8 dtl;
42: } data;
43:
44: // SCAN EQUAL, SCAN LOW OR EQUAL, SCAN HIGH OR EQUAL
45: struct {
46: uint8 hd_us;
47: uint8 c;
48: uint8 h;
49: uint8 r;
50: uint8 n;
51: uint8 eot;
52: uint8 gsl;
53: uint8 dtl;
54: uint8 stp;
55: } scan;
56:
57: struct {
58: uint8 us;
59: uint8 ncn;
60: } seek;
61:
62: struct {
63: uint8 us;
64: } recalibrate;
65:
66: struct {
67: uint8 srt_hut;
68: uint8 hlt_nd;
69: } specify;
70:
71: // READ ID
72: struct {
73: uint8 hd_us;
74: } read_id, sense_device_status;
75:
76: struct {
77: uint8 hd_us;
78: uint8 n;
79: uint8 sc;
80: uint8 gpl;
81: uint8 d;
82: } write_id;
83: };
84: };
85: };
86:
1.1.1.11 root 87: uint len;
1.1.1.8 root 88:
89: void Clear() {
90: len = 0;
91: }
1.1 root 92: };
93:
1.1.1.8 root 94: struct FDCResBuf
95: {
96: union {
97: uint8 buf[7];
98:
99: struct {
100: uint8 st0;
101: uint8 st1;
102: uint8 st2;
103: uint8 c;
104: uint8 h;
105: uint8 r;
106: uint8 n;
107: } data;
108:
109: struct {
110: uint8 st0;
111: uint8 pcn;
112: } interrupt_status;
113:
114: struct {
115: uint8 st3;
116: } device_status;
117:
118: struct {
119: uint8 st0;
120: } invalid;
121: };
122:
123: int len {};
124: int pos {};
125:
126: void Clear() {
127: len = 0;
128: pos = 0;
129: }
130:
131: uint8 Take() {
132: assert(pos < len);
133: return buf[pos++];
134: }
135:
136: uint8 Peek() {
137: assert(pos < len);
138: return buf[pos];
139: }
1.1 root 140: };
141:
1.1.1.8 root 142:
1.1.1.6 root 143: class FDCDevice : public IODevice
1.1 root 144: {
1.1.1.2 root 145: using inherited = IODevice;
1.1.1.11 root 146: static const uint32 baseaddr = 0xe94000;
1.1 root 147:
148: public:
1.1.1.8 root 149: // サポートしているドライブ数上限
1.1.1.11 root 150: static const uint MAX_DRIVE = 4;
1.1.1.8 root 151:
152: private:
153: // コマンド定義
154: struct FDCCmd
155: {
156: uint8 code;
157: uint8 mask;
158: int cmdlen;
159: void (FDCDevice::*func)();
160: const char *name;
161: };
162:
163: // ユニットのポーリング時の動作状態
164: enum class UnitState {
165: Idle,
166: Seek,
167: Recalibrate,
168: };
169:
170: // ユニットの状態
171: struct UnitInfo {
172: // FDC が記憶しているヘッドがいることになっているシリンダ番号。
173: // FDD の実際のヘッド位置とは必ずしも一致しない。
174: int pcn;
175: // シーク先のシリンダ番号
176: int ncn;
177: // ユニットごとの、前回調べた READY
178: bool ready;
179: // ポーリング時動作状態
180: UnitState state;
181:
182: uint64 ready_time; // READY になった時刻
183: };
184:
185: // FDC の動作フェーズ
186: enum fdc_phase_t {
187: PHASE_COMMAND,
188: PHASE_EXEC,
189: PHASE_RESULT,
190: };
191:
192: // マスタステータスレジスタ
193: static const uint32 MSR_RQM = 0x80;
194: static const uint32 MSR_DIO = 0x40;
195: static const uint32 MSR_NDM = 0x20;
196: static const uint32 MSR_CB = 0x10;
197: static const bool DIOtoFDC = false;
198: static const bool DIOtoHost = true;
199: struct MSR {
200: bool rqm; // Request For Master
201: bool dio; // Data Input/Output
202: bool ndm; // Non-DMA Mode
203: bool cb; // FDC Busy
204: std::array<bool, 4> db; // FDn Busy (注:seek中/割り込み保留中)
205: };
206:
207: // ST0 レジスタ
208: static const uint32 ST0_IC_NT = 0x00;
209: static const uint32 ST0_IC_AT = 0x40;
210: static const uint32 ST0_IC_IC = 0x80;
211: static const uint32 ST0_IC_AI = 0xc0;
212: static const uint32 ST0_SE = 0x20;
213: static const uint32 ST0_EC = 0x10;
214: static const uint32 ST0_NR = 0x08;
215: static const uint32 ST0_HD = 0x04;
216: static const uint32 ST0_US = 0x03;
217: struct ST0 {
218: uint8 ic; // Interrupt Code
219: bool se; // Seek End
220: bool ec; // Equipment Check
221: bool nr; // Not Ready
222: bool hd;
223: uint8 us;
224: };
225:
226: // ST1 レジスタ
227: static const uint32 ST1_EN = 0x80;
228: static const uint32 ST1_DE = 0x20;
229: static const uint32 ST1_OR = 0x10;
230: static const uint32 ST1_ND = 0x04;
231: static const uint32 ST1_NW = 0x02;
232: static const uint32 ST1_MA = 0x01;
233: struct ST1 {
234: bool en; // End of Cylinder
235: bool de; // Data Error
236: bool overrun; // Over Run
237: bool nd; // No Data
238: bool nw; // Not Writable
239: bool ma; // Missing Address Mark
240: };
241:
242: // ST2 レジスタ
243: static const uint32 ST2_CM = 0x40;
244: static const uint32 ST2_DD = 0x20;
245: static const uint32 ST2_NC = 0x10;
246: static const uint32 ST2_SH = 0x08;
247: static const uint32 ST2_SN = 0x04;
248: static const uint32 ST2_BC = 0x02;
249: static const uint32 ST2_MD = 0x01;
250: struct ST2 {
251: bool cm; // Control Mark
252: bool dd; // Data Error In Data Field
253: bool nc; // No Cylinder
254: bool sh; // Scan Equal Hit
255: bool sn; // Scan Not Satisfied
256: bool bc; // Bad Cylinder
257: bool md; // Missing Addrss Mark in Data Field
258: };
259:
260: // ST3 レジスタ
261: static const uint32 ST3_FT = 0x80;
262: static const uint32 ST3_WP = 0x40;
263: static const uint32 ST3_RY = 0x20;
264: static const uint32 ST3_T0 = 0x10;
265: static const uint32 ST3_TS = 0x08;
266: static const uint32 ST3_HD = 0x04;
267: static const uint32 ST3_US = 0x03;
268: struct ST3 {
269: bool ft; // Fault
270: bool wp; // Write Protect
271: bool ry; // Ready
272: bool t0; // Track 0
273: bool ts; // Two Side
274: bool hd;
275: uint8 us;
276: };
277:
278: public:
1.1 root 279: FDCDevice();
1.1.1.10 root 280: ~FDCDevice() override;
1.1 root 281:
1.1.1.8 root 282: bool Create() override;
1.1.1.9 root 283: bool Init() override;
1.1.1.7 root 284: void ResetHard(bool poweron) override;
285:
1.1.1.8 root 286: // READY 信号が変化したことの通知 (FDD から呼ばれる)
287: void ReadyChanged(int unit, bool is_ready);
288:
289: // 強制レディ (OPM から呼ばれる)
1.1.1.7 root 290: void SetForceReady(bool force_ready_);
1.1 root 291:
1.1.1.8 root 292: // DACK と TC 信号 (DMA から呼ばれる)
293: void AssertDACK(bool tc);
294: void NegateDACK();
295:
1.1.1.2 root 296: protected:
297: // BusIO インタフェース
298: static const uint32 NPORT = 4;
1.1.1.11 root 299: busdata ReadPort(uint32 offset);
300: busdata WritePort(uint32 offset, uint32 data);
301: busdata PeekPort(uint32 offset);
302: bool PokePort(uint32 offset, uint32 data);
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);
1.1.1.11 root 312: uint32 PopDreg();
1.1.1.8 root 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
1.1.1.10 root 420: uint8 us {}; // Unit Select (US0,US1) 出力信号
1.1.1.8 root 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:
1.1.1.11 root 435: uint seek_srt {}; // SEEK ステップレートタイマカウンタ
1.1.1.8 root 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:
1.1.1.9 root 449: DMACDevice *dmac {};
450: PEDECDevice *pedec {};
451:
1.1.1.8 root 452: Event phase_event { this }; // 状態遷移用
453: Event poll_event { this }; // ポーリング用
454: Event motor_event { this }; // モータ停止用
1.1 root 455:
1.1.1.12! root 456: Monitor *monitor {};
1.1 root 457: };
1.1.1.4 root 458:
1.1.1.9 root 459: static inline FDCDevice *GetFDCDevice() {
460: return Object::GetObject<FDCDevice>(OBJ_FDC);
461: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.