|
|
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 "spc.h"
1.1.1.3 root 8: #include "mainapp.h"
1.1.1.4 root 9: #include "mpu680x0.h"
10: #include "mpu88xx0.h"
1.1 root 11: #include "mystring.h"
12: #include "scheduler.h"
13: #include "vm.h"
14:
1.1.1.2 root 15: // time 時間後に呼び出すコールバックをセットする。
16: // func の書式が面倒なのを省略して書きたいため。
17: #define CallAfter(func_, name_, time_) do { \
18: event.func = (DeviceCallback_t)&SPCDevice::func_; \
19: event.SetName(name_); \
20: event.code = 0; \
21: event.time = time_; \
1.1.1.3 root 22: event.Start(); \
1.1.1.2 root 23: } while (0)
24:
1.1.1.3 root 25: std::unique_ptr<SPCDevice> gSPC;
1.1 root 26:
1.1.1.2 root 27: // コンストラクタ
1.1.1.3 root 28: SPCDevice::SPCDevice()
1.1 root 29: {
30: logname = "spc";
31: devname = "SPC";
1.1.1.3 root 32: // これらは XIOSpace で必要なので、LUNA ではダミー。
33: // もうちょっといい方法を考えたほうがいい。
34: devaddr = 0xe96000;
1.1 root 35: devlen = 0x2000;
36:
1.1.1.3 root 37: SetConfigName("spc0");
1.1.1.2 root 38: myid = -1;
1.1 root 39:
1.1.1.5 ! root 40: monitor_size = nnSize(70, 15);
1.1 root 41:
1.1.1.2 root 42: // 汎用イベント
1.1 root 43: // 名前とコールバック関数は都度セットする。
44: event.dev = this;
1.1.1.2 root 45: event.SetName("SPC phase");
46:
47: // TC カウンタイベント
48: event_tc.dev = this;
49: event_tc.code = 0;
50: event_tc.SetName("SPC Timer");
1.1 root 51: }
52:
1.1.1.2 root 53: // デストラクタ
1.1 root 54: SPCDevice::~SPCDevice()
55: {
56: }
57:
58: bool
59: SPCDevice::Init()
60: {
1.1.1.2 root 61: if (!inherited::Init()) {
62: return false;
63: }
64:
1.1.1.3 root 65: // 実行中に別インスタンスを頻繁に参照しないようにここで vmtype を覚えておく
66: vmtype = gMainApp.GetVMType();
67:
1.1.1.4 root 68: // 入力クロックは機種によって異なる。
69: // X68k は 5MHz が入っている。
70: // LUNA-I はおそらく 6.144MHz だと思われる。LUNA88K は未確認。
71: const ConfigItem& item = gConfig->Find("!spc-tCLF");
72: t_CLF = item.AsInt();
1.1 root 73:
74: return true;
75: }
76:
1.1.1.2 root 77:
1.1 root 78: // 本体リセットスイッチによるリセット
79: void
80: SPCDevice::ResetHard()
81: {
82: // LUNA は本体回路が分からないのでとりあえずこっち。
1.1.1.4 root 83: if (vmtype != VMTYPE_X68030) {
1.1 root 84: Reset();
85: }
86: }
87:
88: // MPU の RESET 命令によるリセット
89: void
90: SPCDevice::ResetSoft()
91: {
92: // X680x0 はこっちだと分かっている。
1.1.1.3 root 93: if (vmtype == VMTYPE_X68030) {
1.1 root 94: Reset();
95: }
96: }
97:
98: // SPC リセット
99: void
100: SPCDevice::Reset()
101: {
102: putlog(1, "リセット");
103:
104: // 初期値 (p.61)
105: spc.sctl = SPC::SCTL_RESET;
106: spc.ints = 0x00;
107: spc.ssts &= 0x0f;
108: spc.serr = 0x00;
109:
110: // XXX マニュアルには書いていないけど、
111: // SDGC bit5 の転送ごとに割り込みを発生させるビットが
112: // OFFになることを NetBSD が期待しているし、
113: // このビットは落ちるのではないだろうか
114: spc.sdgc = 0x00;
1.1.1.2 root 115:
116: // 内部状態
1.1.1.3 root 117: prev_ints = (uint32)-1;
118: prev_ssts = (uint32)-1;
1.1.1.2 root 119: set_atn_in_selection = false;
120: transfer_command_running = false;
1.1.1.3 root 121: event.Stop();
122: event_tc.Stop();
1.1 root 123: }
124:
125: uint64
1.1.1.3 root 126: SPCDevice::Read(uint32 addr)
1.1 root 127: {
128: uint8 data;
129:
1.1.1.3 root 130: switch (addr) {
1.1 root 131: case SPC::BDID:
132: data = 1 << myid;
133: putlog(3, "BDID -> $%02x", data);
134: return data;
135:
136: case SPC::SCTL:
137: data = spc.sctl;
138: putlog(3, "SCTL -> $%02x", data);
139: return data;
140:
141: case SPC::SCMD:
1.1.1.2 root 142: data = spc.scmd;
1.1 root 143: putlog(3, "SCMD -> $%02x", data);
144: return data;
145:
146: case SPC::TMOD:
147: // MB89352 には存在しないレジスタ。
148: // 下位2ビットは %0 らしいので意味はないだろうけど真似ておく。
149: return 0xfc;
150:
151: case SPC::INTS:
152: data = spc.ints;
1.1.1.3 root 153: if (loglevel >= 3) {
154: if (event_tc.active) {
1.1 root 155: // イベント中は値が変わった時だけ表示
156: if (prev_ints != data) {
1.1.1.3 root 157: putlog("INTS -> $%02x", data);
1.1 root 158: prev_ints = data;
159: }
160: } else {
1.1.1.3 root 161: putlog("INTS -> $%02x", data);
1.1 root 162: prev_ints = -1U;
163: }
164: }
165: return data;
166:
167: case SPC::PSNS:
168: data = GetPSNS();
169: putlog(3, "PSNS -> $%02x", data);
170: return data;
171:
172: case SPC::SSTS:
173: data = GetSSTS();
1.1.1.3 root 174: if (loglevel >= 3) {
175: if (event_tc.active) {
1.1 root 176: // イベント中は値が変わった時だけ表示
177: if (prev_ssts != data) {
1.1.1.3 root 178: putlog("SSTS -> $%02x", data);
1.1 root 179: prev_ssts = data;
180: }
181: } else {
1.1.1.3 root 182: putlog("SSTS -> $%02x", data);
1.1 root 183: prev_ssts = -1U;
184: }
185: }
186: return data;
187:
188: case SPC::SERR:
189: data = spc.serr;
190: putlog(3, "SERR -> $%02x", data);
191: return data;
192:
193: case SPC::PCTL:
194: data = GetPCTL();
195: putlog(3, "PCTL -> $%02x", data);
196: return data;
197:
198: case SPC::MBC:
199: putlog(0, "MBC 未実装読み込み");
200: return 0xff;
201:
202: case SPC::DREG:
1.1.1.3 root 203: return ReadDREG();
1.1 root 204:
205: case SPC::TEMP:
206: data = spc.temp_in;
207: putlog(3, "TEMP -> $%02x", data);
208: return data;
209:
210: case SPC::TCH:
211: data = spc.tc >> 16;
212: putlog(3, "TCH -> $%02x", data);
213: return data;
214:
215: case SPC::TCM:
216: data = (spc.tc >> 8) & 0xff;
217: putlog(3, "TCM -> $%02x", data);
218: return data;
219:
220: case SPC::TCL:
221: data = spc.tc & 0xff;
222: putlog(3, "TCL -> $%02x", data);
223: return data;
224:
225: case SPC::EXBF:
226: // MB89352 には存在しないレジスタ
227: return 0xff;
228: }
1.1.1.3 root 229: __unreachable();
1.1 root 230: }
231:
232: uint64
1.1.1.3 root 233: SPCDevice::Write(uint32 addr, uint32 data)
1.1 root 234: {
1.1.1.3 root 235: switch (addr) {
1.1 root 236: case SPC::BDID:
1.1.1.2 root 237: putlog(3, "BDID <- $%02x", data);
238: if (myid == data) {
239: // 同じなら何もしない
240: return 0;
241: }
242: if (myid == -1) {
243: // 初回なのでバスに参加
244: myid = data;
245: scsibus->Attach(this, myid);
246: } else {
247: // そうでなければ移動?
248: putlog(0, "BDID 変更 %d to %d not implemented", myid, data);
249: return 0;
250: }
1.1 root 251: return 0;
1.1.1.3 root 252:
1.1 root 253: case SPC::SCTL:
254: WriteSCTL(data);
255: return 0;
256:
257: case SPC::SCMD:
258: WriteSCMD(data);
259: return 0;
260:
261: case SPC::TMOD:
262: // MB89352 には存在しないレジスタ
263: return 0;
264:
265: case SPC::INTS:
266: WriteINTS(data);
267: return 0;
268:
269: case SPC::SDGC:
270: spc.sdgc = data;
271: putlog(3, "SDGC <- $%02x", spc.sdgc);
272: return 0;
273:
1.1.1.3 root 274: case SPC::SSTS:
275: // XXX 書き込みはどうなる?
276: return 0;
277:
278: case SPC::SERR:
279: // XXX 書き込みはどうなる?
280: return 0;
281:
1.1 root 282: case SPC::PCTL:
283: data &= SPC::PCTL_MASK;
284: putlog(3, "PCTL <- $%02x", data);
285: spc.busfree_intr_enable = (data & SPC::PCTL_BFINT_EN);
1.1.1.2 root 286: SetXfer(data);
1.1 root 287: return 0;
288:
1.1.1.3 root 289: case SPC::MBC:
290: // XXX 書き込みはどうなる?
291: return 0;
292:
1.1 root 293: case SPC::DREG:
1.1.1.2 root 294: putlog(3, "DREG <- $%02x", data);
1.1.1.3 root 295: return WriteDREG(data);
1.1 root 296:
297: case SPC::TEMP:
298: spc.temp_out = data;
299: putlog(3, "TEMP <- $%02x", spc.temp_out);
300:
1.1.1.2 root 301: // Inside (p479) によると、SPC はセレクションタイムアウト時 SEL を
302: // 下げないので、代わりに TEMP に $00 を書き込むことで SEL を下げる、
303: // そうなのだが、データシート PDF には記述が見当たらないし、
304: // luna68k の /boot はここで SEL が下げてしまうと期待した動作に
305: // ならないようだ。
306: // SPC はセレクションタイムアウトしたからと言って、データバスに出した
307: // ID を自動的に取り下げたりはしないので、手動でデータバスをクリア
308: // してあげないといけない (TEMP に $00 を書き込む)、だったんでは。
309: if (0 && GetPhase() == SCSI::Phase::Selection) {
310: NegateSEL();
1.1 root 311: }
312: // Out 方向ならバスに出す
313: if (GetIO() == false) {
1.1.1.2 root 314: SetData(spc.temp_out);
1.1 root 315: }
316: return 0;
317:
318: case SPC::TCH:
319: spc.tc = (spc.tc & 0x00ffff) | (data << 16);
1.1.1.2 root 320: putlog(3, "TCH <- $%02x (TC=$%06x)", data, spc.tc);
1.1 root 321: return 0;
322: case SPC::TCM:
323: spc.tc = (spc.tc & 0xff00ff) | (data << 8);
1.1.1.2 root 324: putlog(3, "TCM <- $%02x (TC=$%06x)", data, spc.tc);
1.1 root 325: return 0;
326: case SPC::TCL:
327: spc.tc = (spc.tc & 0xffff00) | data;
1.1.1.2 root 328: putlog(3, "TCL <- $%02x (TC=$%06x)", data, spc.tc);
1.1 root 329: return 0;
330:
331: case SPC::EXBF:
332: // MB89352 には存在しないレジスタ
333: return 0;
334: }
1.1.1.3 root 335: __unreachable();
1.1 root 336: }
337:
338: uint64
1.1.1.3 root 339: SPCDevice::Peek(uint32 addr)
1.1 root 340: {
1.1.1.3 root 341: switch (addr) {
1.1 root 342: case SPC::BDID:
1.1.1.3 root 343: return 1 << myid;
1.1 root 344:
345: case SPC::SCTL:
1.1.1.3 root 346: return spc.sctl;
1.1 root 347:
348: case SPC::SCMD:
1.1.1.3 root 349: return spc.scmd;
1.1 root 350:
351: case SPC::TMOD:
352: // MB89352 には存在しないレジスタ。
353: // 下位2ビットは %0 らしいので意味はないだろうけど真似ておく。
1.1.1.3 root 354: return 0xfc;
1.1 root 355:
356: case SPC::INTS:
1.1.1.3 root 357: return spc.ints;
1.1 root 358:
359: case SPC::PSNS:
1.1.1.3 root 360: return GetPSNS();
1.1 root 361:
362: case SPC::SSTS:
1.1.1.3 root 363: return GetSSTS();
1.1 root 364:
365: case SPC::SERR:
1.1.1.3 root 366: return spc.serr;
1.1 root 367:
368: case SPC::PCTL:
1.1.1.3 root 369: return GetPCTL();
1.1 root 370:
371: case SPC::MBC:
1.1.1.3 root 372: return 0xff;
1.1 root 373:
374: case SPC::DREG:
1.1.1.3 root 375: // X68k は SPC の DREQ 信号から DTACK 信号を作っているため、
376: // DREQ 信号を出さないプログラム転送モードでは DREG へのアクセスが
377: // すべてバスエラーになってしまう。
378: if (vmtype == VMTYPE_X68030) {
379: if ((spc.scmd & SPC::SCMD_PROGRAM)) {
380: return (uint64)-1;
381: }
382: }
383: return spc.dreg.Peek(0);
1.1 root 384:
385: case SPC::TEMP:
1.1.1.3 root 386: return spc.temp_in;
1.1 root 387:
388: case SPC::TCH:
1.1.1.3 root 389: return spc.tc >> 16;
1.1 root 390:
391: case SPC::TCM:
1.1.1.3 root 392: return (spc.tc >> 8) & 0xff;
1.1 root 393:
394: case SPC::TCL:
1.1.1.3 root 395: return spc.tc & 0xff;
1.1 root 396:
397: case SPC::EXBF:
398: // MB89352 には存在しないレジスタ
1.1.1.3 root 399: return 0xff;
1.1 root 400: }
1.1.1.3 root 401: __unreachable();
1.1 root 402: }
403:
1.1.1.5 ! root 404: void
! 405: SPCDevice::MonitorUpdate(TextScreen& monitor)
1.1 root 406: {
407: int x;
408: int y;
409: uint32 sctl;
410: uint32 scmd;
411: uint32 ints;
412: uint32 psns;
413: uint32 sdgc;
414: uint32 ssts;
415: uint32 serr;
416: uint32 pctl;
417: uint32 tc;
418:
419: monitor.Clear();
420:
421: sctl = spc.sctl;
1.1.1.2 root 422: scmd = spc.scmd;
1.1 root 423: ints = spc.ints;
424: psns = GetPSNS();
425: sdgc = spc.sdgc;
426: ssts = GetSSTS();
427: serr = spc.serr;
428: pctl = GetPCTL();
429: tc = spc.tc;
430:
431: y = 0;
432: monitor.Print(0, y++, "BDID: $%02x (ID=%d)", (1 << myid), myid);
433: monitor.Print(0, y++, "SCTL: $%02x", sctl);
434: monitor.Print(0, y++, "SCMD: $%02x", scmd);
435: monitor.Print(0, y++, "INTS: $%02x", ints);
436: monitor.Print(0, y++, "PSNS: $%02x", psns);
437: monitor.Print(0, y++, "SDGC: $%02x", sdgc);
438: monitor.Print(0, y++, "SSTS: $%02x", ssts);
439: monitor.Print(0, y++, "SERR: $%02x", serr);
440: monitor.Print(0, y++, "PCTL: $%02x", pctl);
441: monitor.Print(0, y++, "MBC : $XX");
442: monitor.Print(0, y, "DREG: ");
443: {
444: uint i;
445: for (i = 0; i < spc.dreg.Length(); i++) {
446: monitor.Print(6 + i * 4, y, "$%02x", spc.dreg.Peek(i));
447: }
448: for (; i < 8; i++) {
449: monitor.Print(6 + i * 4, y, TA::Disable, "---");
450: }
451: }
452: y++;
453: monitor.Print(0, y++, "TEMP: $%02x(IN) $%02x(OUT)",
454: spc.temp_in, spc.temp_out);
455: monitor.Print(0, y++, "TC : $%06x", tc);
456:
457: x = 10;
458: y = 1;
459:
460: // SCTL
461: static const char * const sctl_bits[] = {
462: "RST", "CTRL", "DIAG", "ARB", "PARI", "SEL", "RESL", "INTR"
463: };
1.1.1.5 ! root 464: MonitorReg(monitor, x, y, sctl, sctl_bits);
1.1 root 465: y++;
466:
467: // SCMD
468: static const char * const scmd_bits[] = {
469: "", "", "", "RST", "INTC", "PROG", "", "TERM"
470: };
1.1.1.5 ! root 471: MonitorReg(monitor, x, y, scmd, scmd_bits);
1.1 root 472: static const char * const scmd_cmd[] = {
473: //12345678901234
474: "(Bus Release)",
475: "(Select)",
476: "(Reset ATN)",
477: "(Set ATN)",
478: "(Transfer)",
479: "(XferPause)",
480: "(ResetACK/REQ)",
481: "(Set ACK/REQ)",
482: };
1.1.1.4 root 483: monitor.Puts(x, y, scmd_cmd[scmd >> 5]);
1.1 root 484: y++;
485:
486: // INTS
487: static const char * const ints_bits[] = {
488: "Sel", "Resl", "Disc", "Cmpl", "SReq", "TOut", "HErr", "Rst"
489: };
1.1.1.5 ! root 490: MonitorReg(monitor, x, y, ints, ints_bits);
1.1 root 491: y++;
492:
493: // PSNS
494: static const char * const psns_bits[] = {
495: "REQ", "ACK", "ATN", "SEL", "BSY", "MSG", "C/D", "I/O"
496: };
1.1.1.5 ! root 497: MonitorReg(monitor, x, y, psns, psns_bits);
1.1 root 498: y++;
499:
500: // SDGC
501: static const char * const sdgc_bits[] = {
502: "", "", "XfEn", "", "", "", "", ""
503: };
1.1.1.5 ! root 504: MonitorReg(monitor, x, y, sdgc, sdgc_bits);
1.1 root 505: y++;
506:
507: // SSTS
508: static const char * const ssts_bits[] = {
509: "", "", "SBSY", "XInP", "RSTI", "TCZ", "Full", "Empt"
510: };
1.1.1.5 ! root 511: MonitorReg(monitor, x, y, ssts, ssts_bits);
1.1 root 512: static const char * const ssts_conn[] = {
513: //12345678
514: "(NotConn)",
515: "(As Tgt)",
516: "(As Init)",
517: "(undef?)",
518: };
1.1.1.4 root 519: monitor.Puts(x, y, ssts_conn[ssts >> 6]);
1.1 root 520: y++;
521:
522: // SERR
523: static const char * const serr_bits[] = {
524: "", "", "XOut", "", "PErr", "", "Shrt", ""
525: };
1.1.1.5 ! root 526: MonitorReg(monitor, x, y, serr, serr_bits);
1.1 root 527: y++;
528:
529: // PCTL
530: static const char * const pctl_bits[] = {
531: "BIE", "", "", "", "", "MSG", "C/D", "I/O"
532: };
1.1.1.5 ! root 533: MonitorReg(monitor, x, y, pctl, pctl_bits);
1.1 root 534: y++;
535:
536: // バス状態
537: x = 52;
538: y = 0;
1.1.1.3 root 539: SCSI::Phase ph {};
1.1.1.2 root 540: uint8 rst = 0;
541: uint8 bsy = 0;
542: uint8 sel = 0;
543: uint8 msg = 0;
544: uint8 cd = 0;
545: uint8 io = 0;
546: uint8 atn = 0;
547: uint8 req = 0;
548: uint8 ack = 0;
549: uint8 data = 0;
550: if (bus) {
1.1.1.3 root 551: ph = GetPhase();
1.1.1.2 root 552: rst = GetRST();
553: bsy = GetBSY();
554: sel = GetSEL();
555: msg = GetMSG();
556: cd = GetCD();
557: io = GetIO();
558: atn = GetATN();
559: req = GetREQ();
560: ack = GetACK();
561: data = GetData();
562: }
1.1.1.3 root 563: monitor.Print(x, y++, "Phase: %s", SCSI::GetPhaseName(ph));
1.1.1.4 root 564: monitor.Puts(x, y++, TA::OnOff(rst), "RST");
565: monitor.Puts(x, y++, TA::OnOff(bsy), "BSY");
566: monitor.Puts(x, y++, TA::OnOff(sel), "SEL");
567: monitor.Puts(x, y++, TA::OnOff(msg), "MSG");
568: monitor.Puts(x, y++, TA::OnOff(cd), "CD");
569: monitor.Puts(x, y++, TA::OnOff(io), "IO");
570: monitor.Puts(x, y++, TA::OnOff(atn), "ATN");
571: monitor.Puts(x, y++, TA::OnOff(req), "REQ");
572: monitor.Puts(x, y++, TA::OnOff(ack), "ACK");
1.1.1.2 root 573: monitor.Print(x, y++, "DATA:$%02x", data);
574:
1.1.1.3 root 575: y = 2;
1.1.1.4 root 576: monitor.Puts(x + 4, y++, "(________)");
577: monitor.Puts(x + 4, y++, "(________)");
578: monitor.Puts(x + 4, y++, "+");
579: monitor.Puts(x + 4, y++, "|");
580: monitor.Puts(x + 4, y++, "+");
1.1.1.3 root 581:
1.1.1.2 root 582: // BSY, SEL の内訳。"(76543210)" の順。
583: y = 2;
1.1 root 584: for (int i = 0; i < 8; i++) {
585: if ((bsy & (1 << i))) {
1.1.1.3 root 586: monitor.Print(x + 4 + 8 - i, y, "%d", i);
1.1 root 587: } else {
1.1.1.3 root 588: monitor.Print(x + 4 + 8 - i, y, "_");
1.1 root 589: }
590: }
591: y++;
592: for (int i = 0; i < 8; i++) {
593: if ((sel & (1 << i))) {
1.1.1.3 root 594: monitor.Print(x + 4 + 8 - i, y, "%d", i);
1.1 root 595: } else {
1.1.1.3 root 596: monitor.Print(x + 4 + 8 - i, y, "_");
1.1 root 597: }
598: }
599:
1.1.1.2 root 600: // 転送フェーズ中なら現在の XferPhase
601: y += 2;
1.1.1.3 root 602: if (ph == SCSI::Phase::Transfer) {
1.1.1.4 root 603: monitor.Puts(x + 5, y, SCSI::GetXferPhaseName(GetXfer()));
1.1.1.2 root 604: }
605:
1.1 root 606: // ターゲット
607: x = 0;
608: y = 14;
1.1.1.3 root 609: if (bus) {
610: SCSIDevice *d = bus->GetConnectedTarget();
611: SCSITarget *t = dynamic_cast<SCSITarget*>(d);
612: if (t) {
613: std::vector<uint8> cmds = t->GetCmdSeq();
614: if (cmds.size() > 0) {
615: const char *cmdname = SCSI::GetCommandName(cmds[0]);
616: monitor.Print(x, y, "Command: $%02x", cmds[0]);
617: if (cmdname) {
1.1.1.4 root 618: monitor.Puts(x + 14, y, cmdname);
1.1.1.3 root 619: }
1.1.1.2 root 620: }
1.1 root 621: }
622: }
623: }
624:
625: // レジスタをビットごとに表示する。MonitorUpdate の下請け。
626: void
1.1.1.5 ! root 627: SPCDevice::MonitorReg(TextScreen& monitor,
! 628: int x, int y, uint32 reg, const char * const *names)
1.1 root 629: {
630: for (int i = 0; i < 8; i++) {
631: bool b = reg & (1 << (7 - i));
1.1.1.4 root 632: monitor.Puts(x + i * 5, y, TA::OnOff(b), names[i]);
1.1 root 633: }
634: }
635:
636: // SCTL レジスタへの書き込み
637: void
638: SPCDevice::WriteSCTL(uint32 data)
639: {
640: // リセットの立ち上がり検出が必要
641: uint32 up = ~spc.sctl & data;
642:
643: spc.sctl = data;
644: putlog(3, "SCTL <- $%02x", spc.sctl);
645: if ((up & SPC::SCTL_RESET)) {
646: // リセット
647: Reset();
648: } else {
649: // 通常動作
650: }
651: if ((spc.sctl & SPC::SCTL_CTL_RESET)) {
652: putlog(2, "Control Reset");
653: }
654: if ((spc.sctl & SPC::SCTL_DIAG_MODE)) {
655: putlog(0, "SCTL 未実装 Diag Mode");
656: }
657: }
658:
659: // SCMD レジスタへの書き込み
660: void
661: SPCDevice::WriteSCMD(uint32 data)
662: {
1.1.1.2 root 663: uint32 chg = spc.scmd ^ data; // 変更点
1.1 root 664: spc.scmd = data;
665: putlog(3, "SCMD <- $%02x", spc.scmd);
666:
1.1.1.2 root 667: // Intercept, Program, Terminate Mode の未実装判定は
668: // 転送開始時のみ表示する。
1.1 root 669:
1.1.1.2 root 670: // RST Out 操作は SCTL Reset がオフの時だけ有効
671: // と書いてあるけど、SCTL Reset がオンならほぼ全機能無効なのでは?
672: if ((spc.sctl & SPC::SCTL_RESET) == 0 && (chg & SPC::SCMD_RST_OUT)) {
673: if ((spc.scmd & SPC::SCMD_RST_OUT)) {
674: // 0 -> 1
675: // すでに RST が立ってたらどうするか
676: if (GetRST() == false) {
677: putlog(1, "SCMD RST Out");
678: BusRelease();
679: AssertRST();
680: SetINTS(SPC::INTS_RESET_COND);
681: }
682: } else {
683: // 1 -> 0
684: // 特にすることはない?
685: NegateRST();
1.1 root 686: }
687: }
688:
689: switch (spc.scmd >> 5) {
690: case 0:
691: putlog(2, "SCMD Bus Release コマンド");
692: BusFree();
693: break;
694: case 1:
695: SelectCommand();
696: break;
697: case 2:
1.1.1.2 root 698: putlog(1, "SCMD Reset ATN コマンド (未実装)");
1.1 root 699: break;
700: case 3:
1.1.1.2 root 701: SetATNCommand();
1.1 root 702: break;
703: case 4:
704: TransferCommand();
705: break;
706: case 5:
1.1.1.2 root 707: putlog(2, "SCMD Transfer Pause コマンド (未実装)");
1.1 root 708: break;
709: case 6:
710: putlog(2, "SCMD Reset ACK/REQ コマンド");
711: // イニシエータなら ACK を、ターゲットなら REQ をリセットする。
712: // ターゲットモードはサポートしないので、操作するのは ACK のみ。
1.1.1.2 root 713: NegateACK();
1.1 root 714: break;
715: case 7:
716: putlog(2, "SCMD Set ACK/REQ コマンド");
717: // イニシエータなら ACK を、ターゲットなら REQ をセットする。
718: // ターゲットモードはサポートしないので、操作するのは ACK のみ。
1.1.1.2 root 719: AssertACK();
1.1 root 720: break;
721: }
722: }
723:
724: // INTS レジスタへの書き込み
725: void
726: SPCDevice::WriteINTS(uint32 data)
727: {
728: uint32 ack;
729:
730: // クリアすることになるビットを覚えておく
731: ack = spc.ints & data;
732:
733: // '1' が書き込まれたビットをクリア
734: spc.ints &= ~data;
1.1.1.3 root 735: putlog(3, "INTS <- $%02x (INTS = $%02x)", data, spc.ints);
1.1 root 736:
737: // SPC では INTS でビットを落とす行為は、
738: // ホストが割り込み要因に対して処理を完了したことを
739: // SPC に通知する意味が含まれている。
740:
741: // DISCONNECTED ビットが立っているときは SPC は SCSI から
742: // セレクション、リセレクション要求が来ても応答しない。
743: // DISCONNECTED ビットが下ろされると、応答するようになる。
744:
745: // TIMEOUT ビットをクリアした時が
746: if ((ack & SPC::INTS_TIMEOUT)) {
747: // セレクションフェーズなら
1.1.1.2 root 748: if (GetPhase() == SCSI::Phase::Selection) {
1.1 root 749: // TC がゼロならバスフリー
750: // そうでなければリスタート
751: if (spc.tc == 0) {
752: BusFree();
753: } else {
1.1.1.3 root 754: event_tc.time = spc.tc * t_CLF * 2;
755: event_tc.func = (DeviceCallback_t)&SPCDevice::SelectionTimeout;
756: event_tc.Start();
1.1 root 757: }
758: }
759: }
760: }
761:
1.1.1.2 root 762: // INTS 設定。
763: // INTS にビットを立てる要因が起きた時に data にそれを指定して呼び出す。
764: // この関数は INTS を書き換えて、必要なら割り込みを上げる。
765: // INTS レジスタへの書き込み(割り込み要因のクリア)は WriteINTS() のほう。
1.1 root 766: void
767: SPCDevice::SetINTS(uint32 data)
768: {
769: // 立ち上がりでだけ割り込みがかかるわけではないが表示のため。
770: uint32 up = ~spc.ints & data;
771:
772: // 指定された要因を立てる
773: spc.ints |= data;
774:
1.1.1.2 root 775: // Disconnected 割り込みが起きたら ATN を下げる
776: if ((spc.ints & SPC::INTS_DISCONNECTED) && GetATN()) {
777: NegateATN();
778: }
779:
1.1 root 780: // 割り込み許可なら割り込み。
781: // RESET_COND はノンマスカブル割り込み。
782: if ((spc.sctl & SPC::SCTL_INTR_EN) || (spc.ints & SPC::INTS_RESET_COND)) {
1.1.1.2 root 783: putlog(3, "割り込み ints=$%02x up=$%02x", spc.ints, up);
1.1.1.3 root 784: if (vmtype != VMTYPE_X68030) {
1.1.1.4 root 785: gMPU->Interrupt(this, 2);
1.1 root 786: } else {
787: // とりあえず内蔵だけ
1.1.1.4 root 788: gMPU680x0->Interrupt(this, 1, 0x6c);
1.1 root 789: }
790: }
791: }
792:
793: // PSNS レジスタ値の取得。
794: // Read*() と Peek8() から呼ばれる。
1.1.1.2 root 795: // scsibus 接続前にもモニタの更新などで呼ばれることに注意。
1.1 root 796: uint32
797: SPCDevice::GetPSNS() const
798: {
1.1.1.2 root 799: uint32 data = 0;
800:
801: if (__predict_false(bus == NULL)) {
802: return 0;
803: }
1.1 root 804:
805: if (GetREQ()) {
806: data |= SPC::PSNS_REQ;
807: }
808: if (GetACK()) {
809: data |= SPC::PSNS_ACK;
810: }
811: if (GetATN()) {
812: data |= SPC::PSNS_ATN;
813: }
814: if (GetSEL()) {
815: data |= SPC::PSNS_SEL;
816: }
817: if (GetBSY()) {
818: data |= SPC::PSNS_BSY;
819: }
1.1.1.2 root 820: data |= (uint32)GetXfer();
1.1 root 821:
822: return data;
823: }
824:
825: // SSTS レジスタ値の取得。
826: // Read*() と Peek8() から呼ばれる。
1.1.1.2 root 827: // scsibus 接続前にもモニタの更新などで呼ばれることに注意。
1.1 root 828: uint32
829: SPCDevice::GetSSTS() const
830: {
831: uint32 data;
832:
833: data = spc.ssts & 0xf0;
1.1.1.4 root 834: if (__predict_true(bus != NULL) && GetRST()) { // RST 信号
1.1 root 835: data |= SPC::SSTS_RST_IN;
836: }
837: if (spc.tc == 0) { // TC がゼロか
838: data |= SPC::SSTS_TC_ZERO;
839: }
840: if (spc.dreg.Length() == 8) {
841: data |= SPC::SSTS_DREG_FULL;
842: }
843: if (spc.dreg.Length() == 0) {
844: data |= SPC::SSTS_DREG_EMPTY;
845: }
846:
847: return data;
848: }
849:
850: // PCTL レジスタ値の取得。
851: // Read*() と Peek8() から呼ばれる。
1.1.1.2 root 852: // scsibus 接続前にもモニタの更新などで呼ばれることに注意。
1.1 root 853: uint32
854: SPCDevice::GetPCTL() const
855: {
856: uint32 data;
857:
858: data = 0;
1.1.1.4 root 859: if (__predict_true(bus != NULL)) {
1.1.1.2 root 860: data |= (uint32)GetXfer();
861: }
1.1 root 862: if (spc.busfree_intr_enable) {
863: data |= SPC::PCTL_BFINT_EN;
864: }
865: return data;
866: }
867:
1.1.1.3 root 868: // DREG レジスタの読み込み
869: // (副作用があるので Peek 系からは呼ばないこと)
870: uint64
871: SPCDevice::ReadDREG()
872: {
873: uint32 data;
874:
875: // X68k は SPC の DREQ 信号から DTACK 信号を作っているため、
876: // DREQ 信号を出さないプログラム転送モードでは DREG へのアクセスが
877: // すべてバスエラーになってしまう。
878: if (vmtype == VMTYPE_X68030) {
879: if ((spc.scmd & SPC::SCMD_PROGRAM)) {
880: return (uint64)-1;
881: }
882: }
883:
884: // XFER_OUT は DREG アクセスでリセットされる
885: spc.serr &= ~SPC::SERR_XFER_OUT;
886:
887: // 受信データがあれば取り出す
888: if (__predict_true(spc.dreg.Length() > 0)) {
889: bool q_was_full = spc.dreg.IsFull();
890: data = spc.dreg.Dequeue();
891: if (loglevel >= 4) {
892: putlog("DREG -> $%02x (q=%d TC=0x%x)",
893: data, spc.dreg.Length(), spc.tc);
894: } else {
895: putlog(3, "DREG -> $%02x", data);
896: }
897: // この読み出しが最後だったらこれで転送完了。
898: if (spc.tc == 0 && spc.dreg.Length() == 0) {
899: TransferComplete();
900: }
901: // この読み出しによってバッファに空きが出来たら転送再開。
902: if (transfer_command_running && GetREQ() && q_was_full) {
903: // XXX 時間は適当
904: CallAfter(HardwareTransfer, "SPC ReadDREG to Transfer", t_CLF);
905: }
906: } else {
907: // 受信データがない場合
908: if ((spc.scmd & SPC::SCMD_PROGRAM)) {
909: // XXX プログラム転送中ならどうなる?
910: data = 0xff;
911: putlog(3, "DREG -> $%02x (empty)", data);
912: } else {
913: // DMA 転送
914: // XXX どうする?
915: PANIC("DMA転送中の DREG empty");
916: }
917: }
918: return data;
919: }
920:
921: // DREG レジスタへの書き込み
922: uint64
923: SPCDevice::WriteDREG(uint32 data)
924: {
925: // X68k は SPC の DREQ 信号から DTACK 信号を作っているため、
926: // DREQ 信号を出さないプログラム転送モードでは DREG へのアクセスが
927: // すべてバスエラーになってしまう。
928: if (vmtype == VMTYPE_X68030) {
929: if ((spc.scmd & SPC::SCMD_PROGRAM)) {
930: return (uint64)-1;
931: }
932: }
933:
934: // XFER_OUT は DREG アクセスでリセットされる
935: spc.serr &= ~SPC::SERR_XFER_OUT;
936:
937: // DREG キューに入れて..
938: spc.dreg.Enqueue(data);
939: // ハードウェア転送中で REQ が来てれば送信。
940: if (transfer_command_running && GetREQ()) {
941: // XXX 時間は適当
942: CallAfter(HardwareTransfer, "SPC WriteDREG to Transfer", t_CLF);
943: }
944: return 0;
945: }
946:
1.1 root 947: // バスフリーフェーズに移行する
948: void
949: SPCDevice::BusFree()
950: {
1.1.1.2 root 951: putlog(3, "BusFree");
952:
953: // ここは BDID 書き込み前 (まだ scsibus に自身をつなげる前) にも呼ばれる。
954: // その場合は何もしない。バスフリーのはずでもあるし。
955: if (bus == NULL) {
956: return;
957: }
1.1 root 958:
1.1.1.2 root 959: BusRelease();
1.1 root 960: }
961:
1.1.1.2 root 962: // バスをリリースする。バスフリーとバスリセットから呼ばれる
1.1 root 963: void
964: SPCDevice::BusRelease()
965: {
1.1.1.2 root 966: // 自発的にバスをリリースする場合、今のフェーズから自分が変えていい
967: // BSY、SEL だけを落とす。それ以外の信号線は正しくはないけどとりあえず
968: // 一括して SCSIHostDevice::BusFreeCB() が落とすことにしてある。
969:
970: switch (GetPhase()) {
971: case SCSI::Phase::BusFree:
972: case SCSI::Phase::Transfer:
973: break;
974: case SCSI::Phase::Arbitration:
975: case SCSI::Phase::Selection:
976: case SCSI::Phase::Reselection:
977: NegateSEL();
978: NegateBSY();
979: break;
980: }
1.1 root 981: }
982:
983: // Select コマンド実行
984: void
985: SPCDevice::SelectCommand()
986: {
987: std::string idstr;
988: uint32 data;
1.1.1.2 root 989: uint32 tgtid;
1.1 root 990: uint64 wait;
991:
1.1.1.2 root 992: // ターゲット ID を表示用に解析
1.1 root 993: data = spc.temp_out;
994: if (data == 0) {
995: // ID が一切立ってない?
996: idstr = "TEMP==0; No IDs?";
997: } else if ((data & (1 << myid)) == 0) {
998: // 自 ID が立ってない?
999: idstr = string_format("TEMP=$%02x; No BDID?", data);
1000: } else {
1001: // ここで少なくとも自 ID は立っている
1002: data &= ~(1 << myid);
1003:
1004: if (data == 0) {
1005: // ターゲット ID がない
1006: idstr = string_format("#%d", myid);
1007: } else {
1.1.1.2 root 1008: tgtid = DecodeID(data);
1.1 root 1009: idstr = string_format("#%d -> #%d", myid, tgtid);
1010: }
1011: }
1012: putlog(2, "Select コマンド (%s)", idstr.c_str());
1013:
1014: // アービトレーションありの場合
1015: //
1016: // BSY X\______/~~~~~~~~~~~~~~~~~~~~~~~~~~\_ .. _/^^^^^^^^^^^^^^^
1017: // |t_BFBL| | |t_BIDH|
1018: // DB* ________<XXXXXXXXXXXXXXXXXXXXXXXXXXXX .. XXXXXXXX>________
1019: // |t_ARB|t_AWSL| | |t_BLSH|
1020: // SEL _____________________/~~~~~~~~~~~~~~~ .. ~~~~~~~~\________
1021: // |t_SIDA|t_IDBH| |
1022: // ATN ____________________________/~~~~~~~~ .. ~~~~~~~~~~~~~~~~~
1023: // |t_SHIR|
1024: // INTR _____________________________________ .. _______________/~
1025: //
1026: // t_BFBL = <Min> (6 + TCL) * t_CLF, <Max> (7 + TCL) * t_CLF + 60
1027: // t_ARB = <Min> 32 * t_CLF - 60
1028: // t_AWSL = <Min> 0, <Max> 80
1029: // t_SIDA = <Min> 11 * t_CLF - 30
1030: // t_IDBH = <Min> 2 * t_CLF - 80
1.1.1.2 root 1031: //
1032: // ここではバスフリー検出から少なくとも t_BFBL 以上 + t_ARB + t_AWSL 後に
1033: // SEL と DB* と ATN を立てて、そこから t_SIDA + t_IDBH 後に BSY を落とす。
1034: //
1035: // アービトレーションなしの場合
1036: //
1037: // BSY X\_______________ .. _/~~~~~~~~~~~~~~~
1038: // |t_FRID| |t_BIDH|
1039: // DB* ________<XXXXXXXX .. XXXXXXXX><XXXXXXX
1040: // |t_IDSL| |t_BLSH|
1041: // SEL _______________/~ .. ~~~~~~~~\________
1042: // |t_SHIR|
1043: // INTR _________________ .. _______________/~
1044: //
1045: // t_FRID = <Min> (6 + TCL) * t_CLF, <Max> (7 + TCL) * t_CLF + 140
1046: // t_IDSL = <Min> 11 * t_CLF - 80
1047: // t_BIDH = <Min> t_BLSH = 2 * t_CLF
1048: // t_SHIR = <Max> 60
1049: //
1.1 root 1050:
1051: // t_FRID/t_BFBL はたぶん今からではなくバスフリーになった時点から起算。
1052: // t_FRID と t_BFBL は同じ式なのでここでは t_BFBL で統一。
1053: uint64 t_BFBL = (6 + spc.GetTCL()) * t_CLF; // Min
1.1.1.2 root 1054: uint64 now = gScheduler->GetVirtTime();
1055: if ((last_busfree_time + t_BFBL) > now) {
1056: wait = (last_busfree_time + t_BFBL) - now;
1.1 root 1057: } else {
1058: wait = 0;
1059: }
1060:
1061: spc.ssts &= ~(SPC::SSTS_CONN_INIT | SPC::SSTS_CONN_TARG);
1062: spc.ssts |= SPC::SSTS_SPC_BUSY;
1063:
1.1.1.2 root 1064: // TCH,TCM によるタイマーを始動。
1065: // N が 0 なら無限大なのでタイマーは動かさない。
1066: uint32 N = (spc.tc >> 8) << 8;
1067: if (N != 0) {
1068: event_tc.time = (N + 15) * t_CLF * 2;
1069: event_tc.func = (DeviceCallback_t)&SPCDevice::SelectionTimeout;
1.1.1.3 root 1070: event_tc.Start();
1.1.1.2 root 1071: }
1072:
1.1 root 1073: if ((spc.sctl & SPC::SCTL_ARBIT_EN)) {
1074: // アービトレーションありの場合
1075:
1.1.1.2 root 1076: // ここでは複数のデバイスが同時にアービトレーションフェーズに
1077: // 入ることはないため、アービトレーションを開始したデバイスが
1078: // 必ずバスの使用権を得る。
1.1 root 1079:
1.1.1.2 root 1080: // バスフリーから規定時間後に SEL (と DB* と ATN) を上げる。
1.1 root 1081: uint64 t_ARB = 32 * t_CLF - 60;
1082: uint64 t_AWSL = 40; // 適当に中間
1.1.1.2 root 1083: CallAfter(Arbitration1, "SPC Arbitration", wait + t_ARB + t_AWSL);
1.1 root 1084: } else {
1.1.1.2 root 1085: // アービトレーションなしの場合
1086:
1087: // バスフリーから規定時間後に SEL (と DB*) を上げる。
1.1 root 1088: uint64 t_IDSL = 11 * t_CLF - 80;
1.1.1.2 root 1089: CallAfter(Selection1, "SPC Selection", wait + t_IDSL);
1.1 root 1090: }
1.1.1.2 root 1091: }
1.1 root 1092:
1.1.1.2 root 1093: // アービトレーションフェーズ開始後、規定時間経過したので SEL を立てるところ。
1094: void
1095: SPCDevice::Arbitration1(int dummy)
1096: {
1097: putlog(3, "Arbitration1");
1.1 root 1098:
1.1.1.2 root 1099: spc.ssts |= SPC::SSTS_SPC_BUSY;
1.1 root 1100:
1.1.1.2 root 1101: // 本当は DB* -> SEL -> ATN の順でタイミングも規定されてるけど省略。
1102: // ここでは SEL がトリガーになるので SEL のアサートは最後に行う。
1103: SetData(spc.temp_out);
1104: if (set_atn_in_selection) {
1105: AssertATN();
1106: set_atn_in_selection = false;
1107: }
1108: AssertSEL();
1109:
1110: uint64 t_SIDA = 11 * t_CLF - 30;
1111: uint64 t_IDBH = 2 * t_CLF - 80;
1112: CallAfter(Arbitration2, "SPC Arbitration2", t_SIDA + t_IDBH);
1113: }
1.1 root 1114:
1.1.1.2 root 1115: // アービトレーションフェーズ中、SEL を立ててから規定時間経過したので BSY を
1116: // 下げるところ。
1117: void
1118: SPCDevice::Arbitration2(int dummy)
1119: {
1120: putlog(3, "Arbitration2");
1.1 root 1121:
1.1.1.2 root 1122: NegateBSY();
1.1 root 1123: }
1124:
1.1.1.2 root 1125: // アービトレーションフェーズを使わない場合のセレクションフェーズで、
1126: // 規定時間経過したので SEL を立てるところ。
1.1 root 1127: void
1.1.1.2 root 1128: SPCDevice::Selection1(int dummy)
1.1 root 1129: {
1.1.1.2 root 1130: putlog(3, "Selection1");
1.1 root 1131:
1.1.1.2 root 1132: spc.ssts |= SPC::SSTS_SPC_BUSY;
1.1 root 1133:
1.1.1.2 root 1134: // 本当は DB* -> SEL の順でタイミングも規定されてるけど省略。
1135: // ここでは SEL がトリガーになるので SEL のアサートは最後に行う。
1136: SetData(spc.temp_out);
1137: AssertSEL();
1138: }
1.1 root 1139:
1.1.1.2 root 1140: // セレクションコマンドがタイムアウトした時に呼ばれるコールバック。
1141: void
1142: SPCDevice::SelectionTimeout(int dummy)
1143: {
1144: if (loglevel >= 3) {
1145: int tgtid;
1146: uint8 data = GetData();
1147: data &= ~(1 << myid);
1148: tgtid = DecodeID(data);
1149: if (tgtid == -1) {
1150: putlog("Selection timeout");
1151: } else {
1152: putlog("Selection timeout (#%d)", tgtid);
1153: }
1154: }
1.1 root 1155:
1.1.1.2 root 1156: spc.ssts &= ~(SPC::SSTS_CONN_INIT | SPC::SSTS_SPC_BUSY);
1.1 root 1157:
1.1.1.2 root 1158: // TC は実際には減算カウンタのようだが、とりあえず辻褄合わせ
1159: spc.tc = 0;
1.1 root 1160:
1.1.1.2 root 1161: SetINTS(SPC::INTS_TIMEOUT);
1162: }
1.1 root 1163:
1.1.1.2 root 1164: // SetATN コマンド実行
1165: void
1166: SPCDevice::SetATNCommand()
1167: {
1168: putlog(2, "SCMD Set ATN Command");
1.1 root 1169:
1.1.1.2 root 1170: // Select コマンド前なら、セレクションフェーズで ATN を立てる指示。
1171: // 接続中(転送フェーズ中?) なら即座に ATN を立てる。
1172: switch (GetPhase()) {
1173: case SCSI::Phase::BusFree:
1174: set_atn_in_selection = true;
1175: break;
1176: case SCSI::Phase::Arbitration:
1177: case SCSI::Phase::Selection:
1178: case SCSI::Phase::Reselection:
1179: // Select Command 実行中なので実質ここで呼ばれることはないはずだが
1180: case SCSI::Phase::Transfer:
1181: AssertATN();
1.1 root 1182: break;
1183: }
1184: }
1185:
1.1.1.2 root 1186: // Transfer コマンド実行
1.1 root 1187: void
1.1.1.2 root 1188: SPCDevice::TransferCommand()
1.1 root 1189: {
1.1.1.3 root 1190: putlog(2, "SCMD Transfer Command (xfer=%s len=0x%x)",
1.1.1.2 root 1191: SCSI::GetXferPhaseName(GetPCTL() & 7), spc.tc);
1192:
1193: // SCMD レジスタ書き込みのうち Transfer コマンドに関わる未実装機能の
1194: // ログ表示は SCMD レジスタ書き込み時ではなくここで表示。
1195: if ((spc.scmd & SPC::SCMD_TERM_MODE)) {
1196: putlog(0, "SCMD Padding mode not implemented");
1197: }
1198: if ((spc.scmd & SPC::SCMD_INTERCEPT)) {
1199: putlog(0, "SCMD Intercept Transfer not implemented");
1200: }
1201:
1202: transfer_command_running = true;
1203: spc.ssts |= SPC::SSTS_SPC_BUSY | SPC::SSTS_IN_PROGRESS;
1204:
1205: // 転送開始前に DREG キューを初期化する。
1206: // MPU 側が DREG を全部読まずにフェーズを中断とかはたぶん出来るので。
1207: // XXX 転送開始前なのかリセットなのか…
1208: spc.dreg.Clear();
1209:
1210: // Transfer コマンド発行時に REQ がアサートされていなければ
1211: // アサートされるまで待つ。この場合、ここでは何もすることはなく、
1212: // TransferReqCB() が呼ばれてそこから転送フェーズが動き始める。
1213: if (GetREQ()) {
1214: // コマンドから転送開始までちょっとだけかかる
1215: // XXX 4 * t_CLF だと NetBSD カーネルがレースコンディションにはまる。
1216: CallAfter(TransferCommandStart, "SPC SCMD to Start", 0 * t_CLF);
1.1 root 1217: }
1218: }
1219:
1.1.1.2 root 1220: // バスフリーコールバック (SCSIBus から呼ばれる)
1221: // id はこのバスフリーを行ったデバイス (0..7)
1.1 root 1222: void
1.1.1.2 root 1223: SPCDevice::BusFreeCB(int id)
1.1 root 1224: {
1.1.1.2 root 1225: putlog(4, "BusFree Callback");
1.1 root 1226:
1.1.1.2 root 1227: inherited::BusFreeCB(id);
1228: last_busfree_time = gScheduler->GetVirtTime();
1229:
1230: transfer_command_running = false;
1231: spc.ssts &= ~(SPC::SSTS_CONN_INIT | SPC::SSTS_CONN_TARG);
1232: spc.ssts &= ~(SPC::SSTS_SPC_BUSY | SPC::SSTS_IN_PROGRESS);
1.1 root 1233:
1234: // マニュアルが分かりにくいんだけど、
1.1.1.2 root 1235: // o イニシエータとして動作時に、SPC が自らバスフリーにした時
1236: // o BusFree INT enable ビットが立っていて、ターゲットがバスフリーに
1237: // した時
1.1 root 1238: // のいずれかで INTS のバスフリー検出ビットを立てる
1.1.1.2 root 1239: if (id != myid || spc.busfree_intr_enable) {
1.1 root 1240: SetINTS(SPC::INTS_DISCONNECTED);
1241: }
1242: }
1243:
1.1.1.2 root 1244: // ターゲットがセレクションに応答したコールバック (SCSIBus から呼ばれる)
1.1 root 1245: void
1.1.1.2 root 1246: SPCDevice::SelectionAckCB()
1.1 root 1247: {
1.1.1.2 root 1248: // ターゲットが BSY を立てて応答したので、
1249: // こちらはデータバスをクリアして SEL を下げる。
1250: // これによりセレクションフェーズは成功で完了する。
1251: putlog(4, "SelectionAck Calback");
1252: SetData(0);
1253: NegateSEL();
1254:
1255: // タイムアウトイベントを停止
1.1.1.3 root 1256: event_tc.Stop();
1.1 root 1257:
1258: spc.ssts &= ~SPC::SSTS_SPC_BUSY;
1.1.1.2 root 1259: spc.ssts |= SPC::SSTS_CONN_INIT;
1260:
1261: // Command Complete 割り込みを起こす
1.1 root 1262: SetINTS(SPC::INTS_COMPLETE);
1263: }
1264:
1.1.1.2 root 1265: // 転送フェーズでターゲットが REQ を立てたコールバック (SCSIBus から呼ばれる)
1.1 root 1266: void
1.1.1.2 root 1267: SPCDevice::TransferReqCB()
1.1 root 1268: {
1.1.1.2 root 1269: // REQ が立てば Transfer Command 発行前でも Xfer In Progress は立てる
1270: spc.ssts |= SPC::SSTS_IN_PROGRESS;
1271:
1272: if (transfer_command_running) {
1.1.1.3 root 1273: // ハードウェア転送で SDGC_XFER_ENABLE がセットされていれば、
1.1.1.2 root 1274: // データ要求が来ている時に XFER_OUT をセット(?)
1275: if ((spc.sdgc & SPC::SDGC_XFER_ENABLE)) {
1276: spc.serr |= SPC::SERR_XFER_OUT;
1277: }
1278:
1279: // Transfer Command 実行中なら REQ 待ちだったので
1.1.1.3 root 1280: // ここでハードウェア転送を開始。
1.1.1.2 root 1281: TransferCommandStart(0);
1282: } else {
1.1.1.3 root 1283: // ハードウェア転送中でなくて IN 方向ならここで TEMP に取り込む。
1.1.1.2 root 1284: if (GetIO()) {
1285: spc.temp_in = GetData();
1286: }
1287: }
1288: }
1289:
1290: // Transfer Command の実行開始部分。
1291: // TransferCommand() と TransferReqCB() から呼ばれる。
1292: void
1293: SPCDevice::TransferCommandStart(int dummy)
1294: {
1295: // Transfer コマンドの発行と REQ がアサートの両方が成立した時点で、
1296: // SCSI バスの状態と PCTL レジスタの下位3ビットの状態を比較する。
1297: // 一致していれば転送開始、そうでなければ Service Required 割り込み。
1298: if ((GetPCTL() & 7) == GetXfer()) {
1.1.1.3 root 1299: HardwareTransfer(0);
1.1.1.2 root 1300: } else {
1301: transfer_command_running = false;
1302: SetINTS(SPC::INTS_SERV_REQ);
1303: }
1304: }
1305:
1.1.1.3 root 1306: // ハードウェア転送の1バイト分。
1.1.1.2 root 1307: // イベントコールバックとして呼び出すこと。
1308: // REQ がアサートされているのを確認してから呼び出すこと。
1309: // (1バイト送信するとターゲットが再び REQ を上げるなどしてくるので、
1310: // TransferReqCB() か DREG 書き込みから再びここが呼ばれる)
1311: void
1.1.1.3 root 1312: SPCDevice::HardwareTransfer(int dummy)
1.1.1.2 root 1313: {
1314: // SDGC_XFER_ENABLE は転送要求ごとに割り込みを上げる。
1315: // (SPC から見て) 入力操作時は読み込めるデータがある場合、出力操作時は
1316: // キューにバイトを書き込む必要がある場合に、割り込みを上げる。
1317:
1318: // DREG が送受信不可能ならここでは何もせずに帰るだけでよい。
1319: // その後 DREG アクセスによって送受信可能になればまたこれが呼ばれる。
1320: if (GetIO()) {
1321: // Input (ターゲット → イニシエータ)
1322: bool queued = spc.dreg.Enqueue(GetData());
1323: // SDGC_XFER_ENABLE なら読み込めるデータがある場合に割り込み。
1324: if ((spc.sdgc & SPC::SDGC_XFER_ENABLE)) {
1325: putlog(3, "SDGC XFER_OUT Interrupt");
1326: SetINTS(0);
1327: }
1328: if (!queued) {
1.1.1.3 root 1329: putlog(4, "Hardware Transfer (DREG full)");
1.1.1.2 root 1330: return;
1331: }
1332: } else {
1333: // Output (イニシエータ → ターゲット)
1334: if (spc.dreg.Length() != 0) {
1335: SetData(spc.dreg.Dequeue());
1.1 root 1336: } else {
1.1.1.3 root 1337: putlog(4, "Hardware Transfer (DREG empty)");
1.1.1.2 root 1338: // SDGC_XFER_ENABLE ならキューに書き込む必要がある場合に割り込み。
1339: if ((spc.sdgc & SPC::SDGC_XFER_ENABLE)) {
1340: putlog(3, "SDGC XFER_OUT Interrupt");
1341: SetINTS(0);
1342: }
1343: return;
1.1 root 1344: }
1345: }
1.1.1.2 root 1346: // SDGC XFER_OUT のログと順序が微妙になるけど、
1347: // DREG full/empty で2行出るのを避けたいので。
1.1.1.3 root 1348: putlog(4, "Hardware Transfer");
1.1.1.2 root 1349:
1350: // XXX XFER_OUT はどこで落とすんやろうか。
1351: // データ要求が来たら上げるのだから用が済んだら下ろすのかしら。
1352: spc.serr &= ~SPC::SERR_XFER_OUT;
1353:
1354: AssertACK();
1355:
1356: // 転送完了
1357: spc.tc--;
1.1.1.3 root 1358: putlog(4, "Hardware Transfer: %s q=%d tc=%d",
1.1.1.2 root 1359: (GetIO() ? "IN" : "OUT"), spc.dreg.Length(), spc.tc);
1360: if (spc.tc == 0) {
1.1.1.3 root 1361: // どちらでも転送自体はここで完了(?)
1.1.1.2 root 1362: transfer_command_running = false;
1363:
1.1.1.3 root 1364: if (GetIO()) {
1365: // Input 時は TC がゼロになって DREG キューを全部読み出した
1366: // ところで完了なので、ここでは何もしない。
1367: } else {
1368: // Output ならここで転送完了。
1369: TransferComplete();
1.1.1.2 root 1370: }
1371: }
1372:
1373: // メッセージアウトフェーズの最終バイト送信中(?)に ATN を下げる
1374: if (GetXfer() == SCSI::XferPhase::MsgOut && spc.tc == 0) {
1375: NegateATN();
1376: }
1377:
1378: if (GetXfer() == SCSI::XferPhase::MsgIn && spc.tc == 0) {
1379: // ただしメッセージインフェーズの最終バイトなら ACK を下げない。
1380: } else {
1381: NegateACK();
1382: }
1.1 root 1383: }
1.1.1.3 root 1384:
1385: // 転送完了。
1386: // HardwareTransfer() と Read() から呼ばれる。
1387: void
1388: SPCDevice::TransferComplete()
1389: {
1390: spc.ssts &= ~(SPC::SSTS_SPC_BUSY | SPC::SSTS_IN_PROGRESS);
1391: SetINTS(SPC::INTS_COMPLETE);
1392: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.