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

1.1       root        1: //
                      2: // nono
                      3: // Copyright (C) 2020 nono project
                      4: // Licensed under nono-license.txt
                      5: //
                      6: 
                      7: //
                      8: // uPD7201(MPSC) と Z8530(SCC) の共通部分 (シリアルポート1個つき)
                      9: //
                     10: 
                     11: // IODevice
                     12: //    |
                     13: //    |  +-------------+
                     14: //    +--| MPSCCDevice | (uPD7201 と Z8530 の共通部分)
                     15: //       +-------------+
                     16: //          |
                     17: //          +-- SCCDevice (X68030、Z8530)
                     18: //          +-- SIODevice (LUNA、uPD7201)
                     19: 
                     20: #define MPSCC_SIO_LOG_HACK
                     21: #include "mpscc.h"
                     22: #include "bitops.h"
                     23: #include "hostcom.h"
                     24: #include "interrupt.h"
                     25: #include "scheduler.h"
                     26: #include "sync.h"
1.1.1.2 ! root       27: #include <cmath>
1.1       root       28: 
                     29: //
                     30: // MPSCC チャンネル
                     31: //
                     32: 
                     33: // コンストラクタ
                     34: MPSCCChan::MPSCCChan()
                     35: {
1.1.1.2 ! root       36:        // これらのレジスタの値の初期値は実際は不定だがそれは実際難しいのと
        !            37:        // 有効範囲内の値にしておく必要があるので、適当に初期値を固定しておく。
        !            38:        rxbits = 5;
        !            39:        txbits = 5;
        !            40:        clkrate = 1;
1.1       root       41: }
                     42: 
                     43: // デストラクタ
                     44: MPSCCChan::~MPSCCChan()
                     45: {
                     46: }
                     47: 
                     48: // 初期化
                     49: void
                     50: MPSCCChan::Init(int id_)
                     51: {
                     52:        id = id_;
                     53:        name = 'A' + id;
                     54: }
                     55: 
                     56: 
                     57: //
                     58: // MPSCC デバイス
                     59: //
                     60: 
                     61: // コンストラクタ
                     62: MPSCCDevice::MPSCCDevice(const std::string& objname_)
                     63:        : inherited(objname_)
                     64: {
                     65:        for (int ch = 0; ch < mpscc.chan.size(); ch++) {
                     66:                auto& chan = mpscc.chan[ch];
                     67:                chan.Init(ch);
                     68: 
                     69:                // time は SetTxPeriod() でセット。
                     70:                // 名前は継承先でセットする。機種ごとに名前を使い分けているため。
                     71:                txevent[ch].dev = this;
                     72:                txevent[ch].func = ToEventCallback(&MPSCCDevice::TxCallback);
                     73:                txevent[ch].code = ch;
                     74:                txevent[ch].Regist();
                     75: 
                     76:                rxevent[ch].dev = this;
                     77:                rxevent[ch].func = ToEventCallback(&MPSCCDevice::RxCallback);
                     78:                rxevent[ch].code = ch;
                     79:                rxevent[ch].Regist();
                     80:        }
                     81: 
                     82:        // モニタは継承先で設定する
                     83: }
                     84: 
                     85: // デストラクタ
                     86: MPSCCDevice::~MPSCCDevice()
                     87: {
                     88:        if ((bool)hostcom) {
                     89:                hostcom->SetCallbackDevice(NULL);
                     90:        }
                     91: }
                     92: 
                     93: bool
                     94: MPSCCDevice::Create()
                     95: {
                     96:        // 対応するホストドライバを作成
                     97:        try {
                     98:                hostcom.reset(new HostCOMDevice("HostCOM"));
                     99:        } catch (...) {
                    100:                return false;
                    101:        }
                    102: 
                    103:        hostcom->SetRxCallback(ToDeviceCallback(&MPSCCDevice::HostRxCallback));
                    104:        hostcom->SetCallbackDevice(this);
                    105: 
                    106:        return true;
                    107: }
                    108: 
                    109: void
                    110: MPSCCDevice::SetLogLevel(int loglevel_)
                    111: {
                    112:        inherited::SetLogLevel(loglevel_);
                    113: 
                    114:        assert((bool)hostcom);
                    115:        hostcom->SetLogLevel(loglevel_);
                    116: }
                    117: 
                    118: // 初期化
                    119: bool
                    120: MPSCCDevice::Init()
                    121: {
                    122:        gScheduler->ConnectMessage(MessageID::HOSTCOM_RX, this,
                    123:                ToMessageCallback(&MPSCCDevice::RxMessageCallback));
                    124:        return true;
                    125: }
                    126: 
                    127: // チャンネルリセットの共通部
                    128: void
                    129: MPSCCDevice::ResetChannelCommon(MPSCCChan& chan)
                    130: {
                    131:        // 通信速度を反映する
1.1.1.2 ! root      132:        ChangeBaudrate(chan);
1.1       root      133:        SetTxPeriod(chan);
                    134:        SetRxPeriod(chan);
                    135: 
1.1.1.2 ! root      136:        // Set(Tx|Rx)Period() 呼び出し後は old_cr[345] を更新。
        !           137:        chan.old_cr3 = GetCR3(chan);
        !           138:        chan.old_cr4 = GetCR4(chan);
        !           139:        chan.old_cr5 = GetCR5(chan);
        !           140: 
1.1       root      141:        // リセットで送信バッファは空になるが、リセット直後に
                    142:        // Tx 割り込みを許可しても Tx 割り込みは起こさない。
                    143:        chan.txint_ready = false;
                    144: 
                    145:        // 割り込みをネゲートするため
                    146:        ChangeInterrupt();
                    147: }
                    148: 
                    149: // CR0/WR0 レジスタの内容を取得
                    150: // (値の取り出しだけなら共通)
1.1.1.2 ! root      151: /*static*/ uint8
        !           152: MPSCCDevice::GetCR0(const MPSCCChan& chan)
1.1       root      153: {
                    154:        uint8 data = (chan.crc_cmd << 6) | (chan.cmd << 3) | chan.ptr;
                    155:        return data;
                    156: }
                    157: 
