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