Annotation of nono/vm/sio.cpp, revision 1.1.1.9

1.1       root        1: //
                      2: // nono
1.1.1.4   root        3: // Copyright (C) 2020 nono project
                      4: // Licensed under nono-license.txt
1.1       root        5: //
                      6: 
1.1.1.9 ! root        7: //
        !             8: // SIO (uPD7201)
        !             9: //
        !            10: 
        !            11: #define MPSCC_SIO_LOG_HACK
1.1       root       12: #include "sio.h"
1.1.1.9 ! root       13: #include "hostcom.h"
1.1.1.8   root       14: #include "keyboard.h"
1.1.1.9 ! root       15: #include "mainapp.h"
1.1       root       16: 
1.1.1.9 ! root       17: // グローバル参照用
        !            18: SIODevice *gSIO;
1.1       root       19: 
1.1.1.9 ! root       20: // コンストラクタ
1.1       root       21: SIODevice::SIODevice()
1.1.1.7   root       22:        : inherited("SIO")
1.1       root       23: {
                     24:        devaddr = 0x51000000;
                     25: 
1.1.1.9 ! root       26:        mpscc.chan[0].desc = "Serial Console";
        !            27:        mpscc.chan[1].desc = "Keyboard";
        !            28: 
        !            29:        // ポートアドレス。
        !            30:        // デバイス自身は自分が配置されるアドレスを知らなくてよい構造になって
        !            31:        // いるが、直接アクセスしたりする場合などに毎回アドレスを確認するのが
        !            32:        // 面倒なので(全機種で向きと間隔が異なる)、モニタで表示されてほしい。
        !            33:        if (gMainApp.GetVMType() == VMTYPE_LUNA1) {
        !            34:                mpscc.chan[0].dataaddr = 0x51000000;
        !            35:                mpscc.chan[0].ctrladdr = 0x51000002;
        !            36:                mpscc.chan[1].dataaddr = 0x51000004;
        !            37:                mpscc.chan[1].ctrladdr = 0x51000006;
        !            38:        } else {
        !            39:                mpscc.chan[0].dataaddr = 0x51000000;
        !            40:                mpscc.chan[0].ctrladdr = 0x51000004;
        !            41:                mpscc.chan[1].dataaddr = 0x51000008;
        !            42:                mpscc.chan[1].ctrladdr = 0x5100000c;
        !            43:        }
1.1.1.7   root       44: 
1.1.1.8   root       45:        // 153.6kHz = 6.510416...usec / bit;
                     46:        // 12bit = 78.125usec
1.1.1.9 ! root       47:        xc12_ns = 78.125_usec;
1.1.1.8   root       48: 
1.1.1.7   root       49:        // LUNA では SIO と呼ぶほうが通りがいい。
1.1.1.9 ! root       50:        // イベントの登録は親クラスで行ってある。
1.1.1.8   root       51:        for (int ch = 0; ch < txevent.size(); ch++) {
1.1.1.9 ! root       52:                auto& chan = mpscc.chan[ch];
        !            53:                txevent[ch].SetName(string_format("SIO Ch%c TX", chan.name));
        !            54:                rxevent[ch].SetName(string_format("SIO Ch%c RX", chan.name));
1.1.1.8   root       55:        }
1.1.1.9 ! root       56: 
        !            57:        monitor.func = ToMonitorCallback(&SIODevice::MonitorUpdate);
        !            58:        monitor.SetSize(70, 22);
1.1.1.7   root       59:        monitor.Regist(ID_MONITOR_SIO);
1.1       root       60: }
                     61: 
1.1.1.9 ! root       62: // デストラクタ
1.1       root       63: SIODevice::~SIODevice()
                     64: {
1.1.1.9 ! root       65:        gSIO = NULL;
        !            66: }
        !            67: 
        !            68: // リセット
        !            69: void
        !            70: SIODevice::ResetHard(bool poweron)
        !            71: {
        !            72:        // master_int_enable は uPD7201 にはなく常に true と等価
        !            73:        mpscc.master_int_enable = true;
        !            74: 
        !            75:        // CR2 b0-5,7 = %0
        !            76:        mpscc.intdma_mode = 0;
        !            77:        mpscc.priority_select = false;
        !            78:        mpscc.int_mode = 0;
        !            79:        mpscc.vectored_mode = false;
        !            80:        mpscc.syncb = false;
        !            81: 
        !            82:        for (auto& chan : mpscc.chan) {
        !            83:                ResetChannel(chan);
        !            84:        }
        !            85: 
        !            86:        // ログ省略ステートをリセット
        !            87:        sr0_logphase = 0;
        !            88: }
        !            89: 
        !            90: // チャンネルリセット
        !            91: void
        !            92: SIODevice::ResetChannel(MPSCCChan& chan)
        !            93: {
        !            94:        // CR0 b0-2 = %0
        !            95:        chan.ptr = 0;
        !            96: 
        !            97:        // CR1 b0,1,3,4,7 = %0
        !            98:        chan.esint_enable = false;
        !            99:        chan.txint_enable = false;
        !           100:        chan.rxint_mode = 0;
        !           101:        chan.wait_enable = false;
        !           102: 
        !           103:        // CR3 b0-7 = %0
        !           104:        chan.cr3 = 0;
        !           105:        chan.rx_enable = false;
        !           106: 
        !           107:        // CR5 b1,2,3,4,7 = %0
        !           108:        chan.cr5 &= 0x61;
        !           109:        chan.tx_enable = false;
        !           110: 
        !           111:        // SR0 b0,1 = %0、b2,6 = %1
        !           112:        chan.rxlen = 0;
        !           113:        chan.intpend = 0;
        !           114:        chan.txlen = 0;
        !           115:        chan.tx_underrun = true;
        !           116: 
        !           117:        // SR1 b4-7 = %0
        !           118:        chan.sr1 &= ~(MPSCC::SR1_ENDOFFRAME |
        !           119:                      MPSCC::SR1_FRAMEERROR |
        !           120:                      MPSCC::SR1_RXOVERRUN  |
        !           121:                      MPSCC::SR1_PARITYERROR);
        !           122: 
        !           123:        ResetChannelCommon(chan);
1.1       root      124: }
                    125: 
                    126: uint64
