|
|
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:
88: int len;
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 root 147: static const int baseaddr = 0xe94000;
148:
149: public:
1.1.1.8 root 150: // サポートしているドライブ数上限
151: static const int MAX_DRIVE = 4;
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.4 root 281: virtual ~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.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:
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.8 root 456: Monitor monitor { this };
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.