1.1.1.2 ! root      158: // CR3/WR3 レジスタを設定
        !           159: /*static*/ void
        !           160: MPSCCDevice::SetCR3(MPSCCChan& chan, uint32 data)
        !           161: {
        !           162:        switch (data & MPSCC::CR3_RXBITS) {
        !           163:         case MPSCC::RXBITS_5:
        !           164:                chan.rxbits = 5;
        !           165:                break;
        !           166:         case MPSCC::RXBITS_6:
        !           167:                chan.rxbits = 6;
        !           168:                break;
        !           169:         case MPSCC::RXBITS_7:
        !           170:                chan.rxbits = 7;
        !           171:                break;
        !           172:         case MPSCC::RXBITS_8:
        !           173:                chan.rxbits = 8;
        !           174:                break;
        !           175:         default:
        !           176:                __unreachable();
        !           177:        }
        !           178: 
        !           179:        chan.auto_enable = (data & MPSCC::CR3_AUTO_EN);
        !           180:        chan.cr3_sync    = (data & MPSCC::CR3_SYNC_MASK);
        !           181:        chan.rx_enable   = (data & MPSCC::CR3_RX_EN);
        !           182: }
        !           183: 
1.1       root      184: // CR3/WR3 レジスタの内容を取得
1.1.1.2 ! root      185: /*static*/ uint8
        !           186: MPSCCDevice::GetCR3(const MPSCCChan& chan)
1.1       root      187: {
                    188:        uint8 data;
                    189: 
1.1.1.2 ! root      190:        data = chan.cr3_sync;
        !           191:        switch (chan.rxbits) {
        !           192:         case 5:
        !           193:                data |= MPSCC::RXBITS_5;
        !           194:                break;
        !           195:         case 6:
        !           196:                data |= MPSCC::RXBITS_6;
        !           197:                break;
        !           198:         case 7:
        !           199:                data |= MPSCC::RXBITS_7;
        !           200:                break;
        !           201:         case 8:
        !           202:                data |= MPSCC::RXBITS_8;
        !           203:                break;
        !           204:         default:
        !           205:                __unreachable();
        !           206:        }
        !           207:        if (chan.auto_enable) {
        !           208:                data |= MPSCC::CR3_AUTO_EN;
        !           209:        }
        !           210:        if (chan.rx_enable) {
1.1       root      211:                data |= MPSCC::CR3_RX_EN;
1.1.1.2 ! root      212:        }
        !           213:        return data;
        !           214: }
1.1       root      215: 
1.1.1.2 ! root      216: // CR4/WR4 レジスタを設定
        !           217: /*static*/void
        !           218: MPSCCDevice::SetCR4(MPSCCChan& chan, uint32 data)
        !           219: {
        !           220:        switch (data & MPSCC::CR4_CLKRATE) {
        !           221:         case MPSCC::CLKRATE_1:
        !           222:                chan.clkrate = 1;
        !           223:                break;
        !           224:         case MPSCC::CLKRATE_16:
        !           225:                chan.clkrate = 16;
        !           226:                break;
        !           227:         case MPSCC::CLKRATE_32:
        !           228:                chan.clkrate = 32;
        !           229:                break;
        !           230:         case MPSCC::CLKRATE_64:
        !           231:                chan.clkrate = 64;
        !           232:                break;
        !           233:         default:
        !           234:                __unreachable();
        !           235:        }
        !           236:        chan.syncmode = (data & MPSCC::CR4_SYNCMODE);
        !           237:        chan.stopbits = (data & MPSCC::CR4_STOPBITS) >> 2;
        !           238:        chan.parity_even   = (data & MPSCC::CR4_PARITY_EVEN);
        !           239:        chan.parity_enable = (data & MPSCC::CR4_PARITY_EN) ? 1 : 0;
        !           240: }
        !           241: 
        !           242: // CR4/WR4 レジスタの内容を取得
        !           243: /*static*/ uint8
        !           244: MPSCCDevice::GetCR4(const MPSCCChan& chan)
        !           245: {
        !           246:        uint8 data = 0;
        !           247: 
        !           248:        switch (chan.clkrate) {
        !           249:         case 1:
        !           250:                data |= MPSCC::CLKRATE_1;
        !           251:                break;
        !           252:         case 16:
        !           253:                data |= MPSCC::CLKRATE_16;
        !           254:                break;
        !           255:         case 32:
        !           256:                data |= MPSCC::CLKRATE_32;
        !           257:                break;
        !           258:         case 64:
        !           259:                data |= MPSCC::CLKRATE_64;
        !           260:                break;
        !           261:         default:
        !           262:                __unreachable();
        !           263:        }
        !           264:        data |= chan.syncmode;
        !           265:        data |= chan.stopbits << 2;
        !           266:        if (chan.parity_even) {
        !           267:                data |= MPSCC::CR4_PARITY_EVEN;
        !           268:        }
        !           269:        if (chan.parity_enable) {
        !           270:                data |= MPSCC::CR4_PARITY_EN;
        !           271:        }
1.1       root      272:        return data;
                    273: }
                    274: 
1.1.1.2 ! root      275: // CR5/WR5 レジスタを設定
        !           276: /*static*/ void
        !           277: MPSCCDevice::SetCR5(MPSCCChan& chan, uint32 data)
        !           278: {
        !           279:        switch (data & MPSCC::CR5_TXBITS) {
        !           280:         case MPSCC::TXBITS_5:
        !           281:                chan.txbits = 5;
        !           282:                break;
        !           283:         case MPSCC::TXBITS_6:
        !           284:                chan.txbits = 6;
        !           285:                break;
        !           286:         case MPSCC::TXBITS_7:
        !           287:                chan.txbits = 7;
        !           288:                break;
        !           289:         case MPSCC::TXBITS_8:
        !           290:                chan.txbits = 8;
        !           291:                break;
        !           292:         default:
        !           293:                __unreachable();
        !           294:        }
        !           295:        chan.nDTR      = (data & MPSCC::CR5_nDTR);
        !           296:        chan.sendbreak = (data & MPSCC::CR5_SENDBREAK);
        !           297:        chan.tx_enable = (data & MPSCC::CR5_TX_EN);
        !           298:        chan.crc16     = (data & MPSCC::CR5_CRC16);
        !           299:        chan.nRTS      = (data & MPSCC::CR5_nRTS);
        !           300:        chan.txcrc_en  = (data & MPSCC::CR5_TXCRC_EN);
        !           301: }
        !           302: 
1.1       root      303: // CR5/WR5 レジスタの内容を取得
1.1.1.2 ! root      304: /*static*/ uint8
        !           305: MPSCCDevice::GetCR5(const MPSCCChan& chan)
