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