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