1.1.1.6   root      127: SIODevice::Read(uint32 offset)
1.1       root      128: {
1.1.1.9 ! root      129:        uint64 data;
1.1       root      130: 
1.1.1.6   root      131:        switch (offset) {
1.1       root      132:         case 0:
1.1.1.9 ! root      133:                data = ReadData(mpscc.chan[0]);
1.1       root      134:                break;
                    135:         case 1:
1.1.1.9 ! root      136:                data = ReadCtrl(mpscc.chan[0]);
1.1       root      137:                break;
                    138:         case 2:
1.1.1.9 ! root      139:                data = ReadData(mpscc.chan[1]);
1.1       root      140:                break;
                    141:         case 3:
1.1.1.9 ! root      142:                data = ReadCtrl(mpscc.chan[1]);
1.1       root      143:                break;
                    144:         default:
                    145:                __unreachable();
                    146:        }
                    147:        return data;
                    148: }
                    149: 
                    150: uint64
1.1.1.6   root      151: SIODevice::Write(uint32 offset, uint32 data)
1.1       root      152: {
1.1.1.6   root      153:        switch (offset) {
1.1       root      154:         case 0:
1.1.1.9 ! root      155:                WriteData(mpscc.chan[0], data);
        !           156:                break;
1.1       root      157:         case 1:
1.1.1.9 ! root      158:                WriteCtrl(mpscc.chan[0], data);
        !           159:                break;
1.1       root      160:         case 2:
1.1.1.9 ! root      161:                WriteData(mpscc.chan[1], data);
        !           162:                break;
1.1       root      163:         case 3:
1.1.1.9 ! root      164:                WriteCtrl(mpscc.chan[1], data);
        !           165:                break;
        !           166:         default:
        !           167:                __unreachable();
1.1       root      168:        }
1.1.1.9 ! root      169:        return 0;
1.1       root      170: }
                    171: 
                    172: uint64
