Annotation of nono/vm/upd7201.cpp, revision 1.1.1.5

1.1       root        1: //
                      2: // nono
1.1.1.3   root        3: // Copyright (C) 2020 nono project
                      4: // Licensed under nono-license.txt
1.1       root        5: //
                      6: 
                      7: #include "upd7201.h"
1.1.1.5 ! root        8: #include "interrupt.h"
1.1       root        9: 
                     10: // コンストラクタ
                     11: uPD7201Device::uPD7201Device()
                     12: {
1.1.1.5 ! root       13:        monitor_size = nnSize(48, 22);
1.1       root       14:        cr.chan[0].id = 0;
                     15:        cr.chan[0].name = "A";
                     16:        cr.chan[1].id = 1;
                     17:        cr.chan[1].name = "B";
                     18: 
                     19:        cr.chan[0].desc = NULL;
                     20:        cr.chan[1].desc = NULL;
                     21: }
                     22: 
                     23: // デストラクタ
                     24: uPD7201Device::~uPD7201Device()
                     25: {
                     26: }
                     27: 
                     28: // リセット
                     29: // どのタイミングで呼ばれるかは上位による
                     30: void
                     31: uPD7201Device::Reset()
                     32: {
                     33:        putlog(2, "リセット");
                     34: 
                     35:        // CR2A はチップリセットで bit6 以外を '0' に
                     36:        cr.cr2a &= ~0xbf;
                     37: 
                     38:        // チャンネルリセット
                     39:        ResetChannel(&cr.chan[0]);
                     40:        ResetChannel(&cr.chan[1]);
                     41: }
                     42: 
                     43: // チャンネルリセット
                     44: void
                     45: uPD7201Device::ResetChannel(struct SIO::channel *chan)
                     46: {
1.1.1.5 ! root       47:        putlog(2, "Channel %s Reset", chan->name);
1.1       root       48: 
1.1.1.5 ! root       49:        // CR0 b2-0 (PTR)
1.1       root       50:        chan->ptr = 0;
                     51: 
                     52:        // CR1 b0,1,3,4,7
                     53:        chan->cr1 &= ~(SIO::CR1_WAIT_EN | SIO::CR1_RXINT |
                     54:                       SIO::CR1_TXINT_EN | SIO::CR1_ESINT_EN);
1.1.1.5 ! root       55:        chan->all_or_first = false;
1.1       root       56: 
                     57:        // CR3 b0-7
                     58:        chan->cr3 = 0;
                     59: 
                     60:        // CR5 b1,2,3,4,7
                     61:        chan->cr5 &= ~(SIO::CR5_DTR | SIO::CR5_SENDBREAK | SIO::CR5_TX_EN |
                     62:                       SIO::CR5_CRC16 | SIO::CR5_RTS);
                     63: 
                     64:        // SR0 は b0,1 が '0'、b2,6 が '1'、残りは不定
                     65:        chan->sr0 &= ~(SIO::SR0_INTPEND | SIO::SR0_RXAVAIL);
                     66:        chan->sr0 |= (SIO::SR0_TXUNDER | SIO::SR0_TXEMPTY);
                     67: 
                     68:        // SR1 は b4-7 が '0'
                     69:        chan->sr1 &= ~(SIO::SR1_ENDOFFRAME | SIO::SR1_CRCERROR |
                     70:                       SIO::SR1_RXOVERRUN | SIO::SR1_PARITYERROR);
                     71: 
1.1.1.5 ! root       72:        // 内部状態をリセット
1.1       root       73:        chan->es_ratched = false;
1.1.1.5 ! root       74:        chan->reset_txint_pend = true;
1.1       root       75: 
                     76:        // 受信バッファをクリア
                     77:        memset(chan->rxbuf, 0, sizeof(chan->rxbuf));
                     78:        chan->rxlen = 0;
                     79: }
                     80: 
                     81: // 制御ポートの読み込み
                     82: uint8
                     83: uPD7201Device::ReadCtrl(struct SIO::channel *chan)
                     84: {
                     85:        uint8 data;
                     86: 
                     87:        switch (chan->ptr) {
                     88:         case 0:        // SR0
1.1.1.5 ! root       89:                data = chan->sr0;
1.1       root       90:                putlog(2, "SR%d%s -> $%02x", chan->ptr, chan->name, data);
                     91:                // アクセス後は SR0 へ戻す
                     92:                chan->ptr = 0;
                     93:                break;
                     94: 
                     95:         case 1:        // SR1
1.1.1.5 ! root       96:                data = chan->sr1;
1.1       root       97:                putlog(2, "SR%d%s -> $%02x", chan->ptr, chan->name, data);
                     98:                // アクセス後は SR0 へ戻す
                     99:                chan->ptr = 0;
                    100:                break;
                    101: 
                    102:         case 2:
                    103:                // SR2B はベクタの読み出し
                    104:                if (chan->id == 1) {
                    105:                        data = cr.vector;
                    106:                        putlog(2, "SR%d%s -> $%02x", chan->ptr, chan->name, data);
                    107:                        // アクセス後は SR0 へ戻す
                    108:                        chan->ptr = 0;
                    109:                        break;
                    110:                }
                    111: 
                    112:                // SR2A はない
                    113:                FALLTHROUGH;
                    114: 
                    115:         default:
                    116:                putlog(0, "未実装レジスタ読み込み SR%d%s",
                    117:                        chan->ptr, chan->name);
                    118:                // SR0 へ戻る?
                    119:                chan->ptr = 0;
                    120:                return 0xff;
                    121:        }
                    122:        return data;
                    123: }
                    124: 
                    125: // 制御ポートの書き込み
                    126: void
                    127: uPD7201Device::WriteCtrl(struct SIO::channel *chan, uint32 data)
                    128: {
1.1.1.5 ! root      129:        // CR0 はコマンドかまたは次にアクセスするレジスタを指定する。
        !           130:        // CR0 以外のレジスタをアクセスすると、次のアクセスは CR0 に戻る。
1.1       root      131: 
1.1.1.5 ! root      132:        if (chan->ptr == 0) {
        !           133:                WriteCR0(chan, data);
        !           134:        } else {
        !           135:                switch (chan->ptr) {
        !           136:                 case 1:
        !           137:                        WriteCR1(chan, data);
1.1       root      138:                        break;
1.1.1.5 ! root      139:                 case 2:
        !           140:                        WriteCR2(chan, data);
1.1       root      141:                        break;
1.1.1.5 ! root      142:                 case 3:
        !           143:                        WriteCR3(chan, data);
1.1       root      144:                        break;
1.1.1.5 ! root      145:                 case 4:
        !           146:                        WriteCR4(chan, data);
1.1       root      147:                        break;
1.1.1.5 ! root      148:                 case 5:
        !           149:                        WriteCR5(chan, data);
1.1       root      150:                        break;
1.1.1.5 ! root      151:                 case 6:
        !           152:                        WriteCR6(chan, data);
1.1       root      153:                        break;
1.1.1.5 ! root      154:                 case 7:
        !           155:                        WriteCR7(chan, data);
1.1       root      156:                        break;
                    157:                 default:
1.1.1.5 ! root      158:                        putlog(0, "未実装レジスタ書き込み CR%d%s <- $%02x",
        !           159:                                chan->ptr, chan->name, data);
        !           160:                        break;
1.1       root      161:                }
                    162:                // アクセス後は CR0 へ戻す
                    163:                chan->ptr = 0;
                    164:        }
                    165: }
                    166: 
