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