|
|
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"
14: #include "fixedqueue.h"
15: #include <array>
1.1 root 16:
1.1.1.9 root 17: class DMACDevice;
1.1.1.8 root 18: class FDDDevice;
1.1.1.9 root 19: class PEDECDevice;
1.1.1.8 root 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:
1.1.1.11 root 86: uint len;
1.1.1.8 root 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.1.11 root 145: static const uint32 baseaddr = 0xe94000;
1.1 root 146:
147: public:
1.1.1.8 root 148: // サポートしているドライブ数上限
1.1.1.11 root 149: static const uint MAX_DRIVE = 4;
1.1.1.8 root 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.10 root 279: ~FDCDevice() override;
1.1 root 280:
1.1.1.8 root 281: bool Create() override;
1.1.1.9 root 282: bool Init() override;
1.1.1.7 root 283: void ResetHard(bool poweron) override;
284:
1.1.1.8 root 285: // READY 信号が変化したことの通知 (FDD から呼ばれる)
286: void ReadyChanged(int unit, bool is_ready);
287:
288: // 強制レディ (OPM から呼ばれる)
1.1.1.7 root 289: void SetForceReady(bool force_ready_);
1.1 root 290:
1.1.1.8 root 291: // DACK と TC 信号 (DMA から呼ばれる)
292: void AssertDACK(bool tc);
293: void NegateDACK();
294:
1.1.1.2 root 295: protected:
296: // BusIO インタフェース
297: static const uint32 NPORT = 4;
1.1.1.11 root 298: busdata ReadPort(uint32 offset);
299: busdata WritePort(uint32 offset, uint32 data);
300: busdata PeekPort(uint32 offset);
301: bool PokePort(uint32 offset, uint32 data);
1.1 root 302:
303: private:
304: uint32 ReadData();
1.1.1.8 root 305: void WriteDataReg(uint32);
1.1 root 306: uint32 ReadDriveStatus();
307: void WriteCmd(uint32);
308:
1.1.1.8 root 309: uint32 GetDriveStatus() const;
310: void PushDreg(uint8);
1.1.1.11 root 311: uint32 PopDreg();
1.1.1.8 root 312: void RequestDataByte();
313:
314: uint8 GetMSR() const;
315: uint8 GetST0() const;
316: uint8 GetST1() const;
317: uint8 GetST2() const;
318:
319: void CommandPhase();
320: void ExecPhase();
321: void ResultPhase();
322:
1.1.1.13! root 323: void CommandCallback(Event *);
! 324: void ResultCallback(Event *);
1.1.1.8 root 325:
326: void ChangeInterrupt();
327:
328: // シーク終了処理
329: void SeekEnd();
330:
331: // データ転送
332: void XferStart(bool is_write);
1.1.1.13! root 333: void XferStartCallback(Event *);
! 334: void XferDataCallback(Event *);
! 335: void XferEndCallback(Event *);
1.1.1.8 root 336:
337: // FDC コマンド
338: void CmdInvalid();
339: void CmdReadDiagnostic();
340: void CmdSpecify();
341: void CmdSenseDeviceStatus();
342: void CmdWriteData();
343: void CmdReadData();
344: void CmdRecalibrate();
345: void CmdSenseInterruptStatus();
346: void CmdWriteDeletedData();
347: void CmdReadID();
348: void CmdReadDeletedData();
349: void CmdWriteID();
350: void CmdSeek();
351: void CmdVersion();
352: void CmdScanEqual();
353: void CmdScanLowOrEqual();
354: void CmdScanHighOrEqual();
355: void CmdResetStandby();
356: void CmdSetStandby();
357: void CmdSoftwareReset();
358:
359: // 未実装コマンドの共通部
360: void CmdNotImplemented();
361:
362: // ユニット US0,US1 信号線の状態を変える
363: void UnitSelect(uint8);
364:
365: // ドライブセレクト信号線の状態を変える
366: void DriveSelect(uint8 sel);
367:
368: // READY 入力端子
369: bool IsReady() const;
370:
371: // ポーリング
372: void StartPoll();
1.1.1.13! root 373: void PollEventCallback(Event *);
1.1.1.8 root 374: bool PollReady(int);
375: bool ExecSeek(int);
376:
377: // モータ停止用
1.1.1.13! root 378: void MotorEventCallback(Event *);
1.1.1.8 root 379:
380: DECLARE_MONITOR_CALLBACK(MonitorUpdate);
381: void MonitorReg(TextScreen&,
382: int x, int y, uint8 reg, const char * const *names);
383:
384: // FDC が内部で記憶しているユニットごとの状態。
385: // こちらは US をインデックスとしてアクセスすること。
386: std::array<UnitInfo, MAX_DRIVE> unitinfo {};
387:
388: // 選択されている FDD
389: FDDDevice *fdd {};
390:
391: // ドライブ数
392: int ndrive {};
393:
394: // 接続されているドライブ。
395: // fdd_list[] は配列なので歯抜けをサポート出来るが、今の所そのような
396: // 設定をする方法がない (必要になったら考える)。
397: std::unique_ptr<FDDDevice> fdd_list[MAX_DRIVE] /*{}*/;
398: // 生ポインタを配列と同じ要領で格納したもの。
399: std::vector<FDDDevice *> fdd_vector {};
400:
401: // SPECIFY で設定(初期化)する項目
402: uint8 srt {};
403: uint8 hut {};
404: uint8 hlt {};
405: bool nd {}; // Non DMA
406: bool initialized {}; // SPECIFY で初期化されたかどうか
407:
408: // コマンド
409: const FDCCmd *cmd {}; // 現在選択中のコマンド
410: static const std::vector<FDCCmd> cmd_list;
411:
412: // FDC 内部状態
413: fdc_phase_t phase {}; // 動作フェーズ
414: FDCCmdBuf cmdbuf {};
415: FDCResBuf resbuf {};
416: FixedQueue<uint8, 1> dreg {}; // 内部データレジスタ
417:
418: bool hd {}; // Head address
1.1.1.10 root 419: uint8 us {}; // Unit Select (US0,US1) 出力信号
1.1.1.8 root 420: bool tc {}; // TC 入力信号
421: bool dack {}; // DACK 入力信号
422:
423: bool mt {}; // Multi Track
424: bool mf {}; // MFM
425: bool sk {}; // Skip
426:
427: bool xfer_start {};
428: bool xfer_enable {};
429: bool xfer_write {};
430: uint xfer_remain {};
431: uint sect_remain {};
432: int index_detected {};
433:
1.1.1.11 root 434: uint seek_srt {}; // SEEK ステップレートタイマカウンタ
1.1.1.8 root 435:
436: MSR msr {};
437: ST0 st0 {};
438: ST1 st1 {};
439: ST2 st2 {};
440:
441: // I/O コントローラ部
442: uint8 drivectrl {}; // ドライブコントロールレジスタ
443: bool motor_on_bit {}; // アクセスドライブ選択レジスタの MOTOR_ON
444:
445: // OPM
446: bool force_ready {}; // 強制レディ
447:
1.1.1.9 root 448: DMACDevice *dmac {};
449: PEDECDevice *pedec {};
450:
1.1.1.13! root 451: Event *phase_event {}; // 状態遷移用
! 452: Event *poll_event {}; // ポーリング用
! 453: Event *motor_event {}; // モータ停止用
1.1 root 454:
1.1.1.12 root 455: Monitor *monitor {};
1.1 root 456: };
1.1.1.4 root 457:
1.1.1.9 root 458: static inline FDCDevice *GetFDCDevice() {
459: return Object::GetObject<FDCDevice>(OBJ_FDC);
460: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.