1.1.1.6   root      173: SIODevice::Peek(uint32 offset)
1.1       root      174: {
1.1.1.9 ! root      175:        uint64 data;
        !           176: 
1.1.1.6   root      177:        switch (offset) {
1.1.1.3   root      178:         case 0:
1.1.1.9 ! root      179:                data = PeekData(mpscc.chan[0]);
        !           180:                break;
1.1.1.3   root      181:         case 1:
1.1.1.9 ! root      182:                data = PeekCtrl(mpscc.chan[0]);
        !           183:                break;
        !           184:         case 2:
        !           185:                data = PeekData(mpscc.chan[1]);
        !           186:                break;
        !           187:         case 3:
        !           188:                data = PeekCtrl(mpscc.chan[1]);
        !           189:                break;
        !           190:         default:
        !           191:                __unreachable();
        !           192:        }
        !           193:        return data;
        !           194: }
        !           195: 
        !           196: // 書き込みレジスタ名を返す
        !           197: const char *
        !           198: SIODevice::CRName(const MPSCCChan& chan, int ptr_) const
        !           199: {
        !           200:        assert(ptr_ < 8);
        !           201:        int idx = ptr_ * 2 + chan.id;
        !           202:        assert(idx < countof(crnames));
        !           203:        return crnames[idx];
        !           204: }
        !           205: 
        !           206: // 読み込みレジスタ名を返す
        !           207: const char *
        !           208: SIODevice::SRName(const MPSCCChan& chan, int ptr_) const
        !           209: {
        !           210:        assert(ptr_ < 8);
        !           211:        int idx = ptr_ * 2 + chan.id;
        !           212:        assert(idx < countof(srnames));
        !           213:        return srnames[idx];
        !           214: }
        !           215: 
        !           216: // 制御ポートの読み込み
        !           217: uint8
        !           218: SIODevice::ReadCtrl(MPSCCChan& chan)
        !           219: {
        !           220:        uint8 data;
        !           221: 
        !           222:        switch (chan.ptr) {
        !           223:         case 0:        // SR0
        !           224:                data = GetSR0(chan);
        !           225:                break;
        !           226: 
        !           227:         case 1:        // SR1
        !           228:                data = chan.sr1;
        !           229:                break;
1.1.1.3   root      230: 
                    231:         case 2:
1.1.1.9 ! root      232:                // SR2B はベクタの読み出し
        !           233:                if (chan.id == 1) {
        !           234:                        data = GetSR2B();
        !           235:                        break;
        !           236:                }
        !           237: 
        !           238:                // SR2A はない
        !           239:                // XXX どうなる?
        !           240:                FALLTHROUGH;
        !           241: 
        !           242:         default:
        !           243:                // XXX どうなる?
        !           244:                putlog(0, "%s 未実装レジスタ読み込み", SRName(chan));
        !           245:                // SR0 へ戻る?
        !           246:                chan.ptr = 0;
        !           247:                return 0xff;
        !           248:        }
        !           249: 
        !           250:        // PROM が SR0 を高速でポーリングするのでログを細工する。
        !           251:        //
        !           252:        //             SR0       SRn
        !           253:        // loglevel<=1 非表示    非表示
        !           254:        // loglevel 2  *         常に表示
        !           255:        // loglevel 3  常に表示  常に表示
        !           256:        //
        !           257:        // *: 同じ値の読み込みログが連続したら省略。
        !           258:        if (__predict_true(loglevel <= 1)) {
        !           259:                // nop
        !           260:        } else if (__predict_false(loglevel >= 3 || chan.ptr > 0)) {
        !           261:                putlog(2, "%s -> $%02x", SRName(chan), data);
        !           262:        } else {
        !           263:                // ここは loglevel==2 && SR0
        !           264: 
        !           265:                switch (sr0_logphase) {
        !           266:                 case 0:        // 表示する
        !           267:                 first:
        !           268:                        sr0_logphase = 1;
        !           269:                        sr0_lastread = data;
        !           270:                 disp:
        !           271:                        putlogn("%s -> $%02x", SRName(chan, 0), data);
        !           272:                        break;
        !           273:                 case 1:        // 連続(1回目)
        !           274:                        if (__predict_true(data == sr0_lastread)) {
        !           275:                                sr0_logphase++;
        !           276:                                goto disp;
        !           277:                        } else {
        !           278:                                goto first;
        !           279:                        }
        !           280:                        break;
        !           281:                 case 2:        // 連続(2回目)
        !           282:                        if (__predict_true(data == sr0_lastread)) {
        !           283:                                sr0_logphase++;
        !           284:                                putlogn("%s -> $%02x (omit the following)",
        !           285:                                        SRName(chan, 0), data);
        !           286:                        } else {
        !           287:                                goto first;
        !           288:                        }
        !           289:                        break;
        !           290:                 default:       // 連続(3回目以降)
        !           291:                        if (__predict_true(data == sr0_lastread)) {
        !           292:                                // 連続したので表示省略
        !           293:                        } else {
        !           294:                                goto first;
        !           295:                        }
        !           296:                        break;
        !           297:                }
        !           298:        }
        !           299:        // アクセス後は SR0 へ戻す
        !           300:        chan.ptr = 0;
        !           301: 
        !           302:        return data;
        !           303: }
        !           304: 
        !           305: // 制御ポートの書き込み
        !           306: void
        !           307: SIODevice::WriteCtrl(MPSCCChan& chan, uint32 data)
        !           308: {
        !           309:        // CR0 はコマンドかまたは次にアクセスするレジスタを指定する。
        !           310:        // CR0 以外のレジスタをアクセスすると、次のアクセスは CR0 に戻る。
        !           311: 
        !           312:        if (chan.ptr == 0) {
        !           313:                WriteCR0(chan, data);
        !           314:        } else {
        !           315:                switch (chan.ptr) {
        !           316:                 case 1:
        !           317:                        WriteCR1(chan, data);
        !           318:                        break;
        !           319:                 case 2:
        !           320:                        WriteCR2(chan, data);
        !           321:                        break;
        !           322:                 case 3:
        !           323:                        WriteCR3(chan, data);
        !           324:                        break;
        !           325:                 case 4:
        !           326:                        WriteCR4(chan, data);
        !           327:                        break;
        !           328:                 case 5:
        !           329:                        WriteCR5(chan, data);
        !           330:                        break;
        !           331:                 case 6:
        !           332:                        WriteCR6(chan, data);
        !           333:                        break;
        !           334:                 case 7:
        !           335:                        WriteCR7(chan, data);
        !           336:                        break;
        !           337:                 default:
        !           338:                        __unreachable();
        !           339:                }
        !           340:                // アクセス後は CR0 へ戻す
        !           341:                chan.ptr = 0;
        !           342:        }
        !           343: }
        !           344: 
        !           345: // 制御ポートの Peek
        !           346: uint8
        !           347: SIODevice::PeekCtrl(const MPSCCChan& chan) const
        !           348: {
        !           349:        switch (chan.ptr) {
        !           350:         case 0:        // SR0
        !           351:                return GetSR0(chan);
        !           352: 
        !           353:         case 1:        // SR1
        !           354:                return chan.sr1;
        !           355: 
        !           356:         case 2:        // SR2
        !           357:                // SR2A はない。SR2B は割り込み要因込みのベクタ番号。
        !           358:                if (chan.id == 1) {
        !           359:                        return GetSR2B();
        !           360:                }
        !           361:                FALLTHROUGH;
        !           362: 
        !           363:         default:
        !           364:                // 未調査
        !           365:                return 0xff;
        !           366:        }
        !           367: }
        !           368: 
        !           369: // CR1 レジスタの内容を取得
        !           370: uint8
        !           371: SIODevice::GetCR1(const MPSCCChan& chan) const
        !           372: {
        !           373:        uint8 data = 0;
        !           374: 
        !           375:        if (chan.wait_enable)
        !           376:                data |= MPSCC::CR1_WAIT_EN;
        !           377:        if (chan.wait_on_rx)
        !           378:                data |= MPSCC::CR1_WAIT_RX;
        !           379:        // 内部フォーマットから元のビットを求める
        !           380:        switch (chan.rxint_mode) {
        !           381:         case MPSCCChan::RXINT_DISABLE:
        !           382:                break;
        !           383:         case MPSCCChan::RXINT_1STCHAR:
        !           384:                data |= MPSCC::CR1_RXINT_1STCHAR;
        !           385:                break;
        !           386:         case MPSCCChan::RXINT_ALLCHAR:
        !           387:                if (chan.sp_parity) {
        !           388:                        data |= MPSCC::CR1_RXINT_ALLCHAR;
        !           389:                } else {
        !           390:                        data |= MPSCC::CR1_RXINT_ALL_BUT_PE;
        !           391:                }
        !           392:                break;
        !           393:         default:
        !           394:                assert(false);
        !           395:        }
        !           396:        if (chan.txint_enable)
        !           397:                data |= MPSCC::CR1_TXINT_EN;
        !           398:        if (chan.esint_enable)
        !           399:                data |= MPSCC::CR1_ESINT_EN;
        !           400: 
        !           401:        return data;
        !           402: }
        !           403: 
        !           404: // CR2A レジスタの内容を取得
        !           405: uint8
        !           406: SIODevice::GetCR2A() const
        !           407: {
        !           408:        uint8 data = 0;
        !           409: 
        !           410:        data |= mpscc.syncb ? MPSCC::CR2_SYNCB : 0;
        !           411:        data |= mpscc.vectored_mode ? MPSCC::CR2_VM : 0;
        !           412:        data |= mpscc.int_mode << 3;
        !           413:        data |= mpscc.priority_select ? MPSCC::CR2_PRIOSEL : 0;
        !           414:        data |= mpscc.intdma_mode;
        !           415: 
        !           416:        return data;
        !           417: }
        !           418: 
        !           419: // CR2B レジスタの内容を取得
        !           420: inline uint8
        !           421: SIODevice::GetCR2B() const
        !           422: {
        !           423:        return mpscc.vector;
        !           424: }