1.1       root      306: {
1.1.1.2 ! root      307:        uint8 data = 0;
1.1       root      308: 
1.1.1.2 ! root      309:        switch (chan.txbits) {
        !           310:         case 5:
        !           311:                data |= MPSCC::TXBITS_5;
        !           312:                break;
        !           313:         case 6:
        !           314:                data |= MPSCC::TXBITS_6;
        !           315:                break;
        !           316:         case 7:
        !           317:                data |= MPSCC::TXBITS_7;
        !           318:                break;
        !           319:         case 8:
        !           320:                data |= MPSCC::TXBITS_8;
        !           321:                break;
        !           322:         default:
        !           323:                __unreachable();
        !           324:        }
        !           325:        if (chan.nDTR) {
        !           326:                data |= MPSCC::CR5_nDTR;
        !           327:        }
        !           328:        if (chan.sendbreak) {
        !           329:                data |= MPSCC::CR5_SENDBREAK;
        !           330:        }
        !           331:        if (chan.tx_enable) {
1.1       root      332:                data |= MPSCC::CR5_TX_EN;
1.1.1.2 ! root      333:        }
        !           334:        if (chan.crc16) {
        !           335:                data |= MPSCC::CR5_CRC16;
        !           336:        }
        !           337:        if (chan.nRTS) {
        !           338:                data |= MPSCC::CR5_nRTS;
        !           339:        }
        !           340:        if (chan.txcrc_en) {
        !           341:                data |= MPSCC::CR5_TXCRC_EN;
        !           342:        }
1.1       root      343:        return data;
                    344: }
                    345: 
                    346: // SR2B/RR2B レジスタの内容を取得
                    347: uint8
                    348: MPSCCDevice::GetSR2B() const
                    349: {
                    350:        uint8 data = mpscc.vector;
                    351: 
                    352:        // 割り込み要因をベクタに載せない
                    353:        if (mpscc.vis == MPSCC::VIS_FIXED) {
                    354:                return data;
                    355:        }
                    356: 
                    357:        uint stat = GetHighestInt();
                    358: 
                    359:        // 8種類 (3bit) の割り込み要因をベクタに載せる。
                    360:        // 載せる場所 (と向き) はそれぞれ 2種類ずつある。
                    361:        switch (mpscc.vis) {
                    362:         case MPSCC::VIS_432:           // uPD7201: INTMode = INT85
                    363:                // 割り込み要求がない場合は %111
                    364:                if (stat == MPSCC::VS_none)
                    365:                        stat = 7;
                    366:                data &= ~0x1c;
                    367:                data |= stat << 2;
                    368:                break;
                    369: 
                    370:         case MPSCC::VIS_210:           // uPD7201: INTMode = INT86
                    371:                // 割り込み要求がない場合は %111
                    372:                if (stat == MPSCC::VS_none)
                    373:                        stat = 7;
                    374:                data &= ~0x07;
                    375:                data |= stat;
                    376:                break;
                    377: 
                    378:         case MPSCC::VIS_321:           // Z8530: StatusHigh/StatusLow = %0
                    379:                // 割り込み要求がない場合は %011
                    380:                if (stat == MPSCC::VS_none)
                    381:                        stat = 3;
                    382:                data &= ~0x0e;
                    383:                data |= stat << 1;
                    384:                break;
                    385: 
                    386:         case MPSCC::VIS_456:           // Z8530: StatusHigh/StatusLow = %1
                    387:                // 割り込み要求がない場合は %011
                    388:                if (stat == MPSCC::VS_none)
                    389:                        stat = 3;
                    390:                // VIS_321 とはビット順が逆
                    391:                data &= ~0x70;
                    392:                data |= bitrev(stat << 1);
                    393:                break;
                    394:         default:
                    395:                __unreachable();
                    396:        }
                    397: 
                    398:        return data;
                    399: }
                    400: 
                    401: // CR0/WR0 Send Abort コマンド
                    402: void
                    403: MPSCCDevice::SendAbort(MPSCCChan& chan)
                    404: {
1.1.1.2 ! root      405:        putlog(0, "%s: Command 'Send Abort' (NOT IMPLEMENTED)", CRName(chan, 0));
1.1       root      406: }
                    407: 
                    408: // CR0/WR0 Reset External/Status Interrupt コマンド
                    409: void
                    410: MPSCCDevice::ResetESIntr(MPSCCChan& chan)
                    411: {
                    412:        putlog(3, "%s: Command 'Reset E/S Interrupt'", CRName(chan, 0));
                    413:        chan.es_latched = false;
                    414: }
                    415: 
                    416: // CR0/WR0 Enable Interrupt on Next Rx Character コマンド
                    417: void
                    418: MPSCCDevice::EnableIntrOnNextRx(MPSCCChan& chan)
                    419: {
                    420:        putlog(1, "%s: Command 'Enable Intr on Next Rx Character'",
                    421:                CRName(chan, 0));
                    422:        chan.all_or_first = true;
                    423: }
                    424: 
                    425: // CR0/WR0 Reset Tx Interrupt/DMA Pending コマンド
                    426: void
                    427: MPSCCDevice::ResetTxIntrPending(MPSCCChan& chan)
                    428: {
                    429:        putlog(2, "%s: Command 'Reset Tx Intr/DMA Pending'", CRName(chan, 0));
                    430:        chan.txint_ready = false;
                    431:        ChangeInterrupt();
                    432: }
                    433: 
                    434: // CR0/WR0 Error Reset コマンド
                    435: void
                    436: MPSCCDevice::ErrorReset(MPSCCChan& chan)
                    437: {
                    438:        putlog(1, "%s: Command 'Error Reset'", CRName(chan, 0));
                    439:        chan.sr1 &= ~(MPSCC::SR1_ENDOFFRAME |
                    440:                      MPSCC::SR1_FRAMEERROR |
                    441:                      MPSCC::SR1_RXOVERRUN  |
                    442:                      MPSCC::SR1_PARITYERROR);
                    443:        // XXX Special Rx Condition は未実装
                    444: }
                    445: 
                    446: // CR0 End of Interrupt コマンド
                    447: // WR0 Reset Highest IUS コマンド
                    448: // たぶん名前が違うだけで同じ。後者のほうが分かりやすいのでこっちを使う
                    449: void
                    450: MPSCCDevice::ResetHighestIUS(MPSCCChan& chan)
                    451: {
                    452:        putlog(2, "%s: Command 'Reset Highest IUS'", CRName(chan, 0));
                    453: 
                    454:        // ペンディングのうち最も高い割り込み要因をクリア
                    455:        uint stat = GetHighestInt();
                    456:        switch (stat) {
                    457:         case MPSCC::VS_TxB:
                    458:                mpscc.chan[1].intpend &= ~INTPEND_TX;
                    459:                break;
                    460:         case MPSCC::VS_ESB:
                    461:                mpscc.chan[1].intpend &= ~INTPEND_ES;
                    462:                break;
                    463:         case MPSCC::VS_RxB:
                    464:                mpscc.chan[1].intpend &= ~INTPEND_RX;
                    465:                break;
                    466:         case MPSCC::VS_SPB:
                    467:                mpscc.chan[1].intpend &= ~INTPEND_SP;
                    468:                break;
                    469: 
                    470:         case MPSCC::VS_TxA:
                    471:                mpscc.chan[0].intpend &= ~INTPEND_TX;
                    472:                break;
                    473:         case MPSCC::VS_ESA:
                    474:                mpscc.chan[0].intpend &= ~INTPEND_ES;
                    475:                break;
                    476:         case MPSCC::VS_RxA:
                    477:                mpscc.chan[0].intpend &= ~INTPEND_RX;
                    478:                break;
                    479:         case MPSCC::VS_SPA:
                    480:                mpscc.chan[0].intpend &= ~INTPEND_SP;
                    481:                break;
                    482: 
                    483:         default:
                    484:                break;
                    485:        }
                    486:        ChangeInterrupt();
                    487: }
                    488: 
                    489: // CR3/WR3 への書き込み
                    490: void
                    491: MPSCCDevice::WriteCR3(MPSCCChan& chan, uint32 data)
                    492: {
1.1.1.2 ! root      493:        SetCR3(chan, data);
1.1       root      494:        putlog(2, "%s <- $%02x", CRName(chan), data);
                    495: 
                    496:        SetRxPeriod(chan);
1.1.1.2 ! root      497: 
        !           498:        // Set(Tx|Rx)Period() 呼び出し後は old_cr[345] を更新。
        !           499:        chan.old_cr3 = GetCR3(chan);
1.1       root      500: }
                    501: 
                    502: // CR4/WR4 への書き込み
                    503: void
                    504: MPSCCDevice::WriteCR4(MPSCCChan& chan, uint32 data)
                    505: {
1.1.1.2 ! root      506:        SetCR4(chan, data);
1.1       root      507:        putlog(2, "%s <- $%02x", CRName(chan), data);
                    508: 
1.1.1.2 ! root      509:        if (chan.stopbits == MPSCC::STOPBITS_SYNC) {
1.1       root      510:                // 同期モードはサポートしない
                    511:                putlog(2, "Channel %c Synchronous mode not supported", chan.name);
                    512:        } else {
                    513:                const char *sm[] = { "?", "1", "1.5", "2" };
                    514:                putlog(2, "Channel %c Async Mode (x%d clock, stopbit %s)",
                    515:                        chan.name,
1.1.1.2 ! root      516:                        chan.clkrate,
        !           517:                        sm[chan.stopbits]);
        !           518:                // なんとなく順序的に何倍と表示した後に速度を表示
        !           519:                ChangeBaudrate(chan);
1.1       root      520:        }
                    521: 
                    522:        SetTxPeriod(chan);
                    523:        SetRxPeriod(chan);
1.1.1.2 ! root      524: 
        !           525:        // Set(Tx|Rx)Period() 呼び出し後は old_cr[345] を更新。
        !           526:        chan.old_cr4 = GetCR4(chan);
1.1       root      527: }
                    528: 
                    529: // CR5/WR5 への書き込み
                    530: void
                    531: MPSCCDevice::WriteCR5(MPSCCChan& chan, uint32 data)
                    532: {
1.1.1.2 ! root      533:        SetCR5(chan, data);
1.1       root      534:        putlog(2, "%s <- $%02x", CRName(chan), data);
                    535: 
                    536:        SetTxPeriod(chan);
1.1.1.2 ! root      537:        // Set(Tx|Rx)Period() 呼び出し後は old_cr[345] を更新。
        !           538:        chan.old_cr5 = GetCR5(chan);
        !           539: 
1.1       root      540:        TrySend(chan);
                    541: }
                    542: 
                    543: // CR6/WR6 への書き込み
                    544: void
                    545: MPSCCDevice::WriteCR6(MPSCCChan& chan, uint32 data)
                    546: {
                    547:        chan.cr6 = data;
                    548: 
1.1.1.2 ! root      549:        // どのみちサポートしてないけど初期化のために 0x00 を書き込むようなので
        !           550:        // それ以外ならログを出す。
        !           551:        if (data != 0) {
        !           552:                putlog(0, "Write %s <- $%02x (NOT IMPLEMENTED)", CRName(chan), data);
        !           553:        }
1.1       root      554: }
                    555: 
                    556: // CR7/WR7 への書き込み
                    557: void
                    558: MPSCCDevice::WriteCR7(MPSCCChan& chan, uint32 data)
                    559: {
                    560:        chan.cr7 = data;
                    561: 
1.1.1.2 ! root      562:        // どのみちサポートしてないけど初期化のために 0x00 を書き込むようなので
        !           563:        // それ以外ならログを出す。
        !           564:        if (data != 0) {
        !           565:                putlog(0, "Write %s <- $%02x (NOT IMPLEMENTED)", CRName(chan), data);
        !           566:        }
1.1       root      567: }
                    568: 
                    569: // データポートの読み込み
                    570: uint8
                    571: MPSCCDevice::ReadData(MPSCCChan& chan)
                    572: {
                    573:        uint8 data;
                    574: 
                    575:        // 受信バッファが空でも直近のデータが読めるので常に [0] でよい
                    576:        data = chan.rxbuf[0];
                    577:        if (chan.rxlen > 0) {
                    578:                putlog(3, "Ch%c Data -> $%02x", chan.name, data);
                    579:                chan.rxlen--;
                    580:                if (chan.rxlen == 0) {
                    581:                        // 取り出して空になった
                    582:                        ChangeInterrupt();
                    583:                } else {
                    584:                        chan.rxbuf[0] = chan.rxbuf[1];
                    585:                        chan.rxbuf[1] = chan.rxbuf[2];
                    586:                }
                    587:        } else {
                    588:                putlog(3, "Ch%c Data -> $%02x (Empty)", chan.name, data);
                    589:        }
                    590: 
                    591:        return data;
                    592: }
                    593: 
                    594: // データポートの書き込み
                    595: void
                    596: MPSCCDevice::WriteData(MPSCCChan& chan, uint32 data)
                    597: {
                    598:        char charbuf[4];
                    599: 
                    600:        if (isprint((int)data)) {
                    601:                snprintf(charbuf, sizeof(charbuf), "'%c'", data);
                    602:        } else {
                    603:                charbuf[0] = '\0';
                    604:        }
                    605:        putlog(3, "Ch%c Data <- $%02x %s", chan.name, data, charbuf);
                    606: 
                    607:        // XXX: EMPTY でないときにデータを書いたらどうなるかは未定義
                    608: 
                    609:        // 1byte の TX Buffer
                    610:        chan.txlen = 1;
                    611:        chan.txbuf = data;
                    612: 
                    613:        // データ書き込み後に Empty になったら割り込みを上げるため
                    614:        // ここで ready をセット
                    615:        chan.txint_ready = true;
                    616: 
                    617:        TrySend(chan);
                    618: }
                    619: 
                    620: // データポートの Peek
                    621: uint8
                    622: MPSCCDevice::PeekData(const MPSCCChan &chan) const
                    623: {
                    624:        // 受信バッファにデータがあれば先頭バイトが見える。
                    625:        // 受信バッファが空でも直近に取り出したバイトがそのまま見える。
                    626:        return chan.rxbuf[0];
                    627: }
                    628: 
                    629: // 送信できるか調べて送信する
                    630: void
                    631: MPSCCDevice::TrySend(MPSCCChan& chan)
                    632: {
                    633:        // 送信可で送信バッファにデータがあって送信中でなければ
                    634:        if (chan.tx_enable && chan.txlen && !txevent[chan.id].IsRunning()) {
                    635:                // 送信する
                    636:                chan.tx_shiftreg = chan.txbuf;
                    637:                chan.txlen = 0;
                    638:                gScheduler->StartEvent(txevent[chan.id]);
                    639:                putlog(2, "Ch%c send $%02x", chan.name, chan.tx_shiftreg);
                    640: 
                    641:                // XXX たぶん送信してから割り込みを上げるまでにいくらか遅れがあるはず
                    642:        }
                    643: 
                    644:        // ネゲートされることがあるので、送信しなくても割り込み状態を更新する
                    645:        ChangeInterrupt();
                    646: }
                    647: 
                    648: // 送信のイベントコールバック
                    649: void
                    650: MPSCCDevice::TxCallback(Event& event)
                    651: {
                    652:        int ch = event.code;
                    653:        MPSCCChan& chan = mpscc.chan[ch];
                    654: 
                    655:        // 接続デバイスの呼び出し
                    656:        Tx(ch, chan.tx_shiftreg);
                    657: 
                    658:        // 次の送信データが来てたら送信
                    659:        TrySend(chan);
                    660: }
                    661: 
                    662: // ホストスレッドからの受信通知
                    663: // (HostCOM スレッドで呼ばれる)
                    664: void
                    665: MPSCCDevice::HostRxCallback()
                    666: {
                    667:        // スレッドを超えるためにメッセージを投げる
                    668:        gScheduler->SendMessage(MessageID::HOSTCOM_RX);
                    669: }
                    670: 
                    671: // 1バイト受信する。
                    672: // 受理されれば true を返す。
                    673: bool
                    674: MPSCCDevice::Rx(int ch, uint32 data)
                    675: {
                    676:        MPSCCChan& chan = mpscc.chan[ch];
                    677: 
                    678:        // Rx Enable でなければ受け取らない?
                    679:        if (chan.rx_enable == false) {
                    680:                return false;
                    681:        }
                    682: 
                    683:        // バッファが一杯なら Rx Overrun Error
                    684:        if (chan.rxlen == sizeof(chan.rxbuf)) {
                    685:                putlog(2, "Ch%c Rx Overrun", chan.name);
                    686:                chan.sr1 |= MPSCC::SR1_RXOVERRUN;
                    687:                // XXX special Rx condition interrupt occurs
                    688:                return false;
                    689:        }
                    690: 
                    691:        // 受信
                    692:        putlog(2, "Ch%c recv $%02x", chan.name, data);
                    693:        chan.rxbuf[chan.rxlen++] = data;
                    694: 
                    695:        // 割り込み状態を変更
                    696:        ChangeInterrupt();
                    697: 
                    698:        return true;
                    699: }
                    700: 
                    701: // ホストシリアルからの1バイト受信メッセージ
                    702: void
                    703: MPSCCDevice::RxMessageCallback(MessageID msgid, uint32 arg)
                    704: {
                    705:        Event& ev = rxevent[COM_CH];
                    706: 
                    707:        // 受信ループが止まっていれば開始
                    708:        if (ev.IsRunning() == false) {
                    709:                gScheduler->StartEvent(ev);
                    710:        }
                    711: }
                    712: 
                    713: // 受信イベントコールバック
                    714: void
                    715: MPSCCDevice::RxCallback(Event& ev)
                    716: {
                    717:        int ch = ev.code;
                    718:        int data;
                    719: 
                    720:        // ホストキューにあるだけ取り出す
                    721:        data = hostcom->Rx();
                    722:        if (data >= 0) {
                    723:                Rx(ch, data);
                    724: 
                    725:                gScheduler->StartEvent(ev);
                    726:        }
                    727: }
                    728: 
                    729: static double
                    730: to_freq(uint64 nsec)
                    731: {
                    732:        return (double)1.0 / nsec * 1e9;
                    733: }
                    734: 