1.1.1.2   root      167: // 制御ポートの Peek
                    168: uint8
                    169: uPD7201Device::PeekCtrl(const struct SIO::channel *chan) const
                    170: {
                    171:        switch (chan->ptr) {
                    172:         case 0:        // SR0
1.1.1.5 ! root      173:                return chan->sr0;
1.1.1.2   root      174: 
                    175:         case 1:        // SR1
1.1.1.5 ! root      176:                return chan->sr1;
1.1.1.2   root      177: 
                    178:         case 2:        // SR2
                    179:                // SR2A はない。SR2B はベクタの読み出し
                    180:                if (chan->id == 1) {
                    181:                        return cr.vector;
                    182:                }
                    183:                FALLTHROUGH;
                    184: 
                    185:         default:
                    186:                // 未調査
                    187:                return 0xff;
                    188:        }
                    189: }
                    190: 
1.1.1.5 ! root      191: // CR0 への書き込み
        !           192: void
        !           193: uPD7201Device::WriteCR0(struct SIO::channel *chan, uint32 data)
1.1.1.2   root      194: {
1.1.1.5 ! root      195:        uint cmd;
1.1.1.2   root      196: 
1.1.1.5 ! root      197:        // XXX b7,b6 は未対応。
        !           198:        // b5,b4,b3 がコマンド。
        !           199:        // b2,b1,b0 が次にアクセスするレジスタ(chan->ptr)の切り替え。
        !           200:        chan->cr0 = data;
        !           201:        chan->ptr = (chan->cr0 & SIO::CR0_PTR);
        !           202: 
        !           203:        cmd = (chan->cr0 & SIO::CR0_CMD) >> 3;
        !           204:        if (cmd == 0) {
        !           205:                // コマンド0 ならレジスタ切り替え
        !           206:                putlog(3, "CR0%s <- $%02x (ptr=%d)", chan->name, data, chan->ptr);
        !           207:        } else {
        !           208:                // 0 以外ならコマンド発行
        !           209:                putlog(2, "CR0%s <- $%02x", chan->name, data);
        !           210:        }
        !           211:        switch (cmd) {
        !           212:         case 0:        // No operation
        !           213:                break;
        !           214:         case 1:        // Send Abort
        !           215:                if (chan->mode == SIO::Mode::HDLC) {
        !           216:                        putlog(0, "CR0: Send Abort 未実装");
        !           217:                } else {
        !           218:                        // XXX Send Abort コマンドは「HDLC モードのみ有効」と書いて
        !           219:                        //     あるがそれ以外の時にどうなるか不明。
        !           220:                        putlog(0, "CR0: 未定義コマンド %d", cmd);
        !           221:                }
        !           222:                break;
        !           223:         case 2:        // Reset External/Status Interrupt
        !           224:                putlog(3, "CR0%s: Reset E/S Interrupt", chan->name);
        !           225:                chan->es_ratched = false;
        !           226:                break;
        !           227:         case 3:        // Channel Reset
        !           228:                ResetChannel(chan);
        !           229:                break;
        !           230:         case 4:        // Enable Interrupt On Next Receive Character
        !           231:                putlog(0, "CR0: 未実装コマンド %d", cmd);
        !           232:                break;
        !           233:         case 5:        // Reset Transmitter Interrupt/DMA Pending
        !           234:                putlog(1, "CR0%s: Reset Tx Int/DMA Pending", chan->name);
        !           235:                chan->reset_txint_pend = false;
        !           236:                ChangeInterrupt();
        !           237:                break;
        !           238:         case 6:        // Error Reset
        !           239:         case 7:        // End of Interrupt
        !           240:                putlog(0, "CR0: 未実装コマンド %d", cmd);
        !           241:                break;
        !           242:         default:
        !           243:                __unreachable();
1.1.1.2   root      244:        }
                    245: }
                    246: 
