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

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

unix.superglobalmegacorp.com

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