|
|
1.1 root 1: //
2: // nono
1.1.1.4 ! root 3: // Copyright (C) 2020 nono project
! 4: // Licensed under nono-license.txt
1.1 root 5: //
6:
7: #include "fdc.h"
1.1.1.4 ! root 8: #include "ioctlr.h"
1.1 root 9: #include "scheduler.h"
10:
11: // コンストラクタ
12: FDCDevice::FDCDevice()
13: {
14: logname = "fdc";
15: devname = "FDC";
16: devaddr = baseaddr;
17: devlen = 0x2000;
18:
19: event.dev = this;
20: event.func = (DeviceCallback_t)&FDCDevice::Callback;
1.1.1.2 root 21: event.SetName("FDC");
1.1 root 22: }
23:
24: // デストラクタ
25: FDCDevice::~FDCDevice()
26: {
27: }
28:
29: void
30: FDCDevice::ResetHard()
31: {
32: // XXX 他には
33: idle_phase();
34: }
35:
36: uint64
1.1.1.4 ! root 37: FDCDevice::Read(uint32 addr)
1.1 root 38: {
1.1.1.4 ! root 39: switch (addr) {
! 40: case 0:
1.1 root 41: return ReadStatus();
1.1.1.4 ! root 42: case 1:
1.1 root 43: return ReadData();
1.1.1.4 ! root 44: case 2:
1.1 root 45: return ReadDriveStatus();
1.1.1.4 ! root 46: case 3:
! 47: return 0xff;
1.1 root 48: }
1.1.1.4 ! root 49: __unreachable();
1.1 root 50: }
51:
52: uint64
1.1.1.4 ! root 53: FDCDevice::Write(uint32 addr, uint32 data)
1.1 root 54: {
1.1.1.4 ! root 55: switch (addr) {
! 56: case 0:
! 57: return 0;
1.1 root 58:
1.1.1.4 ! root 59: case 1:
1.1 root 60: WriteCmd(data);
61: return 0;
1.1.1.4 ! root 62:
! 63: case 2:
1.1 root 64: if ((data & 0x0f) != 0) {
65: fdc.drivesel = data & 0x0f;
66: putlog(1, "ドライブ選択%s%s%s%s",
67: (fdc.drivesel & 1) ? " #0" : "",
68: (fdc.drivesel & 2) ? " #1" : "",
69: (fdc.drivesel & 4) ? " #2" : "",
70: (fdc.drivesel & 8) ? " #3" : "");
71: }
72: if ((data & 0xe0) != 0) {
73: putlog(0, "未実装ビット書き込み $%06x <- $%02x", addr, data);
74: }
75: return 0;
76:
1.1.1.4 ! root 77: case 3:
1.1 root 78: fdc.is2DD = ((data & 0x10) != 0);
79: fdc.accdrive = data & 3;
80: putlog(1, "アクセスドライブ %s #%d",
81: fdc.is2DD ? "2DD" : "2HD",
82: fdc.accdrive);
83: fdd[fdc.accdrive].motor = (data & 0x80);
84: if (fdd[fdc.accdrive].motor) {
85: putlog(1, "ドライブ #%d モーターオン", fdc.accdrive);
86: } else {
87: putlog(1, "ドライブ #%d モーターオフ", fdc.accdrive);
88: }
89: return 0;
90: }
1.1.1.4 ! root 91: __unreachable();
1.1 root 92: }
93:
94: uint64
1.1.1.4 ! root 95: FDCDevice::Peek(uint32 addr)
1.1 root 96: {
1.1.1.4 ! root 97: // XXX 未実装
1.1 root 98: return 0xff;
99: }
100:
101: // FDC ステータスレジスタ読み込み
102: uint32
103: FDCDevice::ReadStatus()
104: {
105: uint8 stat = 0;
106:
107: if (fdc.RQM) {
108: stat |= FDC::STAT_RQM;
109: }
110: if (fdc.DIO == DIOtoHost) {
111: stat |= FDC::STAT_DIO;
112: }
113: if (fdc.NDM) {
114: stat |= FDC::STAT_NDM;
115: }
116: if (fdc.CB) {
117: stat |= FDC::STAT_CB;
118: }
119: for (int i = 0; i < 4; i++) {
120: if (fdd[i].seek) {
121: stat |= (1 << i);
122: }
123: }
124:
125: putlog(2, "STAT -> $%02x", stat);
126: return stat;
127: }
128:
129: // FDC データレジスタ読み込み
130: uint32
131: FDCDevice::ReadData()
132: {
133: uint8 data;
134:
135: data = 0xff;
136: if (fdc.respos < fdc.reslen) {
137: data = fdc.resbuf[fdc.respos++];
138: }
139: putlog(2, "DATA -> $%02x", data);
140:
141: if (fdc.respos == fdc.reslen) {
142: idle_phase();
143: }
144: return data;
145: }
146:
147: // ドライブステータスレジスタ読み込み
148: uint32
149: FDCDevice::ReadDriveStatus()
150: {
151: uint8 data;
152:
153: // ディスク非挿入しかサポートしていない
154: data = 0x00;
155: putlog(1, "ドライブステータスレジスタ読み込み; ディスク非挿入");
156: return data;
157: }
158:
159: // FDC コマンドレジスタ書き込み
160: void
161: FDCDevice::WriteCmd(uint32 data)
162: {
163: // cmdpos のインクリメントはログ表示の後で行なっている
164: fdc.cmdbuf[fdc.cmdpos] = data;
165:
166: // 1バイト目はコマンドで、それによって長さが変わる。
167: // コマンド名をログに表示したい。
168: if (fdc.cmdpos == 0) {
169: // コマンドはまず下位5ビットであたりをつける
170: switch (data & FDC::CMD_MASK) {
171: case FDC::CMD_SPECIFY:
172: fdc.cmdlen = 3;
173: break;
174: case FDC::CMD_SENSE_DEVICE_STATUS:
175: fdc.cmdlen = 2;
176: break;
177: case FDC::CMD_SENSE_INTERRUPT_STATUS:
178: fdc.cmdlen = 1;
179: break;
180: case FDC::CMD_RECALIBRATE:
181: fdc.cmdlen = 2;
182: break;
183: case FDC::CMD_SEEK:
184: fdc.cmdlen = 3;
185: break;
186:
187: default:
188: // 未実装コマンド
189: fdc.cmdlen = 1;
190: }
191:
192: const char *cmdname = cmd2name(data & FDC::CMD_MASK);
193: putlog(2, "CMD[%d] <- $%02x(%s)", fdc.cmdpos, data, cmdname);
194: } else {
195: putlog(2, "CMD[%d] <- $%02x", fdc.cmdpos, data);
196: // CB は2バイト目から
197: fdc.CB = true;
198: }
199: // ここでインクリメント
200: fdc.cmdpos++;
201:
202: // 全部受け取ったらフェーズ遷移
203: if (fdc.cmdpos >= fdc.cmdlen) {
204: exec_phase();
205: }
206: }
207:
208: // idle フェーズに移行
209: void
210: FDCDevice::idle_phase()
211: {
212: fdc.phase = PHASE_IDLE;
213: fdc.RQM = true;
214: fdc.DIO = DIOtoFDC;
215: fdc.NDM = false;
216: fdc.CB = false;
217: fdc.cmdpos = 0;
218: fdc.cmdlen = 0;
219: fdc.respos = 0;
220: fdc.reslen = 0;
221: putlog(2, "Idle フェーズ");
222: }
223:
224: // Exec フェーズに移行
225: void
226: FDCDevice::exec_phase()
227: {
228: fdc.phase = PHASE_EXEC;
229: fdc.DIO = DIOtoFDC;
230: fdc.CB = true;
231: if (fdc.nd) {
232: fdc.NDM = true; // XXX ?
233: }
234:
235: switch (fdc.cmdbuf[0] & FDC::CMD_MASK) {
236: case FDC::CMD_SPECIFY:
237: putlog(1, "Exec フェーズ: SPECIFY");
238: fdc.srt = fdc.cmdbuf[1] >> 4;
239: fdc.hut = fdc.cmdbuf[1] & 15;
240: fdc.hlt = fdc.cmdbuf[2] >> 1;
241: fdc.nd = (fdc.cmdbuf[2] & 1);
242: idle_phase();
243: break;
244:
245: case FDC::CMD_SENSE_DEVICE_STATUS:
246: putlog(1, "Exec フェーズ: SENSE DEVICE STATUS");
247: fdc.resbuf[0] = fdc.cmdbuf[1] & 0x07;
248: fdc.resbuf[0] |= 0x00;
249: fdc.reslen = 1;
250: result_phase();
251: break;
252:
253: case FDC::CMD_SENSE_INTERRUPT_STATUS:
254: {
255: putlog(1, "Exec フェーズ: SENSE INTERRUPT STATUS");
256: // XXX まだフロッピー挿入はない
257: uint8 st0 = 0;
258: st0 |= FDC::ST0_IC_NT;
259: st0 |= FDC::ST0_EC;
260: st0 |= FDC::ST0_NR;
261: st0 |= fdc.accdrive;
262: fdc.resbuf[0] = st0;
263: fdc.resbuf[1] = 0; // XXX PCN
264: fdc.reslen = 2;
265: result_phase();
266: break;
267: }
268:
269: case FDC::CMD_RECALIBRATE:
270: putlog(1, "Exec フェーズ: RECALIBRATE");
271: fdd[fdc.accdrive].seek = true;
272: // SEEK/RECALIBRATE では CB はセットされない
273: fdc.CB = false;
274: idle_phase();
275: // XXX ヘッドの位置という概念がまだない
276: event.time = 0;
277: event.code = FDC::CMD_RECALIBRATE; // XXX コマンドをメンバ変数にするとか
1.1.1.3 root 278: event.Start();
1.1 root 279: break;
280:
281: case FDC::CMD_SEEK:
282: putlog(1, "Exec フェーズ: SEEK (未実装)");
283: // SEEK/RECALIBRATE では CB はセットされない
284: fdc.CB = false;
285: idle_phase();
286: break;
287:
288: default:
289: putlog(0, "未実装 Exec フェーズ $%02x", fdc.cmdbuf[0]);
290: break;
291: }
292: }
293:
294: // Result フェーズに移行
295: void
296: FDCDevice::result_phase()
297: {
298: putlog(1, "Result フェーズ");
299: fdc.phase = PHASE_RESULT;
300: fdc.RQM = true;
301: fdc.DIO = DIOtoHost;
302: fdc.NDM = false;
303: fdc.CB = true;
304: }
305:
306: // イベントコールバック
307: void
308: FDCDevice::Callback(int arg)
309: {
310: switch (arg) {
311: case FDC::CMD_RECALIBRATE:
312: fdd[fdc.accdrive].seek = false;
313: fdc.DIO = DIOtoHost;
314: Interrupt();
315: break;
316: }
317: }
318:
319: // 割り込みを上げる
320: void
321: FDCDevice::Interrupt()
322: {
1.1.1.4 ! root 323: gIOCtlr->IntFDC();
1.1 root 324: }
325:
326: // コマンド名
327: /* static */ const char *
328: FDCDevice::cmdnames_str[] = {
329: NULL, // 0x00
330: NULL, // 0x01
331: "READ DIAGNOSTIC", // 0x02
332: "SPECIFY", // 0x03
333: "SENSE DEVICE STATUS", // 0x04
334: "WRITE DATA", // 0x05
335: "READ", // 0x06
336: "RECALIBRATE", // 0x07
337: "SENSE INTERRUPT STATUS", // 0x08
338: "WRITE DELETED DATA", // 0x09
339: "READ ID", // 0x0a
340: NULL, // 0x0b
341: "READ DELETED DATA", // 0x0c
342: "WRITE ID", // 0x0d
343: NULL, // 0x0e
344: "SEEK", // 0x0f
345: NULL, // 0x10
346: "SCAN EQUAL", // 0x11
347: NULL, // 0x12
348: NULL, // 0x13
349: "RESET STANDBY", // 0x14
350: "SET STANDBY", // 0x15
351: "SOFTWARE RESET", // 0x16
352: NULL, // 0x17
353: NULL, // 0x18
354: "SCAN LOW OR EQUAL", // 0x19
355: NULL, // 0x1a
356: NULL, // 0x1b
357: NULL, // 0x1c
358: "SCAN HIGH OR EQUAL", // 0x1d
359: };
360:
361: // コマンドを名前に変換
362: /* static */ const char *
363: FDCDevice::cmd2name(uint32 cmd)
364: {
365: if (cmd < countof(cmdnames_str) && cmdnames_str[cmd]) {
366: return cmdnames_str[cmd];
367: } else {
368: return "?";
369: }
370: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.