1.1.1.5 ! root      247: // CR1 への書き込み
        !           248: void
        !           249: uPD7201Device::WriteCR1(struct SIO::channel *chan, uint32 data)
1.1.1.2   root      250: {
1.1.1.5 ! root      251:        putlog(2, "CR%d%s <- $%02x", chan->ptr, chan->name, data);
        !           252: 
        !           253:        chan->cr1 = data;
        !           254: 
        !           255:        // RXINT モードで all_or_first の値(初期値)を用意。
        !           256:        // DISABLE なら(使わないのでどっちでもいいはずだけど一応) false にしとく。
        !           257:        // FIRSTCHAR なら初期状態が true。ALL_* なら常時 true。
        !           258:        chan->all_or_first = ((chan->cr1 & SIO::CR1_RXINT) != SIO::RXINT_DISABLE);
1.1.1.2   root      259: }
                    260: 
1.1.1.5 ! root      261: // CR2 への書き込み
        !           262: void
        !           263: uPD7201Device::WriteCR2(struct SIO::channel *chan, uint32 data)
        !           264: {
        !           265:        if (chan->id == 0) {    // CR2A
        !           266:                putlog(2, "CR2A <- $%02x 書き込み(b7,b2-0未実装)", data);
        !           267:                cr.cr2a = data;
        !           268:        } else {                                // CR2B
        !           269:                putlog(2, "CR2B <- $%02x (Set vector)", data);
        !           270:                cr.vector = data;
        !           271:        }
        !           272: }
        !           273: 
        !           274: // CR3 への書き込み
        !           275: void
        !           276: uPD7201Device::WriteCR3(struct SIO::channel *chan, uint32 data)
        !           277: {
        !           278:        chan->cr3 = data;
        !           279: 
        !           280:        putlog(2, "CR%d%s <- $%02x", chan->ptr, chan->name, data);
        !           281:        putlog(1, "Channel %s RX %s, %dbits",
        !           282:                chan->name,
        !           283:                (chan->cr3 & SIO::CR3_RX_EN) ? "Enable" : "Disable",
        !           284:                bits_per_char[(chan->cr3 & SIO::CR3_RXBITS) >> 6]);
        !           285: }
        !           286: 
        !           287: // CR4 への書き込み
        !           288: void
        !           289: uPD7201Device::WriteCR4(struct SIO::channel *chan, uint32 data)
        !           290: {
        !           291:        chan->cr4 = data;
        !           292:        putlog(2, "CR%d%s <- $%02x", chan->ptr, chan->name, data);
        !           293:        uint8 stopbits = (chan->cr4 & SIO::CR4_STOPBITS);
        !           294:        uint8 syncmode = (chan->cr4 & SIO::CR4_SYNCMODE);
        !           295: 
        !           296:        // モード分け、優先順位は分からない
        !           297:        if (stopbits == SIO::SYNC_MODE) {
        !           298:                if (syncmode == SIO::SYNC_HDLC) {
        !           299:                        chan->mode = SIO::Mode::HDLC;
        !           300:                        putlog(2, "Channel %s HDLC Mode", chan->name);
        !           301:                } else {
        !           302:                        chan->mode = SIO::Mode::SYNC;
        !           303:                        const char *sm[] = { "8bit", "16bit", "HDLC?", "Ext" };
        !           304:                        putlog(2, "Channel %s Sync (%s) Mode",
        !           305:                                chan->name, sm[syncmode >> 4]);
        !           306:                }
        !           307:        } else {
        !           308:                chan->mode = SIO::Mode::ASYNC;
        !           309:                const char *cm[] = { "x1", "x16", "x32", "x64" };
        !           310:                const char *sm[] = { "?", "1", "1.5", "2" };
        !           311:                putlog(2, "Channel %s Async (%s clock, stopbit %s) Mode",
        !           312:                        chan->name,
        !           313:                        cm[(chan->cr4 & SIO::CR4_CLKRATE) >> 6],
        !           314:                        sm[stopbits >> 2]);
        !           315:        }
        !           316: }
        !           317: 
        !           318: // CR5 への書き込み
        !           319: void
        !           320: uPD7201Device::WriteCR5(struct SIO::channel *chan, uint32 data)
        !           321: {
        !           322:        chan->cr5 = data;
        !           323: 
        !           324:        putlog(2, "CR%d%s <- $%02x", chan->ptr, chan->name, data);
        !           325:        putlog(1, "Channel %s TX %s, %dbits",
        !           326:                chan->name,
        !           327:                (chan->cr5 & SIO::CR5_TX_EN) ? "Enable" : "Disable",
        !           328:                bits_per_char[(chan->cr5 & SIO::CR5_TXBITS) >> 5]);
        !           329: }
        !           330: 
        !           331: // CR6 への書き込み
        !           332: void
        !           333: uPD7201Device::WriteCR6(struct SIO::channel *chan, uint32 data)
        !           334: {
        !           335:        chan->cr6 = data;
        !           336: 
        !           337:        putlog(0, "CR6%s <- $%02x 書き込み(未実装)", chan->name, data);
        !           338: }
        !           339: 
        !           340: // CR7 への書き込み
        !           341: void
        !           342: uPD7201Device::WriteCR7(struct SIO::channel *chan, uint32 data)
        !           343: {
        !           344:        chan->cr7 = data;
        !           345: 
        !           346:        putlog(0, "CR7%s <- $%02x 書き込み(未実装)", chan->name, data);
        !           347: }
