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

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

unix.superglobalmegacorp.com

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