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

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

unix.superglobalmegacorp.com

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