1.1.1.2 ! root      735: // ボーレートを再計算する。
        !           736: // CR4(ClkRate) と xc12_ns の変更で呼ぶこと。
        !           737: void
        !           738: MPSCCDevice::ChangeBaudrate(MPSCCChan& chan)
1.1       root      739: {
1.1.1.2 ! root      740:        double old_baudrate = chan.baudrate;
1.1       root      741: 
1.1.1.2 ! root      742:        // 誤差を減らすため 12bit 分の時間を基準とする。
        !           743:        chan.bit12_ns = chan.xc12_ns * chan.clkrate;
        !           744:        chan.baudrate = (double)to_freq(chan.bit12_ns) * 12;
1.1       root      745: 
1.1.1.2 ! root      746:        if (loglevel >= 3) {
        !           747:                if (chan.baudrate != old_baudrate) {
        !           748:                        putlogn("Channel %c Baudrate %.1f", chan.name, chan.baudrate);
        !           749:                }
        !           750:        }
        !           751: }
        !           752: 
        !           753: // スタートビット、ストップビット、パリティビットの総数を返す。
        !           754: // enable はサポートしていないモードの時にログを出すため。
        !           755: int
        !           756: MPSCCDevice::AdditionalBits(MPSCCChan& chan, bool enable)
        !           757: {
        !           758:        int bit;
1.1       root      759: 
                    760:        // start bit
1.1.1.2 ! root      761:        bit = 1;
1.1       root      762: 
                    763:        // parity bit
1.1.1.2 ! root      764:        bit += chan.parity_enable;
1.1       root      765: 
                    766:        // stop bit
1.1.1.2 ! root      767:        bit += GetStopBits(chan, enable);
        !           768: 
        !           769:        return bit;
        !           770: }
        !           771: 
        !           772: // ストップビット数を返す。
        !           773: // サポートしていないモードなどの場合は enable ならログを出力する。
        !           774: // enable は tx_enable か rx_enable。
        !           775: int
        !           776: MPSCCDevice::GetStopBits(MPSCCChan& chan, bool enable)
        !           777: {
        !           778:        switch (chan.stopbits) {
1.1       root      779:         case MPSCC::STOPBITS_SYNC:
                    780:                // 非同期モードでの STOPBITS 0 は未定義 (Enable ならログ表示)
                    781:                if (enable) {
1.1.1.2 ! root      782:                        putlog(0, "%s Undefined stopbit 0", CRName(chan, 4));
1.1       root      783:                }
1.1.1.2 ! root      784:                return 0;
1.1       root      785:         case MPSCC::STOPBITS_1:
1.1.1.2 ! root      786:                return 1;
1.1       root      787:         case MPSCC::STOPBITS_1_5:
                    788:                // サポートしない (Enable ならログ表示)
                    789:                if (enable) {
1.1.1.2 ! root      790:                        putlog(0, "%s Stopbit 1.5 not supported", CRName(chan, 4));
1.1       root      791:                }
1.1.1.2 ! root      792:                return 0;
1.1       root      793:         case MPSCC::STOPBITS_2:
1.1.1.2 ! root      794:                return 2;
1.1       root      795:        }
1.1.1.2 ! root      796:        __unreachable();
1.1       root      797: }
                    798: 
