Annotation of nono/vm/spc.cpp, revision 1.1.1.12

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.