1.1.1.3   root      425: 
1.1.1.9 ! root      426: // SR0 レジスタの内容を取得
        !           427: uint8
        !           428: SIODevice::GetSR0(const MPSCCChan& chan) const
        !           429: {
        !           430:        uint8 data = 0;
        !           431: 
        !           432:        if (chan.break_detected)data |= MPSCC::SR0_BREAK;
        !           433:        if (chan.tx_underrun)   data |= MPSCC::SR0_TXUNDER;
        !           434:        if (chan.nCTS)                  data |= MPSCC::SR0_nCTS;
        !           435:        if (chan.nSYNC)                 data |= MPSCC::SR0_nSYNC;
        !           436:        if (chan.nDCD)                  data |= MPSCC::SR0_nDCD;
        !           437:        if (chan.txlen == 0)    data |= MPSCC::SR0_TXEMPTY;
        !           438:        if (chan.intpend != 0)  data |= MPSCC::SR0_INTPEND;
        !           439:        if (chan.rxlen != 0)    data |= MPSCC::SR0_RXAVAIL;
        !           440: 
        !           441:        return data;
        !           442: }
        !           443: 
        !           444: // CR0 への書き込み
        !           445: void
        !           446: SIODevice::WriteCR0(MPSCCChan& chan, uint32 data)
        !           447: {
        !           448:        // XXX b7,b6 は未対応。
        !           449:        // b5,b4,b3 がコマンド。
        !           450:        // b2,b1,b0 が次にアクセスするレジスタ(chan->ptr)の切り替え。
        !           451:        chan.crc_cmd = (data & MPSCC::CR0_CRC) >> 6;
        !           452:        chan.cmd     = (data & MPSCC::CR0_CMD) >> 3;
        !           453:        chan.ptr     =  data & MPSCC::CR0_PTR;
        !           454: 
        !           455:        if (chan.crc_cmd != 0) {
        !           456:                putlog(0, "%s crc_cmd %d 未実装", CRName(chan, 0), chan.crc_cmd);
        !           457:        }
        !           458: 
        !           459:        if (chan.cmd == 0) {
        !           460:                // コマンド0 ならレジスタ切り替え
        !           461:                putlog(3, "%s <- $%02x (ptr=%d)", CRName(chan, 0), data, chan.ptr);
        !           462:        } else {
        !           463:                // 0 以外ならコマンド発行
        !           464:                putlog(2, "%s <- $%02x", CRName(chan, 0), data);
        !           465:        }
        !           466:        switch (chan.cmd) {
        !           467:         case 0:        // No operation
        !           468:                break;
        !           469:         case 1:        // Send Abort
        !           470:                SendAbort(chan);
        !           471:                break;
        !           472:         case 2:        // Reset External/Status Interrupt
        !           473:                ResetESIntr(chan);
        !           474:                break;
        !           475:         case 3:        // Channel Reset
        !           476:                putlog(1, "Channel %c Reset", chan.name);
        !           477:                ResetChannel(chan);
        !           478:                break;
        !           479:         case 4:        // Enable Interrupt On Next Rx Character
        !           480:                EnableIntrOnNextRx(chan);
        !           481:                break;
        !           482:         case 5:        // Reset Transmitter Interrupt/DMA Pending
        !           483:                ResetTxIntrPending(chan);
        !           484:                break;
        !           485:         case 6:        // Error Reset
        !           486:                ErrorReset(chan);
        !           487:                break;
        !           488:         case 7:        // End of Interrupt
        !           489:                // uPD7201 ではチャンネル A のみ有効。
        !           490:                // (チャンネル B でどうなるかは書いてない)
        !           491:                if (chan.id == 0) {
        !           492:                        ResetHighestIUS(chan);
        !           493:                } else {
        !           494:                        putlog(0, "%s: Command 'End of Interrupt' 未定義", CRName(chan, 0));
        !           495:                }
        !           496:                break;
        !           497:         default:
        !           498:                __unreachable();
        !           499:        }
        !           500: }
        !           501: 
        !           502: // CR1 への書き込み
        !           503: void
        !           504: SIODevice::WriteCR1(MPSCCChan& chan, uint32 data)
        !           505: {
        !           506:        putlog(2, "%s <- $%02x", CRName(chan), data);
        !           507: 
        !           508:        chan.wait_enable = (data & MPSCC::CR1_WAIT_EN);
        !           509:        chan.wait_on_rx  = (data & MPSCC::CR1_WAIT_RX);
        !           510:        // RXINT は内部フォーマットで覚えておく。
        !           511:        // all_or_first の初期値もここでセット。
        !           512:        // o RXINT_DISABLE なら (使わないけど一応) false にしとく。
        !           513:        // o RXINT_1STCHAR なら初期状態が true。
        !           514:        // o RXINT_ALLCHAR なら常時 true。
        !           515:        switch ((data >> 3) & 3) {
        !           516:         case 0:
        !           517:                chan.rxint_mode = MPSCCChan::RXINT_DISABLE;
        !           518:                chan.all_or_first = false;
        !           519:                break;
        !           520:         case 1:
        !           521:                chan.rxint_mode = MPSCCChan::RXINT_1STCHAR;
        !           522:                chan.sp_parity = false;
        !           523:                chan.all_or_first = true;
        !           524:                break;
        !           525:         case 2:
        !           526:                chan.rxint_mode = MPSCCChan::RXINT_ALLCHAR;
        !           527:                chan.sp_parity = false;
        !           528:                chan.all_or_first = true;
        !           529:                break;
1.1.1.3   root      530:         case 3:
1.1.1.9 ! root      531:                chan.rxint_mode = MPSCCChan::RXINT_ALLCHAR;
        !           532:                chan.sp_parity = true;
        !           533:                chan.all_or_first = true;
        !           534:         default:
        !           535:                __unreachable();
1.1.1.3   root      536:        }
1.1.1.9 ! root      537: 
        !           538:        if (chan.id == 0) {
        !           539:                mpscc.sav_vis = (data & MPSCC::CR1_SAV);
        !           540:                // sav を変更したので vis モードを更新
        !           541:                SetVIS();
        !           542:        }
        !           543: 
        !           544:        chan.txint_enable = (data & MPSCC::CR1_TXINT_EN);
        !           545:        chan.esint_enable = (data & MPSCC::CR1_ESINT_EN);
1.1       root      546: }
                    547: 