1.1.1.2 ! root      799: // 受信イベントの時間を設定する。
        !           800: // CR3 または CR4 の変更で呼ぶこと。また呼び出し後は old_cr3、old_cr4 を
        !           801: // 更新すること。
1.1       root      802: void
                    803: MPSCCDevice::SetRxPeriod(MPSCCChan& chan)
                    804: {
                    805:        int bit;
                    806: 
                    807:        // 受信データビット数
1.1.1.2 ! root      808:        bit = chan.rxbits;
        !           809:        // スタート/ストップ等を足す
        !           810:        bit += AdditionalBits(chan, chan.rx_enable);
        !           811:        chan.rxframebits = bit;
        !           812: 
        !           813:        if (loglevel >= 1) {
        !           814:                bool old_enable = chan.old_cr3 & MPSCC::CR3_RX_EN;
        !           815:                bool new_enable = chan.rx_enable;
        !           816:                if (old_enable == false && new_enable == false) {
        !           817:                        // 無効→無効ならパラメータが変化しても表示しない
        !           818: 
        !           819:                } else if (old_enable == true && new_enable == false) {
        !           820:                        // 有効→無効なら無効にしたことだけ表示
        !           821:                        putlogn("Channel %c RX Disable", chan.name);
        !           822:                        sr0_logphase = 0;
        !           823: 
        !           824:                } else if ((old_enable == false && new_enable == true) ||
        !           825:                           (chan.old_cr4 ^ GetCR4(chan)) != 0 ||
        !           826:                           ((chan.old_cr3 ^ GetCR3(chan)) & MPSCC::CR3_RXBITS) != 0)
        !           827:                {
        !           828:                        // 無効→有効なら表示。
        !           829:                        // そうでなければ(有効→有効なら)、パラメータが変化すれば表示。
        !           830:                        std::string nsstr;
        !           831:                        if (loglevel >= 2) {
        !           832:                                nsstr = string_format(" (%" PRIu64 ")", chan.bit12_ns);
        !           833:                        }
        !           834:                        putlogn("Channel %c RX Enable, %.1f bps%s, %d bits/frame",
        !           835:                                chan.name,
        !           836:                                chan.baudrate,
        !           837:                                nsstr.c_str(),
        !           838:                                bit);
        !           839:                        sr0_logphase = 0;
        !           840:                }
1.1       root      841:        }
                    842: 
                    843:        // パフォーマンス測定用のギミック。
                    844:        // シリアルポートを特定の設定 (本体 5bit、ストップビット 2bit) にすると、
                    845:        // VM 電源オン時から現在までの実時間をログに出力する。NetBSD/OpenBSD の
                    846:        // マルチユーザブートがあらかた終わってログインプロンプトが出る手前の
                    847:        // /etc/rc.local に
                    848:        //
                    849:        // stty -f /dev/ttya cs5 cstopb; stty -f /dev/ttya cs8 -cstopb
                    850:        //
                    851:        // と書いておくことで、ここまでにかかる時間を表示できる。
                    852:        // この値はホスト性能に依存するため、同一環境下での相対比較のみ可能。
                    853:        // シリアルポートの設定を (通常ではまず使わなそうなやつに) 変えてすぐ戻す
                    854:        // だけなので、実機でも副作用はないはず。
1.1.1.2 ! root      855:        if (chan.id == 0 &&
        !           856:            chan.rxbits == 5 && chan.stopbits == MPSCC::STOPBITS_2)
1.1       root      857:        {
                    858:                gSync->PutlogRealtime();
                    859:        }
                    860: }
                    861: 