1.1.1.2   root      348: 
1.1       root      349: // データポートの読み込み
                    350: uint8
1.1.1.2   root      351: uPD7201Device::ReadData(struct SIO::channel *chan)
1.1       root      352: {
                    353:        uint8 data;
                    354: 
                    355:        if (chan->rxlen > 0) {
                    356:                data = chan->rxbuf[0];
1.1.1.5 ! root      357:                putlog(3, "Ch%s Data -> $%02x", chan->name, data);
1.1       root      358:                chan->rxlen--;
1.1.1.5 ! root      359:                if (chan->rxlen == 0) {
        !           360:                        // 取り出して空になった
        !           361:                        chan->sr0 &= ~SIO::SR0_RXAVAIL;
        !           362:                        ChangeInterrupt();
        !           363:                } else {
        !           364:                        // 少ないので毎回前詰めしちゃえ
1.1       root      365:                        memmove(chan->rxbuf + 1, chan->rxbuf, chan->rxlen);
                    366:                }
                    367:        } else {
                    368:                // XXX 何が読めるか
                    369:                data = 0xff;
1.1.1.5 ! root      370:                putlog(3, "Ch%s Data -> $%02x (Empty)", chan->name, data);
1.1       root      371:        }
                    372: 
                    373:        return data;
                    374: }
                    375: 
                    376: // データポートの書き込み
                    377: void
                    378: uPD7201Device::WriteData(struct SIO::channel *chan, uint32 data)
                    379: {
                    380:        char charbuf[4];
                    381: 
                    382:        if (isprint((int)data)) {
                    383:                snprintf(charbuf, sizeof(charbuf), "'%c'", data);
                    384:        } else {
                    385:                charbuf[0] = '\0';
                    386:        }
1.1.1.5 ! root      387:        putlog(3, "Ch%s Data <- $%02x %s", chan->name, data, charbuf);
1.1       root      388: 
                    389:        // 1文字送信
                    390: 
                    391:        // 今のところ内部バッファがなく常に送信できるので
                    392:        // 必ず Tx Buffer Empty が発生する。
                    393:        chan->sr0 |= SIO::SR0_TXEMPTY;
                    394: 
1.1.1.5 ! root      395:        // 割り込み状態を変える
        !           396:        ChangeInterrupt();
1.1       root      397: }
                    398: 
