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