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

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

unix.superglobalmegacorp.com

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