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

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

unix.superglobalmegacorp.com

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