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