1.1.1.2 ! root      862: // 送信イベントの時間を設定する。
        !           863: // CR4 または CR5 の変更で呼ぶこと。また呼び出し後は old_cr4、old_cr5 を
        !           864: // 更新すること。
1.1       root      865: void
                    866: MPSCCDevice::SetTxPeriod(MPSCCChan& chan)
                    867: {
                    868:        int bit;
                    869: 
                    870:        // 送信データビット数
1.1.1.2 ! root      871:        bit = chan.txbits;
        !           872:        // スタート/ストップ等を足す
        !           873:        bit += AdditionalBits(chan, chan.tx_enable);
        !           874:        chan.txframebits = bit;
        !           875: 
        !           876:        if (loglevel >= 1) {
        !           877:                bool old_enable = chan.old_cr5 & MPSCC::CR5_TX_EN;
        !           878:                bool new_enable = chan.tx_enable;
        !           879:                if (old_enable == false && new_enable == false) {
        !           880:                        // 無効→無効ならパラメータが変化しても表示しない
        !           881: 
        !           882:                } else if (old_enable == true && new_enable == false) {
        !           883:                        // 有効→無効なら無効にしたことだけ表示
        !           884:                        putlogn("Channel %c TX Disable", chan.name);
        !           885:                        sr0_logphase = 0;
        !           886: 
        !           887:                } else if ((old_enable == false && new_enable == true) ||
        !           888:                           (chan.old_cr4 ^ GetCR4(chan)) != 0 ||
        !           889:                           ((chan.old_cr5 ^ GetCR5(chan)) & MPSCC::CR5_TXBITS) != 0)
        !           890:                {
        !           891:                        // 無効→有効なら表示。
        !           892:                        // そうでなければ(有効→有効なら)、パラメータが変化すれば表示。
        !           893:                        std::string nsstr;
        !           894:                        if (loglevel >= 2) {
        !           895:                                nsstr = string_format(" (%" PRIu64 ")", chan.bit12_ns);
        !           896:                        }
        !           897:                        putlogn("Channel %c TX Enable, %.1f bps%s, %d bits/frame",
        !           898:                                chan.name,
        !           899:                                chan.baudrate,
        !           900:                                nsstr.c_str(),
        !           901:                                bit);
        !           902:                        sr0_logphase = 0;
        !           903:                }
1.1       root      904:        }
                    905: }
                    906: 
                    907: // 割り込み状態を変更
                    908: //
                    909: // uPD7201 の場合:
                    910: //
                    911: //     RxINT Disable (CR1 b4,3=%00) -->o--+ (注1)
                    912: //                                        |
                    913: //   o RxCharAvailable  ----|&            |
                    914: //                          |&---|OR      +--|&
                    915: //     All/First RxChar ----|&   |OR         |&--+
                    916: //                               |OR---------|&  |
                    917: //   o Special Rx Condition -----|OR             +---|OR
                    918: //                                                   |OR       ---
                    919: //   o External/Status ------------------------------|OR-->o-- INT
                    920: //                                                   |OR
                    921: //   o Tx Buffer Empty ----------|&              +---|OR
                    922: //                               |&-----|&       |
                    923: //     Tx INT/DMA Enable --------|&     |&       |
                    924: //     (CR1 b1)                         |&-------+
                    925: //                                      |&
                    926: //     INT/DMA Mode (CR2A b1,0) --------|& (注2)
                    927: //
                    928: // 注1: uPD7201/7201A Figure 3-2 では "Rx Disable (CR1:D1)" だがそこは
                    929: // Tx INT/DMA Enable ビットなので名称もビット位置も誤り。
                    930: // uPD7201 ユーザーズマニュアル p.23 の 図3-2 では "Rx Disable (CR1:D4-3=00)"
                    931: // とあるのでこれのビット位置が正しければ Rx Int Disable が正しいはず。
                    932: //
                    933: // 注2: uPD7201 のみ。Z8530 ではこの選択肢はないので常に true のはず。
                    934: //
                    935: void
                    936: MPSCCDevice::ChangeInterrupt()
                    937: {
                    938:        uint total_intpend = 0;
                    939:        bool int_enable[2];
                    940: 
                    941:        // uPD7201 の CR1 INT/DMA Mode による制御。
                    942:        // Z8530 では intdma_mode = INT_INT 固定。
                    943:        //
                    944:        // ついでにここで txint_enable も演算しておく。見た目は
                    945:        // 無駄っぽいけどコンパイラで最適化されるので気にしない。
                    946:        if (__predict_true(mpscc.intdma_mode == MPSCC::INTDMA_INT_INT)) {
                    947:                int_enable[0] = mpscc.chan[0].txint_enable && true;             // ChA INT
                    948:                int_enable[1] = mpscc.chan[1].txint_enable && true;             // ChB INT
                    949:        } else if (mpscc.intdma_mode == MPSCC::INTDMA_DMA_INT) {
                    950:                int_enable[0] = mpscc.chan[0].txint_enable && false;    // ChA DMA
                    951:                int_enable[1] = mpscc.chan[1].txint_enable && true;             // ChB INT
                    952:        } else {
                    953:                int_enable[0] = mpscc.chan[0].txint_enable && false;    // ChA DMA
                    954:                int_enable[1] = mpscc.chan[1].txint_enable && false;    // ChB DMA
                    955:        }
                    956: 
                    957:        for (auto& chan : mpscc.chan) {
                    958:                // Rx
                    959:                bool rx_avail = (chan.rxlen > 0) && chan.all_or_first;
                    960:                // Special Rx (XXX not yet)
                    961:                bool special = false;
                    962:                bool rx_int = (chan.rxint_mode != MPSCCChan::RXINT_DISABLE) &&
                    963:                              (rx_avail || special);
                    964: 
                    965:                // FirstChar モードなら1文字受信割り込み後にフラグを下ろす
                    966:                // (Rx 割り込み用の変数 rx_int が確定したここで行う)
                    967:                if (chan.rxint_mode == MPSCCChan::RXINT_1STCHAR) {
                    968:                        chan.all_or_first = false;
                    969:                }
                    970: 
                    971:                // XXX E/S not yet
                    972:                bool es_int = false;
                    973: 
                    974:                // Tx
                    975:                bool tx_int = int_enable[chan.id] &&
                    976:                              chan.txint_ready && (chan.txlen == 0);
                    977: 
                    978:                uint intpend = 0;
                    979:                if (rx_int)
                    980:                        intpend |= INTPEND_RX;
                    981:                if (tx_int)
                    982:                        intpend |= INTPEND_TX;
                    983:                if (es_int)
                    984:                        intpend |= INTPEND_ES;
                    985:                chan.intpend = intpend;
                    986: 
                    987:                total_intpend |= chan.intpend;
                    988:        }
                    989: 
                    990:        // いずれかでもあれば割り込みをアサート
                    991:        gInterrupt->ChangeINT(this, total_intpend);
                    992: }
                    993: 
                    994: // "9600,N,8,1" みたいなのを返す
                    995: std::string
                    996: MPSCCDevice::GetParamStr(const MPSCCChan& chan) const
                    997: {
                    998:        std::string rv;
                    999:        char parity;
                   1000:        char bits;
                   1001:        char stopbits;
                   1002: 
                   1003:        int parity_idx = 0;
1.1.1.2 ! root     1004:        if (chan.parity_enable) {
1.1       root     1005:                parity_idx++;
1.1.1.2 ! root     1006:                if (chan.parity_even) {
1.1       root     1007:                        parity_idx++;
                   1008:                }
                   1009:        }
                   1010:        parity = "NOE"[parity_idx];
                   1011: 
                   1012:        // bits は RX==TX のときのみ有効出力
                   1013:        // 違うときは '?' にしておく。
1.1.1.2 ! root     1014:        if (chan.rxbits == chan.txbits) {
        !          1015:                bits = '0' + chan.rxbits;
1.1       root     1016:        } else {
                   1017:                bits = '?';
                   1018:        }
                   1019: 
                   1020:        // stop bit は 1, 2 のみ有効出力。
                   1021:        // SYNC とか 1.5 bit とかは '?' にしておく。
1.1.1.2 ! root     1022:        switch (chan.stopbits) {
1.1       root     1023:         case MPSCC::STOPBITS_1:
                   1024:                stopbits = '1';
                   1025:                break;
                   1026:         case MPSCC::STOPBITS_2:
                   1027:                stopbits = '2';
                   1028:                break;
                   1029:         default:
                   1030:                stopbits = '?';
                   1031:                break;
                   1032:        }
                   1033: 
1.1.1.2 ! root     1034:        // ここは、このポートに接続する時に相手方で指定する設定値を
        !          1035:        // 表示したいので、ボーレートをよく知られている値に丸めたい。
        !          1036:        // 75 * 2^n の +-5% に入っていたら採用。
        !          1037:        int baud;
        !          1038:        int e;
        !          1039: 
        !          1040:        // 75 * 2 ^ (e-1) を求める
        !          1041:        double a = (chan.baudrate / 75) * 1.5;
        !          1042:        std::frexp(a, &e);
        !          1043:        int b = 75 * (1 << (e - 1));
        !          1044: 
        !          1045:        if (b * 19 / 20 <= chan.baudrate && chan.baudrate <= b * 21 / 20) {
        !          1046:                baud = b;
        !          1047:        } else {
        !          1048:                // +-5% 範囲外なら仕方ないのでそのままの値
        !          1049:                baud = (int)chan.baudrate;
        !          1050:        }
        !          1051: 
1.1       root     1052:        return string_format("%d,%c,%c,%c",
1.1.1.2 ! root     1053:                baud,
1.1       root     1054:                parity,
                   1055:                bits,
                   1056:                stopbits);
                   1057: }
                   1058: 
                   1059: // モニタに CR3/WR3、CR4/WR4、CR5/WR5 の内容を書き出す。
                   1060: // 更新後の y を返す。
                   1061: int
                   1062: MPSCCDevice::MonitorUpdateCR345(TextScreen& screen, int x, int y,
                   1063:        uint8 cr3, uint8 cr4, uint8 cr5)
                   1064: {
1.1.1.2 ! root     1065:        const std::array<char, 4> bits_per_char { '5', '7', '6', '8' };
        !          1066: 
1.1       root     1067:        // CR3/WR3
                   1068:        static const char * const cr3_str[] = {
                   1069:                "", "", "Auto", "", "", "", "", "RxEn"
                   1070:        };
                   1071:        MonitorReg(screen, x + 9, y, cr3, cr3_str);
1.1.1.2 ! root     1072:        screen.Print(x + 9, y, "RxBits=%c", bits_per_char[(cr3 >> 6) & 3]);
1.1       root     1073:        // b1-4 は非同期モードでは使わないのでグレーにしておく
                   1074:        screen.Puts(x + 24, y, TA::Disable, (cr3 & 0x10) ? "1" : "0");
                   1075:        screen.Puts(x + 29, y, TA::Disable, (cr3 & 0x08) ? "1" : "0");
                   1076:        screen.Puts(x + 34, y, TA::Disable, (cr3 & 0x04) ? "1" : "0");
                   1077:        screen.Puts(x + 39, y, TA::Disable, (cr3 & 0x02) ? "1" : "0");
                   1078:        y++;
                   1079: 
                   1080:        // CR4/WR4
                   1081:        static const char * const cr4_str[] = {
                   1082:                "", "", "", "", "", "", "PaEv", "PaEn"
                   1083:        };
                   1084:        MonitorReg(screen, x + 9, y, cr4, cr4_str);
1.1.1.2 ! root     1085:        static const char * const clkrate_str[] = {
        !          1086:                "1", "16", "32", "64"
        !          1087:        };
        !          1088:        screen.Print(x + 9, y, "Rate=x%s", clkrate_str[cr4 >> 6]);
1.1       root     1089:        static const char * const syncmode_str[] = {
                   1090:                "Mono", "Bi", "HDLC", "Ext"
                   1091:        };
                   1092:        uint stopbit = (cr4 >> 2) & 3;
                   1093:        screen.Print(x + 19, y, (stopbit == 0 ? TA::Normal : TA::Disable),
                   1094:                "Sync=%s", syncmode_str[(cr4 >> 4) & 3]);
                   1095:        static const char * const stopbit_str[] = {
                   1096:                "SyncMode",
                   1097:                "StopBit=1",
                   1098:                "Stop=1.5",
                   1099:                "StopBit=2"
                   1100:        };
                   1101:        screen.Puts(x + 29, y, stopbit_str[stopbit]);
                   1102:        y++;
                   1103: 
                   1104:        // CR5/WR5
                   1105:        static const char * const cr5_str[] = {
                   1106:                "!DTR", "", "", "SBrk", "TxEn", "CRC", "!RTS", "TCEn"
                   1107:        };
                   1108:        MonitorReg(screen, x + 9, y, cr5, cr5_str);
1.1.1.2 ! root     1109:        screen.Print(x + 14, y, "TxBits=%c", bits_per_char[(cr5 >> 5) & 3]);
1.1       root     1110:        y++;
                   1111: 
                   1112:        return y;
                   1113: }
                   1114: 
                   1115: // モニタに SR1/RR1 の内容を書き出す。
                   1116: void
                   1117: MPSCCDevice::MonitorUpdateSR1(TextScreen& screen, int x, int y, uint8 sr1)
                   1118: {
                   1119:        static const char * const sr1_str[] = {
                   1120:                "EOF", "FrEr", "RxOv", "PaEr", "", "", "", "Sent"
                   1121:        };
                   1122:        MonitorReg(screen, x + 9, y, sr1, sr1_str);
                   1123:        screen.Print(x + 29, y, TA::Disable, "ResidueCode=%d", (sr1 >> 1) & 7);
                   1124: }
                   1125: 
                   1126: // レジスタをビットごとに表示する。MonitorUpdate の下請け。
                   1127: void
                   1128: MPSCCDevice::MonitorReg(TextScreen& screen,
                   1129:        int x, int y, uint32 reg, const char * const *names)
                   1130: {
                   1131:        for (int i = 0; i < 8; i++) {
                   1132:                if (names[i][0] == '-') {
                   1133:                        screen.Puts(x + i * 5, y, TA::Disable, "----");
                   1134:                } else {
                   1135:                        bool b = reg & (1 << (7 - i));
                   1136:                        screen.Puts(x + i * 5, y, TA::OnOff(b), names[i]);
                   1137:                }
                   1138:        }
                   1139: }

unix.superglobalmegacorp.com

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