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