Annotation of nono/vm/spc.cpp, revision 1.1.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.