1.1.1.9 ! root      548: // CR2 への書き込み
1.1       root      549: void
1.1.1.9 ! root      550: SIODevice::WriteCR2(MPSCCChan& chan, uint32 data)
1.1       root      551: {
1.1.1.9 ! root      552:        if (chan.id == 0) {     // CR2A
        !           553:                putlog(2, "%s <- $%02x", CRName(chan), data);
        !           554:                mpscc.syncb                             = (data & MPSCC::CR2_SYNCB);
        !           555:                mpscc.vectored_mode             = (data & MPSCC::CR2_VM);
        !           556:                mpscc.int_mode                  = (data & MPSCC::CR2_INT);
        !           557:                mpscc.priority_select   = (data & MPSCC::CR2_PRIOSEL);
        !           558:                mpscc.intdma_mode               = (data & MPSCC::CR2_INTDMA);
        !           559:                // int_mode を変更したので vis モードを更新
        !           560:                SetVIS();
        !           561:        } else {                        // CR2B
        !           562:                putlog(2, "%s <- $%02x (Set vector)", CRName(chan), data);
        !           563:                mpscc.vector = data;
        !           564:        }
        !           565: }
        !           566: 
        !           567: // CR1 の SAV と CR2 の INT_MODE に従って VIS を更新
        !           568: void
        !           569: SIODevice::SetVIS()
        !           570: {
        !           571:        if (mpscc.sav_vis) {
        !           572:                if (mpscc.int_mode == MPSCC::INTMODE_86) {
        !           573:                        mpscc.vis = MPSCC::VIS_210;
        !           574:                } else {
        !           575:                        mpscc.vis = MPSCC::VIS_432;
        !           576:                }
        !           577:        } else {
        !           578:                mpscc.vis = MPSCC::VIS_FIXED;
        !           579:        }
        !           580: }
        !           581: 
        !           582: // モニター
        !           583: void
        !           584: SIODevice::MonitorUpdate(Monitor *, TextScreen& screen)
        !           585: {
        !           586:        uint cr2a;
        !           587:        uint cr2b;
        !           588:        uint sr2b;
        !           589:        int y;
        !           590: 
        !           591:        cr2a = GetCR2A();
        !           592:        cr2b = mpscc.vector;
        !           593:        sr2b = GetSR2B();
        !           594: 
        !           595:        screen.Clear();
        !           596:        for (int i = 0; i < 2; i++) {
        !           597:                int x = 0;
        !           598:                y = i * 10;
        !           599:                MonitorUpdateCh(screen, i, x, y);
        !           600:        }
        !           601: 
        !           602:        // CR2A
        !           603:        y = 20;
        !           604:        screen.Print(0, y, "CR2A:$%02x", cr2a);
        !           605:        if ((cr2a & MPSCC::CR2_SYNCB)) {
        !           606:                screen.Print(9, y, TA::On, "SYNC");
        !           607:        } else {
        !           608:                screen.Print(9, y, "RTSB");
        !           609:        }
        !           610:        screen.Print(14, y, TA::Disable, "----");
        !           611:        screen.Print(19, y, TA::OnOff((cr2a & MPSCC::CR2_VM)), "Vect");
        !           612:        if ((cr2a & MPSCC::CR2_INT) == 0x10) {
        !           613:                screen.Print(24, y, "IM=V4-V2");
        !           614:        } else {
        !           615:                screen.Print(24, y, "IM=V2-V0");
        !           616:        }
        !           617:        screen.Print(34, y, TA::OnOff((cr2a & MPSCC::CR2_PRIOSEL)), "PRIO");
        !           618:        // bit1,0 はよく分からん
        !           619:        screen.Print(39, y, "INT/DMA=%d", (cr2a & MPSCC::CR2_INTDMA));
        !           620:        y++;
        !           621: 
        !           622:        // CR2B
        !           623:        screen.Print(0, y, "CR2B:$%02x / SR2B:$%02x", cr2b, sr2b);
        !           624: }
        !           625: 
        !           626: // モニター (1チャンネル)
        !           627: void
        !           628: SIODevice::MonitorUpdateCh(TextScreen& screen, int ch, int xbase, int ybase)
        !           629: {
        !           630:        const MPSCCChan& chan = mpscc.chan[ch];
        !           631:        uint cr0;
        !           632:        uint cr1;
        !           633:        uint cr3;
        !           634:        uint cr4;
        !           635:        uint cr5;
        !           636:        uint sr0;
        !           637:        uint sr1;
        !           638:        uint rxlen;
        !           639:        int x;
        !           640:        int y;
        !           641: 
        !           642:        cr0 = GetCR0(chan);
        !           643:        cr1 = GetCR1(chan);
        !           644:        cr3 = GetCR3(chan);
        !           645:        cr4 = chan.cr4;
        !           646:        cr5 = GetCR5(chan);
        !           647:        sr0 = GetSR0(chan);
        !           648:        sr1 = chan.sr1;
        !           649:        rxlen = chan.rxlen;
        !           650: 
        !           651:        // 0         1         2         3         4         5         6
        !           652:        // 0123456789012345678901234567890123456789012345678901234567890123456789
        !           653:        //          0123 0123 0123 0123 0123 0123 0123 0123
        !           654:        // Channel A: Serial Console                          DataAddr  $00000000
        !           655:        // CR0: $xx CRC=x     CMD=x          PTR=x            CtrlAddr  $00000000
        !           656:        // CR1: $xx WE   0    WR   RXInt=x   0    TXEn ESEn
        !           657:        // RXBuf: 0 --- --- ---           Intr: SP Rx ES Tx
        !           658: 
        !           659:        x = xbase;
        !           660:        y = ybase;
        !           661:        screen.Print(x, y++, "Channel %c: %s", chan.name, chan.desc);
        !           662:        screen.Print(x, y++, "CR0: $%02x", cr0);
        !           663:        screen.Print(x, y++, "CR1: $%02x", cr1);
        !           664:        screen.Print(x, y++, "CR3: $%02x", cr3);
        !           665:        screen.Print(x, y++, "CR4: $%02x", cr4);
        !           666:        screen.Print(x, y++, "CR5: $%02x", cr5);
        !           667:        screen.Print(x, y++, "SR0: $%02x", sr0);
        !           668:        screen.Print(x, y++, "SR1: $%02x", sr1);
        !           669:        screen.Print(x, y,   "RXbuf: %d", rxlen);
        !           670:        int i;
        !           671:        for (i = 0; i < rxlen; i++) {
        !           672:                screen.Print(x + 9 + i * 4, y, "$%02x", chan.rxbuf[i]);
        !           673:        }
        !           674:        for (; i < sizeof(chan.rxbuf); i++) {
        !           675:                screen.Print(x + 9 + i * 4, y, "---");
        !           676:        }
        !           677:        // 内部割り込み状態
        !           678:        screen.Print(x + 31, y, "Intr:");
        !           679:        screen.Print(x + 37, y, TA::OnOff(chan.intpend & INTPEND_SP), "SP");
        !           680:        screen.Print(x + 40, y, TA::OnOff(chan.intpend & INTPEND_RX), "Rx");
        !           681:        screen.Print(x + 43, y, TA::OnOff(chan.intpend & INTPEND_ES), "ES");
        !           682:        screen.Print(x + 46, y, TA::OnOff(chan.intpend & INTPEND_TX), "Tx");
        !           683: 
        !           684:        y = ybase + 1;
        !           685:        x = xbase;
        !           686:        // CR0
        !           687:        screen.Print(x + 9, y, "CRC=%d", (cr0 >> 6));
        !           688:        static const char * const cmd_str[] = {
        !           689:        //   0123456789012345
        !           690:                "No operation",
        !           691:                "Send Abort",
        !           692:                "Reset E/S Int",
        !           693:                "Channel Reset",
        !           694:                "Enable IntNextCh",
        !           695:                "Reset TxIntPend",
        !           696:                "Error Reset",
        !           697:                "End of Interrupt",
        !           698:        };
        !           699:        uint cmd = (cr0 >> 3) & 7;
        !           700:        screen.Print(x + 19, y, "CMD=%d(%s)", cmd, cmd_str[cmd]);
        !           701:        screen.Print(x + 43, y, "PTR=%d", (cr0 & 7));
        !           702:        y++;
        !           703: 
        !           704:        // CR1
        !           705:        static const char * const cr1_str[] = {
        !           706:                "Wait", "-", "OnRx", "", "", "SAV", "TxIE", "ESIE"
        !           707:        };
        !           708:        MonitorReg(screen, x + 9, y, cr1, cr1_str);
        !           709:        // XXX All Char 割り込みのうちパリティエラーの扱いは表示省略。
        !           710:        // パリティエラーの扱いが必要になったら考える。
        !           711:        static const char * const rxint_str[] = {
        !           712:        //   012345678
        !           713:                "RxInt=Dis",
        !           714:                "RI=1stChr",
        !           715:                "RI=AllChr",    // Parity Error を Special Condition に含む
        !           716:                "RI=AllChr",    // Parity Error を Special Condition に含まない
        !           717:        };
        !           718:        screen.Puts(x + 24, y, rxint_str[(cr1 >> 3) & 3]);
        !           719:        // CR1 の bit2 (Modified Vector) は CR1B のみ。
        !           720:        if (ch == 0) {
        !           721:                screen.Puts(x + 34, y, TA::Disable, "----");
        !           722:        }
        !           723:        y++;
        !           724: 
        !           725:        // CR3,CR4,CR5
        !           726:        y = MonitorUpdateCR345(screen, x, y, cr3, cr4, cr5);
        !           727: 
        !           728:        // SR0
        !           729:        static const char * const sr0_str[] = {
        !           730:                "BrAb", "TxUn", "!CTS", "!SYN", "!DCD", "TxEm", "IntP", "RxAv"
        !           731:        };
        !           732:        MonitorReg(screen, x + 9, y, sr0, sr0_str);
        !           733:        // SR0 の bit1 (Interrupt Pending) は SR0A のみ。SR0B では 0。
        !           734:        if (ch == 1) {
        !           735:                screen.Print(39, y, TA::Disable, "----");
        !           736:        }
        !           737:        y++;
        !           738: 
        !           739:        // SR1
        !           740:        MonitorUpdateSR1(screen, x, y, sr1);
        !           741:        y++;
        !           742: 
        !           743:        // 右列
        !           744:        y = ybase;
        !           745:        x = xbase + 51;
        !           746:        screen.Print(x, y++, "DataAddr  $%08x", chan.dataaddr);
        !           747:        screen.Print(x, y++, "CtrlAddr  $%08x", chan.ctrladdr);
        !           748:        y++;
        !           749:        screen.Print(x, y++, "Param  %12s", GetParamStr(chan).c_str());
        !           750:        screen.Print(x, y++, "Rx Bits/Frame    %2d", chan.rxbits);
        !           751:        screen.Print(x, y++, "Tx Bits/Frame    %2d", chan.txbits);
        !           752: }
        !           753: 
        !           754: // ペンディングのうち最も優先度の高い割り込み要因を返す
        !           755: uint
        !           756: SIODevice::GetHighestInt() const
        !           757: {
        !           758:        // 優先度は CR2A b2 (priority_select) で決まるが、
        !           759:        // Int/DMA が %01 なら priority_select によらず 0 と同じほうになるという
        !           760:        // ことのようだ。
        !           761:        //
        !           762:        //        CR2 b210      High -> Low
        !           763:        // uPD7201      0 0 0   RxA TxA RxB TxB ESA ESB
        !           764:        // uPD7201  x 0 1       RxA TxA RxB TxB ESA ESB
        !           765:        // uPD7201  0 1 0       RxA TxA RxB TxB ESA ESB
        !           766:        //
        !           767:        // uPD7201  1 0 0       RxA RxB TxA TxB ESA ESB
        !           768:        // uPD7201  1 1 0       RxA RxB TxA TxB ESA ESB
        !           769: 
        !           770:        if (mpscc.intdma_mode == 1 || mpscc.priority_select == false) {
        !           771:                if ((mpscc.chan[0].intpend & INTPEND_SP)) return MPSCC::VS_SPA;
        !           772:                if ((mpscc.chan[0].intpend & INTPEND_RX)) return MPSCC::VS_RxA;
        !           773:                if ((mpscc.chan[0].intpend & INTPEND_TX)) return MPSCC::VS_TxA;
        !           774:                if ((mpscc.chan[1].intpend & INTPEND_SP)) return MPSCC::VS_SPB;
        !           775:                if ((mpscc.chan[1].intpend & INTPEND_RX)) return MPSCC::VS_RxB;
        !           776:                if ((mpscc.chan[1].intpend & INTPEND_TX)) return MPSCC::VS_TxB;
        !           777:                if ((mpscc.chan[0].intpend & INTPEND_ES)) return MPSCC::VS_ESA;
        !           778:                if ((mpscc.chan[1].intpend & INTPEND_ES)) return MPSCC::VS_ESB;
        !           779: 
        !           780:        } else {
        !           781:                if ((mpscc.chan[0].intpend & INTPEND_SP)) return MPSCC::VS_SPA;
        !           782:                if ((mpscc.chan[0].intpend & INTPEND_RX)) return MPSCC::VS_RxA;
        !           783:                if ((mpscc.chan[1].intpend & INTPEND_SP)) return MPSCC::VS_SPB;
        !           784:                if ((mpscc.chan[1].intpend & INTPEND_RX)) return MPSCC::VS_RxB;
        !           785:                if ((mpscc.chan[0].intpend & INTPEND_TX)) return MPSCC::VS_TxA;
        !           786:                if ((mpscc.chan[1].intpend & INTPEND_TX)) return MPSCC::VS_TxB;
        !           787:                if ((mpscc.chan[0].intpend & INTPEND_ES)) return MPSCC::VS_ESA;
        !           788:                if ((mpscc.chan[1].intpend & INTPEND_ES)) return MPSCC::VS_ESB;
        !           789:        }
        !           790: 
        !           791:        return MPSCC::VS_none;
1.1       root      792: }
1.1.1.8   root      793: 
                    794: void
                    795: SIODevice::Tx(int ch, uint32 data)
                    796: {
                    797:        switch (ch) {
                    798:         case 0:
1.1.1.9 ! root      799:                hostcom->Tx(data);
1.1.1.8   root      800:                break;
                    801:         case 1:
                    802:                gKeyboard->Command(data);
                    803:                break;
                    804:         default:
                    805:                __unreachable();
                    806:        }
                    807: }
1.1.1.9 ! root      808: 
        !           809: // ログ表示用のレジスタ名
        !           810: /*static*/ const char * const
        !           811: SIODevice::crnames[16] = {
        !           812:        "CR0A",         "CR0B",
        !           813:        "CR1A",         "CR1B",
        !           814:        "CR2A",         "CR2B",
        !           815:        "CR3A",         "CR3B",
        !           816:        "CR4A",         "CR4B",
        !           817:        "CR5A",         "CR5B",
        !           818:        "CR6A",         "CR6B",
        !           819:        "CR7A",         "CR7B",
        !           820: };
        !           821: /*static*/ const char * const
        !           822: SIODevice::srnames[16] = {
        !           823:        "SR0A",         "SR0B",
        !           824:        "SR1A",         "SR1B",
        !           825:        "SR2A?",        "SR2B",
        !           826:        "SR3A?",        "SR3B?",
        !           827:        "SR4A?",        "SR4B?",
        !           828:        "SR5A?",        "SR5B?",
        !           829:        "SR6A?",        "SR6B?",
        !           830:        "SR7A?",        "SR7B?",
        !           831: };

unix.superglobalmegacorp.com

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