1.1.1.2   root      399: // データポートの Peek
                    400: uint8
                    401: uPD7201Device::PeekData(const struct SIO::channel *chan) const
                    402: {
                    403:        if (chan->rxlen > 0) {
                    404:                // 受信バッファにデータがあれば先頭バイトが見える
                    405:                return chan->rxbuf[0];
                    406:        } else {
                    407:                // 空の時は?
                    408:                return 0xff;
                    409:        }
                    410: }
                    411: 
1.1.1.3   root      412: // TX/RX の bits/char のレジスタ値を実際の bits/char の値に変換する。
1.1       root      413: /* static */
                    414: const int
                    415: uPD7201Device::bits_per_char[] = { 5, 7, 6, 8 };
                    416: 
                    417: // 1バイト受信する。
                    418: // 受理されれば true を返す。
                    419: bool
                    420: uPD7201Device::Rx(int ch, uint32 data)
                    421: {
                    422:        struct SIO::channel *chan = &cr.chan[ch];
                    423: 
                    424:        // Rx Enable でなければ受け取らない?
                    425:        if ((chan->cr3 & SIO::CR3_RX_EN) == 0) {
                    426:                return false;
                    427:        }
                    428: 
1.1.1.5 ! root      429:        // 1バイトでもあれば有効
        !           430:        chan->sr0 |= SIO::SR0_RXAVAIL;
        !           431: 
1.1       root      432:        // バッファが一杯なら Rx Overrun Error
                    433:        if (chan->rxlen == sizeof(chan->rxbuf)) {
                    434:                putlog(2, "Rx Overrun");
                    435:                chan->sr1 |= SIO::SR1_RXOVERRUN;
1.1.1.5 ! root      436:                // XXX special Rx condition interrupt occurs
1.1       root      437:                return false;
                    438:        }
                    439: 
                    440:        // 受信
                    441:        chan->rxbuf[chan->rxlen++] = data;
                    442: 
1.1.1.5 ! root      443:        // 割り込み状態を変更
        !           444:        ChangeInterrupt();
        !           445: 
        !           446:        return true;
        !           447: }
        !           448: 
        !           449: // 割り込み状態を変更
        !           450: void
        !           451: uPD7201Device::ChangeInterrupt()
        !           452: {
        !           453:        uint int_asserted = 0;
        !           454: 
        !           455:        for (int ch = 0; ch < 2; ch++) {
        !           456:                struct SIO::channel *chan = &cr.chan[ch];
        !           457: 
        !           458:                // Rx
        !           459:                bool rx_avail = (chan->rxlen > 0) && chan->all_or_first;
        !           460:                // Special Rx
        !           461:                bool special = false;   // XXX not yet
        !           462: 
        !           463:                bool rx_enable = (chan->cr3 & SIO::CR3_RX_EN);
        !           464:                bool rx_int = (rx_enable && (rx_avail || special));
        !           465: 
        !           466:                // FirstChar モードなら1文字受信割り込み後にフラグを下ろす
        !           467:                // (Rx 割り込み用の変数 rx_int が確定したここで行う)
        !           468:                if ((chan->cr1 & SIO::CR1_RXINT) == SIO::RXINT_FIRSTCHAR) {
        !           469:                        chan->all_or_first = false;
1.1       root      470:                }
1.1.1.5 ! root      471: 
        !           472:                // XXX E/S not yet
        !           473: 
        !           474:                // Tx
        !           475:                bool tx_empty = (chan->sr0 & SIO::SR0_TXEMPTY);
        !           476:                bool tx_enable = (chan->cr1 & SIO::CR1_TXINT_EN);
        !           477:                // reset_txint_pend は通常 true、コマンド発行で false に落ちる。
        !           478:                // XXX INT DMA Mode はよく分からんのでスルー
        !           479:                bool tx_int = (tx_empty && tx_enable && chan->reset_txint_pend);
        !           480: 
        !           481:                // 4つの要因の合成
        !           482:                chan->int_asserted = 0;
        !           483:                chan->int_asserted |= tx_int ? SIO::INTR_TX : 0;
        !           484:                chan->int_asserted |= rx_int ? SIO::INTR_RX : 0;
        !           485: 
        !           486:                // 両方のチャンネル分を合成
        !           487:                int_asserted |= chan->int_asserted;
1.1       root      488:        }
                    489: 
1.1.1.5 ! root      490:        gInterrupt->ChangeINT(this, int_asserted);
1.1       root      491: }
                    492: 
                    493: // モニター
