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