|
|
1.1 root 1: //
2: // nono
3: // Copyright (C) 2017 [email protected]
4: //
5:
6: #include "fdc.h"
7: #include "iocon.h"
8: #include "scheduler.h"
9:
10: // コンストラクタ
11: FDCDevice::FDCDevice()
12: {
13: logname = "fdc";
14: devname = "FDC";
15: devaddr = baseaddr;
16: devlen = 0x2000;
17:
18: event.dev = this;
19: event.func = (DeviceCallback_t)&FDCDevice::Callback;
20: event.name = "FDC";
21: }
22:
23: // デストラクタ
24: FDCDevice::~FDCDevice()
25: {
26: }
27:
28: void
29: FDCDevice::ResetHard()
30: {
31: // XXX 他には
32: idle_phase();
33: }
34:
35: uint64
36: FDCDevice::Read8(uint32 addr)
37: {
38: uint32 offset = addr - baseaddr;
39: switch (offset) {
40: case 1:
41: return ReadStatus();
42: case 3:
43: return ReadData();
44: case 5:
45: return ReadDriveStatus();
46: default:
47: break;
48: }
49: PANIC("not impl");
50: }
51:
52: uint64
53: FDCDevice::Read16(uint32 addr)
54: {
55: return 0xff00 | Read8(addr + 1);
56: }
57:
58: uint64
59: FDCDevice::Write8(uint32 addr, uint32 data)
60: {
61: uint32 offset = addr - baseaddr;
62: switch (offset) {
63: case 3:
64: WriteCmd(data);
65: return 0;
66: case 5:
67: if ((data & 0x0f) != 0) {
68: fdc.drivesel = data & 0x0f;
69: putlog(1, "ドライブ選択%s%s%s%s",
70: (fdc.drivesel & 1) ? " #0" : "",
71: (fdc.drivesel & 2) ? " #1" : "",
72: (fdc.drivesel & 4) ? " #2" : "",
73: (fdc.drivesel & 8) ? " #3" : "");
74: }
75: if ((data & 0xe0) != 0) {
76: putlog(0, "未実装ビット書き込み $%06x <- $%02x", addr, data);
77: }
78: return 0;
79:
80: case 7:
81: fdc.is2DD = ((data & 0x10) != 0);
82: fdc.accdrive = data & 3;
83: putlog(1, "アクセスドライブ %s #%d",
84: fdc.is2DD ? "2DD" : "2HD",
85: fdc.accdrive);
86: fdd[fdc.accdrive].motor = (data & 0x80);
87: if (fdd[fdc.accdrive].motor) {
88: putlog(1, "ドライブ #%d モーターオン", fdc.accdrive);
89: } else {
90: putlog(1, "ドライブ #%d モーターオフ", fdc.accdrive);
91: }
92: return 0;
93:
94: default:
95: break;
96: }
97: PANIC("FDC 未実装書き込み $%06x <- $%02x", addr, data);
98: return 0;
99: }
100:
101: uint64
102: FDCDevice::Write16(uint32 addr, uint32 data)
103: {
104: return Write8(addr + 1, data);
105: }
106:
107: uint64
108: FDCDevice::Peek8(uint32 addr)
109: {
110: return 0xff;
111: }
112:
113: // FDC ステータスレジスタ読み込み
114: uint32
115: FDCDevice::ReadStatus()
116: {
117: uint8 stat = 0;
118:
119: if (fdc.RQM) {
120: stat |= FDC::STAT_RQM;
121: }
122: if (fdc.DIO == DIOtoHost) {
123: stat |= FDC::STAT_DIO;
124: }
125: if (fdc.NDM) {
126: stat |= FDC::STAT_NDM;
127: }
128: if (fdc.CB) {
129: stat |= FDC::STAT_CB;
130: }
131: for (int i = 0; i < 4; i++) {
132: if (fdd[i].seek) {
133: stat |= (1 << i);
134: }
135: }
136:
137: putlog(2, "STAT -> $%02x", stat);
138: return stat;
139: }
140:
141: // FDC データレジスタ読み込み
142: uint32
143: FDCDevice::ReadData()
144: {
145: uint8 data;
146:
147: data = 0xff;
148: if (fdc.respos < fdc.reslen) {
149: data = fdc.resbuf[fdc.respos++];
150: }
151: putlog(2, "DATA -> $%02x", data);
152:
153: if (fdc.respos == fdc.reslen) {
154: idle_phase();
155: }
156: return data;
157: }
158:
159: // ドライブステータスレジスタ読み込み
160: uint32
161: FDCDevice::ReadDriveStatus()
162: {
163: uint8 data;
164:
165: // ディスク非挿入しかサポートしていない
166: data = 0x00;
167: putlog(1, "ドライブステータスレジスタ読み込み; ディスク非挿入");
168: return data;
169: }
170:
171: // FDC コマンドレジスタ書き込み
172: void
173: FDCDevice::WriteCmd(uint32 data)
174: {
175: // cmdpos のインクリメントはログ表示の後で行なっている
176: fdc.cmdbuf[fdc.cmdpos] = data;
177:
178: // 1バイト目はコマンドで、それによって長さが変わる。
179: // コマンド名をログに表示したい。
180: if (fdc.cmdpos == 0) {
181: // コマンドはまず下位5ビットであたりをつける
182: switch (data & FDC::CMD_MASK) {
183: case FDC::CMD_SPECIFY:
184: fdc.cmdlen = 3;
185: break;
186: case FDC::CMD_SENSE_DEVICE_STATUS:
187: fdc.cmdlen = 2;
188: break;
189: case FDC::CMD_SENSE_INTERRUPT_STATUS:
190: fdc.cmdlen = 1;
191: break;
192: case FDC::CMD_RECALIBRATE:
193: fdc.cmdlen = 2;
194: break;
195: case FDC::CMD_SEEK:
196: fdc.cmdlen = 3;
197: break;
198:
199: default:
200: // 未実装コマンド
201: fdc.cmdlen = 1;
202: }
203:
204: const char *cmdname = cmd2name(data & FDC::CMD_MASK);
205: putlog(2, "CMD[%d] <- $%02x(%s)", fdc.cmdpos, data, cmdname);
206: } else {
207: putlog(2, "CMD[%d] <- $%02x", fdc.cmdpos, data);
208: // CB は2バイト目から
209: fdc.CB = true;
210: }
211: // ここでインクリメント
212: fdc.cmdpos++;
213:
214: // 全部受け取ったらフェーズ遷移
215: if (fdc.cmdpos >= fdc.cmdlen) {
216: exec_phase();
217: }
218: }
219:
220: // idle フェーズに移行
221: void
222: FDCDevice::idle_phase()
223: {
224: fdc.phase = PHASE_IDLE;
225: fdc.RQM = true;
226: fdc.DIO = DIOtoFDC;
227: fdc.NDM = false;
228: fdc.CB = false;
229: fdc.cmdpos = 0;
230: fdc.cmdlen = 0;
231: fdc.respos = 0;
232: fdc.reslen = 0;
233: putlog(2, "Idle フェーズ");
234: }
235:
236: // Exec フェーズに移行
237: void
238: FDCDevice::exec_phase()
239: {
240: fdc.phase = PHASE_EXEC;
241: fdc.DIO = DIOtoFDC;
242: fdc.CB = true;
243: if (fdc.nd) {
244: fdc.NDM = true; // XXX ?
245: }
246:
247: switch (fdc.cmdbuf[0] & FDC::CMD_MASK) {
248: case FDC::CMD_SPECIFY:
249: putlog(1, "Exec フェーズ: SPECIFY");
250: fdc.srt = fdc.cmdbuf[1] >> 4;
251: fdc.hut = fdc.cmdbuf[1] & 15;
252: fdc.hlt = fdc.cmdbuf[2] >> 1;
253: fdc.nd = (fdc.cmdbuf[2] & 1);
254: idle_phase();
255: break;
256:
257: case FDC::CMD_SENSE_DEVICE_STATUS:
258: putlog(1, "Exec フェーズ: SENSE DEVICE STATUS");
259: fdc.resbuf[0] = fdc.cmdbuf[1] & 0x07;
260: fdc.resbuf[0] |= 0x00;
261: fdc.reslen = 1;
262: result_phase();
263: break;
264:
265: case FDC::CMD_SENSE_INTERRUPT_STATUS:
266: {
267: putlog(1, "Exec フェーズ: SENSE INTERRUPT STATUS");
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 コマンドをメンバ変数にするとか
290: gScheduler->AddEvent(&event);
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
320: FDCDevice::Callback(int arg)
321: {
322: switch (arg) {
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: {
335: gIOCon->IntFDC();
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.