1.1.1.4   root      494: void
                    495: uPD7201Device::MonitorUpdate(TextScreen& monitor)
1.1       root      496: {
1.1.1.5 ! root      497:        int y;
        !           498: 
1.1       root      499:        monitor.Clear();
                    500:        for (int i = 0; i < 2; i++) {
                    501:                int x = 0;
1.1.1.5 ! root      502:                y = i * 10;
1.1.1.4   root      503:                MonitorUpdateCh(monitor, i, x, y);
1.1       root      504:        }
1.1.1.5 ! root      505: 
        !           506:        // CR2A
        !           507:        uint cr2a = cr.cr2a;
        !           508:        y = 20;
        !           509:        monitor.Print(0, y, "CR2A:$%02x", cr2a);
        !           510:        if ((cr2a & 0x80)) {
        !           511:                monitor.Print(9, y, TA::On, "SYNC");
        !           512:        } else {
        !           513:                monitor.Print(9, y, "RTSB");
        !           514:        }
        !           515:        monitor.Print(14, y, "----");
        !           516:        monitor.Print(19, y, TA::OnOff((cr2a & 0x20)), "Vect");
        !           517:        if ((cr2a & 0x18) == 0x10) {
        !           518:                monitor.Print(24, y, "IM=V4-V2");
        !           519:        } else {
        !           520:                monitor.Print(24, y, "IM=V2-V0");
        !           521:        }
        !           522:        // bit2 (Priority Select) は bit0 が 0 の時だけ意味があるようだ
        !           523:        if ((cr2a & 0x01) == 0) {
        !           524:                if ((cr2a & 0x04)) {
        !           525:                        monitor.Print(34, y, "RxTx");
        !           526:                } else {
        !           527:                        monitor.Print(34, y, "A->B");
        !           528:                }
        !           529:        }
        !           530:        // bit1,0 はよく分からん
        !           531:        monitor.Print(39, y, "INT/DMA=%d", (cr2a & 0x3));
        !           532:        y++;
        !           533: 
        !           534:        // CR2B
        !           535:        monitor.Print(0, y, "CR2B:$%02x", cr.vector);
1.1       root      536: }
                    537: 
                    538: // モニター (1チャンネル)
                    539: void
1.1.1.4   root      540: uPD7201Device::MonitorUpdateCh(TextScreen& monitor,
                    541:        int ch, int xbase, int ybase)
