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

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

unix.superglobalmegacorp.com

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