1.1       root      542: {
                    543:        struct SIO::channel *chan = &cr.chan[ch];
                    544:        uint cr0;
                    545:        uint cr1;
                    546:        uint cr3;
                    547:        uint cr4;
                    548:        uint cr5;
                    549:        uint sr0;
                    550:        uint sr1;
                    551:        uint rxlen;
                    552:        int x;
                    553:        int y;
                    554: 
1.1.1.5 ! root      555:        cr0 = (chan->cr0 & ~SIO::CR0_PTR) | chan->ptr;
1.1       root      556:        cr1 = chan->cr1;
                    557:        cr3 = chan->cr3;
                    558:        cr4 = chan->cr4;
                    559:        cr5 = chan->cr5;
                    560:        sr0 = chan->sr0;
                    561:        sr1 = chan->sr1;
                    562:        rxlen = chan->rxlen;
                    563: 
                    564:        // 0         1         2         3         4         5         6
                    565:        // 012345678901234567890123456789012345678901234567890123456789012345
                    566:        //          0123 0123 0123 0123 0123 0123 0123 0123
1.1.1.5 ! root      567:        // CR0: $xx CRC=x     CMD=x          PTR=x
        !           568:        // CR1: $xx WE   0    WR   RXInt=x   0    TXEn ESEn
        !           569:        // RXBuf: 0 --- --- ---           Intr: Rx Sp Tx ES
1.1       root      570: 
                    571:        x = xbase;
                    572:        y = ybase;
                    573:        monitor.Print(x, y++, "Channel %s: %s", chan->name, chan->desc);
1.1.1.5 ! root      574:        monitor.Print(x, y++, "CR0: $%02x", cr0);
        !           575:        monitor.Print(x, y++, "CR1: $%02x", cr1);
        !           576:        monitor.Print(x, y++, "CR3: $%02x", cr3);
        !           577:        monitor.Print(x, y++, "CR4: $%02x", cr4);
        !           578:        monitor.Print(x, y++, "CR5: $%02x", cr5);
        !           579:        monitor.Print(x, y++, "SR0: $%02x", sr0);
        !           580:        monitor.Print(x, y++, "SR1: $%02x", sr1);
        !           581:        monitor.Print(x, y,   "RXbuf: %d", rxlen);
1.1       root      582:        int i;
                    583:        for (i = 0; i < rxlen; i++) {
1.1.1.5 ! root      584:                monitor.Print(x + 9 + i * 4, y, "$%02x", chan->rxbuf[i]);
1.1       root      585:        }
                    586:        for (; i < sizeof(chan->rxbuf); i++) {
1.1.1.5 ! root      587:                monitor.Print(x + 9 + i * 4, y, "---");
1.1       root      588:        }
1.1.1.5 ! root      589:        // 内部割り込み状態
        !           590:        monitor.Print(31, y, "Intr:");
        !           591:        monitor.Print(37, y, TA::OnOff(chan->int_asserted & SIO::INTR_RX), "Rx");
        !           592:        monitor.Print(40, y, TA::OnOff(chan->int_asserted & SIO::INTR_SP), "SP");
        !           593:        monitor.Print(43, y, TA::OnOff(chan->int_asserted & SIO::INTR_TX), "Tx");
        !           594:        monitor.Print(46, y, TA::OnOff(chan->int_asserted & SIO::INTR_ES), "ES");
1.1       root      595: 
                    596:        y = ybase + 1;
                    597:        x = xbase;
                    598:        // CR0
                    599:        monitor.Print(x + 9, y, "CRC=%d", (cr0 >> 6));
                    600:        static const char * const cmd_str[] = {
                    601:        //   0123456789012345
                    602:                "No operation",
                    603:                "Send Abort",
                    604:                "Reset E/S Int",
                    605:                "Channel Reset",
                    606:                "Enable IntNextCh",
                    607:                "Reset TxIntPend",
                    608:                "Error Reset",
                    609:                "End of Interrupt",
                    610:        };
                    611:        uint cmd = (cr0 >> 3) & 7;
                    612:        monitor.Print(x + 19, y, "CMD=%d(%s)", cmd, cmd_str[cmd]);
                    613:        monitor.Print(x + 43, y, "PTR=%d", (cr0 & 7));
                    614:        y++;
                    615: 
                    616:        // CR1
                    617:        static const char * const cr1_str[] = {
                    618:                "WaEn", "----", "WaRx", "", "", "----", "TxIE", "ESEn"
                    619:        };
1.1.1.4   root      620:        MonitorReg(monitor, x + 9, y, cr1, cr1_str);
1.1.1.5 ! root      621:        static const char * const rxint_str[] = {
        !           622:        //   2345678
        !           623:                "=SpOnly",
        !           624:                "=AllChr",
        !           625:                "=1stChr",
        !           626:                "Disable",
        !           627:        };
        !           628:        monitor.Print(x + 24, y, "RI%s", rxint_str[(cr1 >> 3) & 3]);
1.1       root      629:        y++;
                    630: 
                    631:        // CR3
                    632:        static const char * const cr3_str[] = {
                    633:                "", "", "AuEn", "----", "----", "----", "----", "RXEn"
                    634:        };
1.1.1.4   root      635:        MonitorReg(monitor, x + 9, y, cr3, cr3_str);
1.1       root      636:        monitor.Print(x + 9, y, "RXbits=%d", 5 + ((cr3 >> 6) & 3));
                    637:        y++;
                    638: 
                    639:        // CR4
                    640:        static const char * const cr4_str[] = {
                    641:                "", "", "", "", "", "", "PaEv", "PaEn"
                    642:        };
1.1.1.4   root      643:        MonitorReg(monitor, x + 9, y, cr4, cr4_str);
1.1       root      644: 
                    645:        static const char * const clkrate_str[] = {
                    646:                "1", "16", "32", "64"
                    647:        };
                    648:        monitor.Print(x + 9, y, "Rate=x%s", clkrate_str[(cr4 >> 6) & 3]);
                    649:        static const char * const syncmode_str[] = {
                    650:                "Mono", "Bi", "HDLC", "Ext"
                    651:        };
                    652:        monitor.Print(x + 19, y, "Sync=%s", syncmode_str[(cr4 >> 4) & 3]);
                    653:        static const char * const stopbit_str[] = {
                    654:                "Sync", "1", "1.5", "2"
                    655:        };
                    656:        monitor.Print(x + 29, y, "Stop=%s", stopbit_str[(cr4 >> 2) & 3]);
                    657:        y++;
                    658: 
                    659:        // CR5
                    660:        static const char * const cr5_str[] = {
                    661:                "DTR", "", "", "SBrk", "TXEn", "CRC", "!RTS", "TCEn"
                    662:        };
1.1.1.4   root      663:        MonitorReg(monitor, x + 9, y, cr5, cr5_str);
1.1       root      664:        monitor.Print(x + 14, y, "TXbits=%d", 5 + ((cr5 >> 5) & 3));
                    665:        y++;
                    666: 
                    667:        // SR0
                    668:        static const char * const sr0_str[] = {
                    669:                "BrAb", "TxUn", "CTS", "SYNC", "DCD", "TxEm", "IntP", "RxAv"
                    670:        };
1.1.1.4   root      671:        MonitorReg(monitor, x + 9, y, sr0, sr0_str);
1.1.1.5 ! root      672:        // SR0 の bit1 (Interrupt Pending) は SR0A のみ。SR0B では 0。
        !           673:        if (ch == 1) {
        !           674:                monitor.Print(39, y, "----");
        !           675:        }
1.1       root      676:        y++;
                    677: 
                    678:        // SR1
                    679:        static const char * const sr1_str[] = {
                    680:                "EOF", "CRCE", "RxOv", "PaEr", "", "", "", "Sent"
                    681:        };
1.1.1.4   root      682:        MonitorReg(monitor, x + 9, y, sr1, sr1_str);
1.1       root      683:        monitor.Print(x + 29, y, "ResidueCode=%d", (sr1 >> 1) & 7);
                    684:        y++;
                    685: }
                    686: 
                    687: // レジスタをビットごとに表示する。MonitorUpdate の下請け。
                    688: void
1.1.1.4   root      689: uPD7201Device::MonitorReg(TextScreen& monitor,
                    690:        int x, int y, uint32 reg, const char * const *names)
1.1       root      691: {
                    692:        for (int i = 0; i < 8; i++) {
                    693:                if (strcmp(names[i], "----") == 0) {
1.1.1.3   root      694:                        monitor.Puts(x + i * 5, y, TA::Disable, names[i]);
1.1       root      695:                } else {
                    696:                        bool b = reg & (1 << (7 - i));
1.1.1.3   root      697:                        monitor.Puts(x + i * 5, y, TA::OnOff(b), names[i]);
1.1       root      698:                }
                    699:        }
                    700: }

unix.superglobalmegacorp.com

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