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

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: // コンストラクタ
1.1.1.7   root       11: uPD7201Device::uPD7201Device(const std::string& objname_)
                     12:        : inherited(objname_)
1.1       root       13: {
                     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;
1.1.1.7   root       21: 
1.1.1.9 ! root       22:        for (int ch = 0; ch < txevent.size(); ch++) {
        !            23:                // time は SetTXPeriod() でセット
        !            24:                txevent[ch].dev = this;
        !            25:                txevent[ch].func = (DeviceCallback_t)&uPD7201Device::TXCallback;
        !            26:                txevent[ch].code = ch;
        !            27:                // 名前は継承先でセットする。機種ごとに名前を使い分けているため。
        !            28:        }
        !            29: 
1.1.1.7   root       30:        monitor.func = (MonitorCallback_t)&uPD7201Device::MonitorUpdate;
                     31:        monitor.SetSize(48, 22);
                     32:        // 登録は継承先で行う。機種ごとに通りのいい名前を使い分けているため。
1.1       root       33: }
                     34: 
                     35: // デストラクタ
                     36: uPD7201Device::~uPD7201Device()
                     37: {
                     38: }
                     39: 
                     40: // リセット
                     41: void
1.1.1.6   root       42: uPD7201Device::ResetHard()
1.1       root       43: {
                     44:        putlog(2, "リセット");
                     45: 
                     46:        // CR2A はチップリセットで bit6 以外を '0' に
                     47:        cr.cr2a &= ~0xbf;
                     48: 
                     49:        // チャンネルリセット
                     50:        ResetChannel(&cr.chan[0]);
                     51:        ResetChannel(&cr.chan[1]);
                     52: }
                     53: 
                     54: // チャンネルリセット
                     55: void
1.1.1.9 ! root       56: uPD7201Device::ResetChannel(SIO::channel *chan)
1.1       root       57: {
1.1.1.5   root       58:        putlog(2, "Channel %s Reset", chan->name);
1.1       root       59: 
1.1.1.5   root       60:        // CR0 b2-0 (PTR)
1.1       root       61:        chan->ptr = 0;
                     62: 
                     63:        // CR1 b0,1,3,4,7
                     64:        chan->cr1 &= ~(SIO::CR1_WAIT_EN | SIO::CR1_RXINT |
                     65:                       SIO::CR1_TXINT_EN | SIO::CR1_ESINT_EN);
1.1.1.5   root       66:        chan->all_or_first = false;
1.1       root       67: 
                     68:        // CR3 b0-7
                     69:        chan->cr3 = 0;
                     70: 
                     71:        // CR5 b1,2,3,4,7
                     72:        chan->cr5 &= ~(SIO::CR5_DTR | SIO::CR5_SENDBREAK | SIO::CR5_TX_EN |
                     73:                       SIO::CR5_CRC16 | SIO::CR5_RTS);
1.1.1.9 ! root       74:        SetTXPeriod(chan);
1.1       root       75: 
                     76:        // SR0 は b0,1 が '0'、b2,6 が '1'、残りは不定
                     77:        chan->sr0 &= ~(SIO::SR0_INTPEND | SIO::SR0_RXAVAIL);
                     78:        chan->sr0 |= (SIO::SR0_TXUNDER | SIO::SR0_TXEMPTY);
                     79: 
                     80:        // SR1 は b4-7 が '0'
                     81:        chan->sr1 &= ~(SIO::SR1_ENDOFFRAME | SIO::SR1_CRCERROR |
                     82:                       SIO::SR1_RXOVERRUN | SIO::SR1_PARITYERROR);
                     83: 
1.1.1.5   root       84:        // 内部状態をリセット
1.1       root       85:        chan->es_ratched = false;
1.1.1.9 ! root       86:        chan->txint = false;
1.1       root       87: 
                     88:        // 受信バッファをクリア
                     89:        memset(chan->rxbuf, 0, sizeof(chan->rxbuf));
                     90:        chan->rxlen = 0;
1.1.1.9 ! root       91: 
        !            92:        chan->txbuf = 0;
        !            93:        chan->txlen = 0;
        !            94:        chan->tx_shiftreg = 0;
        !            95:        // 送信の停止
        !            96:        // XXX 送信途中のデータをぶちきることはサポートしない
        !            97:        txevent[chan->id].Stop();
        !            98: 
        !            99:        ChangeInterrupt();
        !           100: }
        !           101: 
        !           102: // CR(WR) レジスタ名を返す。uPD7201 では CRn のほうが通りがいい。
        !           103: const char *
        !           104: uPD7201Device::CRName(const SIO::channel *chan, int ptr_) const
        !           105: {
        !           106:        assert(ptr_ < 8);
        !           107:        int idx = ptr_ * 2 + chan->id;
        !           108:        assert(idx < countof(crnames));
        !           109:        return crnames[idx];
        !           110: }
        !           111: 
        !           112: // SR(RR) レジスタ名を返す。uPD7201 では SRn のほうが通りがいい。
        !           113: const char *
        !           114: uPD7201Device::SRName(const SIO::channel *chan, int ptr_) const
        !           115: {
        !           116:        assert(ptr_ < 8);
        !           117:        int idx = ptr_ * 2 + chan->id;
        !           118:        assert(idx < countof(srnames));
        !           119:        return srnames[idx];
1.1       root      120: }
                    121: 
                    122: // 制御ポートの読み込み
                    123: uint8
1.1.1.9 ! root      124: uPD7201Device::ReadCtrl(SIO::channel *chan)
1.1       root      125: {
                    126:        uint8 data;
                    127: 
                    128:        switch (chan->ptr) {
                    129:         case 0:        // SR0
1.1.1.5   root      130:                data = chan->sr0;
1.1.1.9 ! root      131:                putlog(2, "%s -> $%02x", SRName(chan), data);
1.1       root      132:                // アクセス後は SR0 へ戻す
                    133:                chan->ptr = 0;
                    134:                break;
                    135: 
                    136:         case 1:        // SR1
1.1.1.5   root      137:                data = chan->sr1;
1.1.1.9 ! root      138:                putlog(2, "%s -> $%02x", SRName(chan), data);
1.1       root      139:                // アクセス後は SR0 へ戻す
                    140:                chan->ptr = 0;
                    141:                break;
                    142: 
                    143:         case 2:
                    144:                // SR2B はベクタの読み出し
                    145:                if (chan->id == 1) {
                    146:                        data = cr.vector;
1.1.1.9 ! root      147:                        putlog(2, "%s -> $%02x", SRName(chan), data);
1.1       root      148:                        // アクセス後は SR0 へ戻す
                    149:                        chan->ptr = 0;
                    150:                        break;
                    151:                }
                    152: 
                    153:                // SR2A はない
                    154:                FALLTHROUGH;
                    155: 
                    156:         default:
1.1.1.9 ! root      157:                putlog(0, "未実装レジスタ読み込み %s", SRName(chan));
1.1       root      158:                // SR0 へ戻る?
                    159:                chan->ptr = 0;
                    160:                return 0xff;
                    161:        }
                    162:        return data;
                    163: }
                    164: 
                    165: // 制御ポートの書き込み
                    166: void
1.1.1.9 ! root      167: uPD7201Device::WriteCtrl(SIO::channel *chan, uint32 data)
1.1       root      168: {
1.1.1.5   root      169:        // CR0 はコマンドかまたは次にアクセスするレジスタを指定する。
                    170:        // CR0 以外のレジスタをアクセスすると、次のアクセスは CR0 に戻る。
1.1       root      171: 
1.1.1.5   root      172:        if (chan->ptr == 0) {
                    173:                WriteCR0(chan, data);
                    174:        } else {
                    175:                switch (chan->ptr) {
                    176:                 case 1:
                    177:                        WriteCR1(chan, data);
1.1       root      178:                        break;
1.1.1.5   root      179:                 case 2:
                    180:                        WriteCR2(chan, data);
1.1       root      181:                        break;
1.1.1.5   root      182:                 case 3:
                    183:                        WriteCR3(chan, data);
1.1       root      184:                        break;
1.1.1.5   root      185:                 case 4:
                    186:                        WriteCR4(chan, data);
1.1       root      187:                        break;
1.1.1.5   root      188:                 case 5:
                    189:                        WriteCR5(chan, data);
1.1       root      190:                        break;
1.1.1.5   root      191:                 case 6:
                    192:                        WriteCR6(chan, data);
1.1       root      193:                        break;
1.1.1.5   root      194:                 case 7:
                    195:                        WriteCR7(chan, data);
1.1       root      196:                        break;
                    197:                 default:
1.1.1.9 ! root      198:                        __unreachable();
1.1       root      199:                }
                    200:                // アクセス後は CR0 へ戻す
                    201:                chan->ptr = 0;
                    202:        }
                    203: }
                    204: 
1.1.1.2   root      205: // 制御ポートの Peek
                    206: uint8
1.1.1.9 ! root      207: uPD7201Device::PeekCtrl(const SIO::channel *chan) const
1.1.1.2   root      208: {
                    209:        switch (chan->ptr) {
                    210:         case 0:        // SR0
1.1.1.5   root      211:                return chan->sr0;
1.1.1.2   root      212: 
                    213:         case 1:        // SR1
1.1.1.5   root      214:                return chan->sr1;
1.1.1.2   root      215: 
                    216:         case 2:        // SR2
                    217:                // SR2A はない。SR2B はベクタの読み出し
                    218:                if (chan->id == 1) {
                    219:                        return cr.vector;
                    220:                }
                    221:                FALLTHROUGH;
                    222: 
                    223:         default:
                    224:                // 未調査
                    225:                return 0xff;
                    226:        }
                    227: }
                    228: 
1.1.1.5   root      229: // CR0 への書き込み
1.1.1.9 ! root      230: // Z8530 の WR0 とは微妙に互換性がなく、scc.cpp に似た別物があるので注意。
1.1.1.5   root      231: void
1.1.1.9 ! root      232: uPD7201Device::WriteCR0(SIO::channel *chan, uint32 data)
1.1.1.2   root      233: {
1.1.1.5   root      234:        uint cmd;
1.1.1.2   root      235: 
1.1.1.5   root      236:        // XXX b7,b6 は未対応。
                    237:        // b5,b4,b3 がコマンド。
                    238:        // b2,b1,b0 が次にアクセスするレジスタ(chan->ptr)の切り替え。
                    239:        chan->cr0 = data;
                    240:        chan->ptr = (chan->cr0 & SIO::CR0_PTR);
                    241: 
                    242:        cmd = (chan->cr0 & SIO::CR0_CMD) >> 3;
                    243:        if (cmd == 0) {
                    244:                // コマンド0 ならレジスタ切り替え
1.1.1.9 ! root      245:                putlog(3, "%s <- $%02x (ptr=%d)", CRName(chan, 0), data, chan->ptr);
1.1.1.5   root      246:        } else {
                    247:                // 0 以外ならコマンド発行
1.1.1.9 ! root      248:                putlog(2, "%s <- $%02x", CRName(chan, 0), data);
1.1.1.5   root      249:        }
                    250:        switch (cmd) {
                    251:         case 0:        // No operation
                    252:                break;
                    253:         case 1:        // Send Abort
1.1.1.9 ! root      254:                SendAbort(chan);
1.1.1.5   root      255:                break;
                    256:         case 2:        // Reset External/Status Interrupt
1.1.1.9 ! root      257:                ResetESIntr(chan);
1.1.1.5   root      258:                break;
                    259:         case 3:        // Channel Reset
                    260:                ResetChannel(chan);
                    261:                break;
                    262:         case 4:        // Enable Interrupt On Next Receive Character
1.1.1.9 ! root      263:                EnableIntrOnNextRx(chan);
1.1.1.5   root      264:                break;
                    265:         case 5:        // Reset Transmitter Interrupt/DMA Pending
1.1.1.9 ! root      266:                ResetTxIntrPending(chan);
1.1.1.5   root      267:                break;
                    268:         case 6:        // Error Reset
1.1.1.9 ! root      269:                ErrorReset(chan);
        !           270:                break;
1.1.1.5   root      271:         case 7:        // End of Interrupt
1.1.1.9 ! root      272:                // uPD7201 ではチャンネル A のみ有効。
        !           273:                // (チャンネル B でどうなるかは書いてない)
        !           274:                if (chan->id == 0) {
        !           275:                        ResetHighestIUS(chan);
        !           276:                } else {
        !           277:                        putlog(0, "%s: End of Intterupt 未定義", CRName(chan, 0));
        !           278:                }
1.1.1.5   root      279:                break;
                    280:         default:
                    281:                __unreachable();
1.1.1.2   root      282:        }
                    283: }
                    284: 
1.1.1.9 ! root      285: // CR0(WR0) Send Abort コマンド
        !           286: void
        !           287: uPD7201Device::SendAbort(SIO::channel *chan)
        !           288: {
        !           289:        if (chan->mode == SIO::Mode::HDLC) {
        !           290:                putlog(0, "%s: Send Abort 未実装", CRName(chan, 0));
        !           291:        } else {
        !           292:                // XXX Send Abort コマンドは「HDLC モードのみ有効」と書いて
        !           293:                //     あるがそれ以外の時にどうなるか不明。
        !           294:                uint cmd = (chan->cr0 & SIO::CR0_CMD) >> 3;
        !           295:                putlog(0, "%s: 未定義コマンド %d", CRName(chan, 0), cmd);
        !           296:        }
        !           297: }
        !           298: 
        !           299: // CR0(WR0) Reset External/Status Interrupt コマンド
        !           300: void
        !           301: uPD7201Device::ResetESIntr(SIO::channel *chan)
        !           302: {
        !           303:        putlog(3, "%s: Reset E/S Interrupt", CRName(chan, 0));
        !           304:        chan->es_ratched = false;
        !           305: }
        !           306: 
        !           307: // CR0(WR0) Enable Interrupt on Next Rx Character コマンド
        !           308: void
        !           309: uPD7201Device::EnableIntrOnNextRx(SIO::channel *chan)
        !           310: {
        !           311:        putlog(0, "%s: Enable Intr on Next Rx Character 未実装", CRName(chan, 0));
        !           312: }
        !           313: 
        !           314: // CR0(WR0) Reset Tx Interrupt/DMA Pending コマンド
        !           315: void
        !           316: uPD7201Device::ResetTxIntrPending(SIO::channel *chan)
        !           317: {
        !           318:        putlog(1, "%s: Reset Tx Intr/DMA Pending", CRName(chan, 0));
        !           319:        chan->txint = false;
        !           320:        ChangeInterrupt();
        !           321: }
        !           322: 
        !           323: // CR0(WR0) Error Reset コマンド
        !           324: void
        !           325: uPD7201Device::ErrorReset(SIO::channel *chan)
        !           326: {
        !           327:        putlog(1, "%s: Error Reset", CRName(chan, 0));
        !           328:        chan->sr1 &= ~(SIO::SR1_ENDOFFRAME | SIO::SR1_CRCERROR |
        !           329:                       SIO::SR1_RXOVERRUN | SIO::SR1_PARITYERROR);
        !           330:        // XXX Special Rx Condition は未実装
        !           331: }
        !           332: 
        !           333: // CR0 End of Interrupt コマンド
        !           334: // WR0 Reset Highest IUS コマンド
        !           335: // たぶん名前が違うだけで同じ。後者のほうが分かりやすいのでこっちを使う
        !           336: void
        !           337: uPD7201Device::ResetHighestIUS(SIO::channel *chan)
        !           338: {
        !           339:        putlog(0, "%s: Reset Highest IUS 未実装", CRName(chan, 0));
        !           340: }
        !           341: 
1.1.1.5   root      342: // CR1 への書き込み
                    343: void
1.1.1.9 ! root      344: uPD7201Device::WriteCR1(SIO::channel *chan, uint32 data)
1.1.1.2   root      345: {
1.1.1.9 ! root      346:        putlog(2, "%s <- $%02x", CRName(chan), data);
1.1.1.5   root      347: 
                    348:        chan->cr1 = data;
                    349: 
                    350:        // RXINT モードで all_or_first の値(初期値)を用意。
                    351:        // DISABLE なら(使わないのでどっちでもいいはずだけど一応) false にしとく。
                    352:        // FIRSTCHAR なら初期状態が true。ALL_* なら常時 true。
                    353:        chan->all_or_first = ((chan->cr1 & SIO::CR1_RXINT) != SIO::RXINT_DISABLE);
1.1.1.2   root      354: }
                    355: 
1.1.1.5   root      356: // CR2 への書き込み
                    357: void
1.1.1.9 ! root      358: uPD7201Device::WriteCR2(SIO::channel *chan, uint32 data)
1.1.1.5   root      359: {
                    360:        if (chan->id == 0) {    // CR2A
1.1.1.9 ! root      361:                putlog(2, "%s <- $%02x 書き込み(b7,b2-0未実装)", CRName(chan), data);
1.1.1.5   root      362:                cr.cr2a = data;
                    363:        } else {                                // CR2B
1.1.1.9 ! root      364:                putlog(2, "%s <- $%02x (Set vector)", CRName(chan), data);
1.1.1.5   root      365:                cr.vector = data;
                    366:        }
                    367: }
                    368: 
                    369: // CR3 への書き込み
                    370: void
1.1.1.9 ! root      371: uPD7201Device::WriteCR3(SIO::channel *chan, uint32 data)
1.1.1.5   root      372: {
1.1.1.9 ! root      373:        uint8 oldcr3;
        !           374: 
        !           375:        oldcr3 = chan->cr3;
1.1.1.5   root      376:        chan->cr3 = data;
                    377: 
1.1.1.9 ! root      378:        putlog(2, "%s <- $%02x", CRName(chan), data);
        !           379: 
        !           380:        // Disable は Disable に変化した時だけ表示
        !           381:        if ((oldcr3 & SIO::CR3_RX_EN) != 0 && (chan->cr3 & SIO::CR3_RX_EN) == 0) {
        !           382:                putlog(1, "Channel %s RX Disable", chan->name);
        !           383:        }
        !           384:        // Enable はパラメータ変更があるかもなので常に表示
        !           385:        if ((chan->cr3 & SIO::CR3_RX_EN)) {
        !           386:                putlog(1, "Channel %s RX Enable, %d bits/frame",
        !           387:                        chan->name,
        !           388:                        bits_per_char[(chan->cr3 & SIO::CR3_RXBITS) >> 6]);
        !           389:        }
1.1.1.5   root      390: }
                    391: 
                    392: // CR4 への書き込み
                    393: void
1.1.1.9 ! root      394: uPD7201Device::WriteCR4(SIO::channel *chan, uint32 data)
1.1.1.5   root      395: {
                    396:        chan->cr4 = data;
1.1.1.9 ! root      397:        putlog(2, "%s <- $%02x", CRName(chan), data);
1.1.1.5   root      398:        uint8 stopbits = (chan->cr4 & SIO::CR4_STOPBITS);
                    399:        uint8 syncmode = (chan->cr4 & SIO::CR4_SYNCMODE);
                    400: 
1.1.1.9 ! root      401:        // TODO: 優先順位逆じゃない?
        !           402: 
1.1.1.5   root      403:        // モード分け、優先順位は分からない
                    404:        if (stopbits == SIO::SYNC_MODE) {
                    405:                if (syncmode == SIO::SYNC_HDLC) {
                    406:                        chan->mode = SIO::Mode::HDLC;
                    407:                        putlog(2, "Channel %s HDLC Mode", chan->name);
                    408:                } else {
                    409:                        chan->mode = SIO::Mode::SYNC;
                    410:                        const char *sm[] = { "8bit", "16bit", "HDLC?", "Ext" };
                    411:                        putlog(2, "Channel %s Sync (%s) Mode",
                    412:                                chan->name, sm[syncmode >> 4]);
                    413:                }
                    414:        } else {
                    415:                chan->mode = SIO::Mode::ASYNC;
                    416:                const char *sm[] = { "?", "1", "1.5", "2" };
1.1.1.9 ! root      417:                putlog(2, "Channel %s Async (x%d clock, stopbit %s) Mode",
1.1.1.5   root      418:                        chan->name,
1.1.1.9 ! root      419:                        clkrate[(chan->cr4 & SIO::CR4_CLKRATE) >> 6],
1.1.1.5   root      420:                        sm[stopbits >> 2]);
                    421:        }
1.1.1.9 ! root      422: 
        !           423:        SetTXPeriod(chan);
1.1.1.5   root      424: }
                    425: 
                    426: // CR5 への書き込み
                    427: void
1.1.1.9 ! root      428: uPD7201Device::WriteCR5(SIO::channel *chan, uint32 data)
1.1.1.5   root      429: {
1.1.1.9 ! root      430:        uint8 oldcr5;
        !           431: 
        !           432:        oldcr5 = chan->cr5;
1.1.1.5   root      433:        chan->cr5 = data;
                    434: 
1.1.1.9 ! root      435:        putlog(2, "%s <- $%02x", CRName(chan), data);
        !           436: 
        !           437:        // Disable は Disable に変化した時だけ表示
        !           438:        // (Enable は SetTXPeriod() 内で表示)
        !           439:        if ((oldcr5 & SIO::CR5_TX_EN) != 0 && (chan->cr5 & SIO::CR5_TX_EN) == 0) {
        !           440:                putlog(1, "Channel %s TX Disable", chan->name);
        !           441:        }
        !           442: 
        !           443:        SetTXPeriod(chan);
        !           444:        TrySend(chan);
1.1.1.5   root      445: }
                    446: 
                    447: // CR6 への書き込み
                    448: void
1.1.1.9 ! root      449: uPD7201Device::WriteCR6(SIO::channel *chan, uint32 data)
1.1.1.5   root      450: {
                    451:        chan->cr6 = data;
                    452: 
1.1.1.9 ! root      453:        putlog(0, "%s <- $%02x 書き込み(未実装)", CRName(chan), data);
1.1.1.5   root      454: }
                    455: 
                    456: // CR7 への書き込み
                    457: void
1.1.1.9 ! root      458: uPD7201Device::WriteCR7(SIO::channel *chan, uint32 data)
1.1.1.5   root      459: {
                    460:        chan->cr7 = data;
                    461: 
1.1.1.9 ! root      462:        putlog(0, "%s <- $%02x 書き込み(未実装)", CRName(chan), data);
1.1.1.5   root      463: }
1.1.1.2   root      464: 
1.1       root      465: // データポートの読み込み
                    466: uint8
1.1.1.9 ! root      467: uPD7201Device::ReadData(SIO::channel *chan)
1.1       root      468: {
                    469:        uint8 data;
                    470: 
                    471:        if (chan->rxlen > 0) {
                    472:                data = chan->rxbuf[0];
1.1.1.5   root      473:                putlog(3, "Ch%s Data -> $%02x", chan->name, data);
1.1       root      474:                chan->rxlen--;
1.1.1.5   root      475:                if (chan->rxlen == 0) {
                    476:                        // 取り出して空になった
                    477:                        chan->sr0 &= ~SIO::SR0_RXAVAIL;
                    478:                        ChangeInterrupt();
                    479:                } else {
1.1.1.6   root      480:                        chan->rxbuf[0] = chan->rxbuf[1];
                    481:                        chan->rxbuf[1] = chan->rxbuf[2];
1.1       root      482:                }
                    483:        } else {
                    484:                // XXX 何が読めるか
                    485:                data = 0xff;
1.1.1.5   root      486:                putlog(3, "Ch%s Data -> $%02x (Empty)", chan->name, data);
1.1       root      487:        }
                    488: 
                    489:        return data;
                    490: }
                    491: 
                    492: // データポートの書き込み
                    493: void
1.1.1.9 ! root      494: uPD7201Device::WriteData(SIO::channel *chan, uint32 data)
1.1       root      495: {
                    496:        char charbuf[4];
                    497: 
                    498:        if (isprint((int)data)) {
                    499:                snprintf(charbuf, sizeof(charbuf), "'%c'", data);
                    500:        } else {
                    501:                charbuf[0] = '\0';
                    502:        }
1.1.1.5   root      503:        putlog(3, "Ch%s Data <- $%02x %s", chan->name, data, charbuf);
1.1       root      504: 
1.1.1.9 ! root      505:        // XXX: EMPTY でないときにデータを書いたらどうなるかは未定義
1.1       root      506: 
1.1.1.9 ! root      507:        // 1byte の TX Buffer
        !           508:        chan->txlen = 1;
        !           509:        chan->txbuf = data;
        !           510:        chan->sr0 &= ~SIO::SR0_TXEMPTY;
        !           511: 
        !           512:        // TX 割り込みのクリア
        !           513:        chan->txint = false;
        !           514:        ChangeInterrupt();
        !           515: 
        !           516:        TrySend(chan);
        !           517: }
        !           518: 
        !           519: // 送信できるか調べて送信する
        !           520: void
        !           521: uPD7201Device::TrySend(SIO::channel *chan)
        !           522: {
        !           523:        if ((chan->cr5 & SIO::CR5_TX_EN) == false) {
        !           524:                // 送信可でなければなにもしない
        !           525:                return;
        !           526:        }
        !           527:        if (chan->txlen == 0) {
        !           528:                // 送信バッファが空なら何もしない
        !           529:                return;
        !           530:        }
        !           531:        if (txevent[chan->id].IsRunning()) {
        !           532:                // 送信中なので何もしない
        !           533:                return;
        !           534:        }
        !           535: 
        !           536:        // 送信する
        !           537:        chan->tx_shiftreg = chan->txbuf;
        !           538:        txevent[chan->id].Start();
        !           539:        putlog(2, "Ch%s sending $%02x", chan->name, chan->tx_shiftreg);
        !           540:        chan->txlen = 0;
1.1       root      541: 
1.1.1.9 ! root      542:        // XXX たぶん送信してから割り込みを上げるまでにいくらか遅れがあるはず
        !           543: 
        !           544:        // 送信割り込み
        !           545:        chan->sr0 |= SIO::SR0_TXEMPTY;
        !           546:        chan->txint = true;
1.1.1.5   root      547:        ChangeInterrupt();
1.1       root      548: }
                    549: 
1.1.1.9 ! root      550: // 送信のイベントコールバック
        !           551: void
        !           552: uPD7201Device::TXCallback(Event& event)
        !           553: {
        !           554:        int ch = event.code;
        !           555:        SIO::channel *chan = &cr.chan[ch];
        !           556: 
        !           557:        // 接続デバイスの呼び出し
        !           558:        Tx(ch, chan->tx_shiftreg);
        !           559: 
        !           560:        // 次の送信データが来てたら送信
        !           561:        TrySend(chan);
        !           562: }
        !           563: 
1.1.1.2   root      564: // データポートの Peek
                    565: uint8
1.1.1.9 ! root      566: uPD7201Device::PeekData(const SIO::channel *chan) const
1.1.1.2   root      567: {
                    568:        if (chan->rxlen > 0) {
                    569:                // 受信バッファにデータがあれば先頭バイトが見える
                    570:                return chan->rxbuf[0];
                    571:        } else {
                    572:                // 空の時は?
                    573:                return 0xff;
                    574:        }
                    575: }
                    576: 
1.1.1.3   root      577: // TX/RX の bits/char のレジスタ値を実際の bits/char の値に変換する。
1.1.1.9 ! root      578: /*static*/ const int
1.1       root      579: uPD7201Device::bits_per_char[] = { 5, 7, 6, 8 };
                    580: 
1.1.1.9 ! root      581: // CR4 CLKRATE のレジスタ値を実際の倍率に変換する。
        !           582: /*static*/ const int
        !           583: uPD7201Device::clkrate[] = { 1, 16, 32, 64 };
        !           584: 
1.1       root      585: // 1バイト受信する。
                    586: // 受理されれば true を返す。
                    587: bool
                    588: uPD7201Device::Rx(int ch, uint32 data)
                    589: {
1.1.1.9 ! root      590:        SIO::channel *chan = &cr.chan[ch];
1.1       root      591: 
                    592:        // Rx Enable でなければ受け取らない?
                    593:        if ((chan->cr3 & SIO::CR3_RX_EN) == 0) {
                    594:                return false;
                    595:        }
                    596: 
1.1.1.5   root      597:        // 1バイトでもあれば有効
                    598:        chan->sr0 |= SIO::SR0_RXAVAIL;
                    599: 
1.1       root      600:        // バッファが一杯なら Rx Overrun Error
                    601:        if (chan->rxlen == sizeof(chan->rxbuf)) {
                    602:                putlog(2, "Rx Overrun");
                    603:                chan->sr1 |= SIO::SR1_RXOVERRUN;
1.1.1.5   root      604:                // XXX special Rx condition interrupt occurs
1.1       root      605:                return false;
                    606:        }
                    607: 
                    608:        // 受信
                    609:        chan->rxbuf[chan->rxlen++] = data;
                    610: 
1.1.1.5   root      611:        // 割り込み状態を変更
                    612:        ChangeInterrupt();
                    613: 
                    614:        return true;
                    615: }
                    616: 
1.1.1.9 ! root      617: static double
        !           618: to_freq(uint64 nsec)
        !           619: {
        !           620:        return (double)1.0 / nsec * 1e9;
        !           621: }
        !           622: 
        !           623: // 送信イベントの時間を設定する (CR4, CR5 の変更で呼ぶ)
        !           624: void
        !           625: uPD7201Device::SetTXPeriod(SIO::channel *chan)
        !           626: {
        !           627:        uint64 bit12_ns;
        !           628:        int bit;
        !           629: 
        !           630:        // 誤差を減らすため 12bit 単位が基準
        !           631:        // 12bit 時間
        !           632:        bit12_ns = txc12_ns * clkrate[(chan->cr4 & SIO::CR4_CLKRATE) >> 6];
        !           633: 
        !           634:        // start bit
        !           635:        bit = 1;
        !           636: 
        !           637:        // data bit
        !           638:        bit += bits_per_char[(chan->cr5 & SIO::CR5_TXBITS) >> 5];
        !           639: 
        !           640:        // parity bit
        !           641:        bit += (chan->cr4 & SIO::CR4_PARITY_EN) ? 1 : 0;
        !           642: 
        !           643:        switch (chan->cr4 & SIO::CR4_STOPBITS) {
        !           644:         case 0:
        !           645:                // 非同期モードでの STOPBITS 0 は未定義 (Enable ならログ表示)
        !           646:                if ((chan->cr5 & SIO::CR5_TX_EN)) {
        !           647:                        putlog(0, "%s 未定義ストップビット長 0", CRName(chan, 4));
        !           648:                }
        !           649:                break;
        !           650:         case SIO::STOP_BITS_1:
        !           651:                bit += 1;
        !           652:                break;
        !           653:         case SIO::STOP_BITS_1_5:
        !           654:                // サポートしない (Enable ならログ表示)
        !           655:                if ((chan->cr5 & SIO::CR5_TX_EN)) {
        !           656:                        putlog(0, "%s 未実装ストップビット長 1.5", CRName(chan, 4));
        !           657:                }
        !           658:                break;
        !           659:         case SIO::STOP_BITS_2:
        !           660:                bit += 2;
        !           661:                break;
        !           662:        }
        !           663: 
        !           664:        txevent[chan->id].time = bit * bit12_ns / 12;
        !           665: 
        !           666:        // TX Enable (CR5) ならパラメータを含めて表示
        !           667:        if ((chan->cr5 & SIO::CR5_TX_EN)) {
        !           668:                std::string nsstr;
        !           669:                if (loglevel >= 2) {
        !           670:                        nsstr = string_format(" (%" PRIu64 ")", bit12_ns);
        !           671:                }
        !           672:                putlog(1, "Channel %s TX Enable, %.1f baud%s, %d bits/frame",
        !           673:                        chan->name,
        !           674:                        (double)to_freq(bit12_ns) * 12,
        !           675:                        nsstr.c_str(),
        !           676:                        bit);
        !           677:        }
        !           678: }
        !           679: 
1.1.1.5   root      680: // 割り込み状態を変更
                    681: void
                    682: uPD7201Device::ChangeInterrupt()
                    683: {
                    684:        uint int_asserted = 0;
                    685: 
                    686:        for (int ch = 0; ch < 2; ch++) {
1.1.1.9 ! root      687:                SIO::channel *chan = &cr.chan[ch];
1.1.1.5   root      688: 
                    689:                // Rx
                    690:                bool rx_avail = (chan->rxlen > 0) && chan->all_or_first;
                    691:                // Special Rx
                    692:                bool special = false;   // XXX not yet
                    693: 
                    694:                bool rx_enable = (chan->cr3 & SIO::CR3_RX_EN);
                    695:                bool rx_int = (rx_enable && (rx_avail || special));
                    696: 
                    697:                // FirstChar モードなら1文字受信割り込み後にフラグを下ろす
                    698:                // (Rx 割り込み用の変数 rx_int が確定したここで行う)
                    699:                if ((chan->cr1 & SIO::CR1_RXINT) == SIO::RXINT_FIRSTCHAR) {
                    700:                        chan->all_or_first = false;
1.1       root      701:                }
1.1.1.5   root      702: 
                    703:                // XXX E/S not yet
                    704: 
                    705:                // Tx
                    706:                bool tx_enable = (chan->cr1 & SIO::CR1_TXINT_EN);
1.1.1.9 ! root      707:                bool tx_int = tx_enable && chan->txint;
1.1.1.5   root      708: 
                    709:                // 4つの要因の合成
                    710:                chan->int_asserted = 0;
                    711:                chan->int_asserted |= tx_int ? SIO::INTR_TX : 0;
                    712:                chan->int_asserted |= rx_int ? SIO::INTR_RX : 0;
                    713: 
                    714:                // 両方のチャンネル分を合成
                    715:                int_asserted |= chan->int_asserted;
1.1       root      716:        }
                    717: 
1.1.1.5   root      718:        gInterrupt->ChangeINT(this, int_asserted);
1.1       root      719: }
                    720: 
                    721: // モニター
1.1.1.4   root      722: void
1.1.1.7   root      723: uPD7201Device::MonitorUpdate(Monitor *, TextScreen& screen)
1.1       root      724: {
1.1.1.5   root      725:        int y;
                    726: 
1.1.1.7   root      727:        screen.Clear();
1.1       root      728:        for (int i = 0; i < 2; i++) {
                    729:                int x = 0;
1.1.1.5   root      730:                y = i * 10;
1.1.1.7   root      731:                MonitorUpdateCh(screen, i, x, y);
1.1       root      732:        }
1.1.1.5   root      733: 
                    734:        // CR2A
                    735:        uint cr2a = cr.cr2a;
                    736:        y = 20;
1.1.1.7   root      737:        screen.Print(0, y, "CR2A:$%02x", cr2a);
1.1.1.5   root      738:        if ((cr2a & 0x80)) {
1.1.1.7   root      739:                screen.Print(9, y, TA::On, "SYNC");
1.1.1.5   root      740:        } else {
1.1.1.7   root      741:                screen.Print(9, y, "RTSB");
1.1.1.5   root      742:        }
1.1.1.8   root      743:        screen.Print(14, y, TA::Disable, "----");
1.1.1.7   root      744:        screen.Print(19, y, TA::OnOff((cr2a & 0x20)), "Vect");
1.1.1.5   root      745:        if ((cr2a & 0x18) == 0x10) {
1.1.1.7   root      746:                screen.Print(24, y, "IM=V4-V2");
1.1.1.5   root      747:        } else {
1.1.1.7   root      748:                screen.Print(24, y, "IM=V2-V0");
1.1.1.5   root      749:        }
                    750:        // bit2 (Priority Select) は bit0 が 0 の時だけ意味があるようだ
                    751:        if ((cr2a & 0x01) == 0) {
                    752:                if ((cr2a & 0x04)) {
1.1.1.7   root      753:                        screen.Print(34, y, "RxTx");
1.1.1.5   root      754:                } else {
1.1.1.7   root      755:                        screen.Print(34, y, "A->B");
1.1.1.5   root      756:                }
                    757:        }
                    758:        // bit1,0 はよく分からん
1.1.1.7   root      759:        screen.Print(39, y, "INT/DMA=%d", (cr2a & 0x3));
1.1.1.5   root      760:        y++;
                    761: 
                    762:        // CR2B
1.1.1.7   root      763:        screen.Print(0, y, "CR2B:$%02x", cr.vector);
1.1       root      764: }
                    765: 
                    766: // モニター (1チャンネル)
                    767: void
1.1.1.7   root      768: uPD7201Device::MonitorUpdateCh(TextScreen& screen,
1.1.1.4   root      769:        int ch, int xbase, int ybase)
1.1       root      770: {
1.1.1.9 ! root      771:        SIO::channel *chan = &cr.chan[ch];
1.1       root      772:        uint cr0;
                    773:        uint cr1;
                    774:        uint cr3;
                    775:        uint cr4;
                    776:        uint cr5;
                    777:        uint sr0;
                    778:        uint sr1;
                    779:        uint rxlen;
                    780:        int x;
                    781:        int y;
                    782: 
1.1.1.5   root      783:        cr0 = (chan->cr0 & ~SIO::CR0_PTR) | chan->ptr;
1.1       root      784:        cr1 = chan->cr1;
                    785:        cr3 = chan->cr3;
                    786:        cr4 = chan->cr4;
                    787:        cr5 = chan->cr5;
                    788:        sr0 = chan->sr0;
                    789:        sr1 = chan->sr1;
                    790:        rxlen = chan->rxlen;
                    791: 
                    792:        // 0         1         2         3         4         5         6
                    793:        // 012345678901234567890123456789012345678901234567890123456789012345
                    794:        //          0123 0123 0123 0123 0123 0123 0123 0123
1.1.1.5   root      795:        // CR0: $xx CRC=x     CMD=x          PTR=x
                    796:        // CR1: $xx WE   0    WR   RXInt=x   0    TXEn ESEn
                    797:        // RXBuf: 0 --- --- ---           Intr: Rx Sp Tx ES
1.1       root      798: 
                    799:        x = xbase;
                    800:        y = ybase;
1.1.1.7   root      801:        screen.Print(x, y++, "Channel %s: %s", chan->name, chan->desc);
                    802:        screen.Print(x, y++, "CR0: $%02x", cr0);
                    803:        screen.Print(x, y++, "CR1: $%02x", cr1);
                    804:        screen.Print(x, y++, "CR3: $%02x", cr3);
                    805:        screen.Print(x, y++, "CR4: $%02x", cr4);
                    806:        screen.Print(x, y++, "CR5: $%02x", cr5);
                    807:        screen.Print(x, y++, "SR0: $%02x", sr0);
                    808:        screen.Print(x, y++, "SR1: $%02x", sr1);
                    809:        screen.Print(x, y,   "RXbuf: %d", rxlen);
1.1       root      810:        int i;
                    811:        for (i = 0; i < rxlen; i++) {
1.1.1.7   root      812:                screen.Print(x + 9 + i * 4, y, "$%02x", chan->rxbuf[i]);
1.1       root      813:        }
                    814:        for (; i < sizeof(chan->rxbuf); i++) {
1.1.1.7   root      815:                screen.Print(x + 9 + i * 4, y, "---");
1.1       root      816:        }
1.1.1.5   root      817:        // 内部割り込み状態
1.1.1.7   root      818:        screen.Print(31, y, "Intr:");
                    819:        screen.Print(37, y, TA::OnOff(chan->int_asserted & SIO::INTR_RX), "Rx");
                    820:        screen.Print(40, y, TA::OnOff(chan->int_asserted & SIO::INTR_SP), "SP");
                    821:        screen.Print(43, y, TA::OnOff(chan->int_asserted & SIO::INTR_TX), "Tx");
                    822:        screen.Print(46, y, TA::OnOff(chan->int_asserted & SIO::INTR_ES), "ES");
1.1       root      823: 
                    824:        y = ybase + 1;
                    825:        x = xbase;
                    826:        // CR0
1.1.1.7   root      827:        screen.Print(x + 9, y, "CRC=%d", (cr0 >> 6));
1.1       root      828:        static const char * const cmd_str[] = {
                    829:        //   0123456789012345
                    830:                "No operation",
                    831:                "Send Abort",
                    832:                "Reset E/S Int",
                    833:                "Channel Reset",
                    834:                "Enable IntNextCh",
                    835:                "Reset TxIntPend",
                    836:                "Error Reset",
                    837:                "End of Interrupt",
                    838:        };
                    839:        uint cmd = (cr0 >> 3) & 7;
1.1.1.7   root      840:        screen.Print(x + 19, y, "CMD=%d(%s)", cmd, cmd_str[cmd]);
                    841:        screen.Print(x + 43, y, "PTR=%d", (cr0 & 7));
1.1       root      842:        y++;
                    843: 
                    844:        // CR1
                    845:        static const char * const cr1_str[] = {
1.1.1.9 ! root      846:                "Wait", "-", "", "", "", "VMod", "TxIE", "ESIE"
1.1       root      847:        };
1.1.1.7   root      848:        MonitorReg(screen, x + 9, y, cr1, cr1_str);
1.1.1.9 ! root      849:        if ((cr1 & SIO::CR1_WAIT_EN)) {
        !           850:                screen.Puts(x + 19, y, ((cr1 & SIO::CR1_WAIT_RX) ? "OnRx" : "OnTx"));
        !           851:        } else {
        !           852:                screen.Puts(x + 19, y, TA::Disable, "TxRx");
        !           853:        }
        !           854:        screen.Print(x + 24, y, "RxIntMod%d", (cr1 >> 3) & 3);
        !           855:        // CR1 の bit2 (Modified Vector) は CR1B のみ。
        !           856:        if (ch == 0) {
        !           857:                screen.Puts(x + 34, y, TA::Disable, "----");
        !           858:        }
1.1       root      859:        y++;
                    860: 
                    861:        // CR3
                    862:        static const char * const cr3_str[] = {
1.1.1.9 ! root      863:                "", "", "Auto", "-", "-", "-", "-", "RxEn"
1.1       root      864:        };
1.1.1.7   root      865:        MonitorReg(screen, x + 9, y, cr3, cr3_str);
1.1.1.9 ! root      866:        screen.Print(x + 9, y, "RxBits=%d", 5 + ((cr3 >> 6) & 3));
1.1       root      867:        y++;
                    868: 
                    869:        // CR4
                    870:        static const char * const cr4_str[] = {
                    871:                "", "", "", "", "", "", "PaEv", "PaEn"
                    872:        };
1.1.1.7   root      873:        MonitorReg(screen, x + 9, y, cr4, cr4_str);
1.1       root      874: 
                    875:        static const char * const clkrate_str[] = {
                    876:                "1", "16", "32", "64"
                    877:        };
1.1.1.7   root      878:        screen.Print(x + 9, y, "Rate=x%s", clkrate_str[(cr4 >> 6) & 3]);
1.1       root      879:        static const char * const syncmode_str[] = {
                    880:                "Mono", "Bi", "HDLC", "Ext"
                    881:        };
1.1.1.9 ! root      882:        uint stopbit = (cr4 >> 2) & 3;
        !           883:        screen.Print(x + 19, y, (stopbit == 0 ? TA::Normal : TA::Disable),
        !           884:                "Sync=%s", syncmode_str[(cr4 >> 4) & 3]);
1.1       root      885:        static const char * const stopbit_str[] = {
1.1.1.9 ! root      886:                "SyncMode",
        !           887:                "StopBit=1",
        !           888:                "Stop=1.5",
        !           889:                "StopBit=2"
1.1       root      890:        };
1.1.1.9 ! root      891:        screen.Puts(x + 29, y, stopbit_str[stopbit]);
1.1       root      892:        y++;
                    893: 
                    894:        // CR5
                    895:        static const char * const cr5_str[] = {
1.1.1.9 ! root      896:                "!DTR", "", "", "SBrk", "TxEn", "CRC", "!RTS", "TCEn"
1.1       root      897:        };
1.1.1.7   root      898:        MonitorReg(screen, x + 9, y, cr5, cr5_str);
1.1.1.9 ! root      899:        screen.Print(x + 14, y, "TxBits=%d", 5 + ((cr5 >> 5) & 3));
1.1       root      900:        y++;
                    901: 
                    902:        // SR0
                    903:        static const char * const sr0_str[] = {
1.1.1.9 ! root      904:                "BrAb", "TxUn", "!CTS", "!SYN", "!DCD", "TxEm", "IntP", "RxAv"
1.1       root      905:        };
1.1.1.7   root      906:        MonitorReg(screen, x + 9, y, sr0, sr0_str);
1.1.1.5   root      907:        // SR0 の bit1 (Interrupt Pending) は SR0A のみ。SR0B では 0。
                    908:        if (ch == 1) {
1.1.1.8   root      909:                screen.Print(39, y, TA::Disable, "----");
1.1.1.5   root      910:        }
1.1       root      911:        y++;
                    912: 
                    913:        // SR1
                    914:        static const char * const sr1_str[] = {
1.1.1.9 ! root      915:                "EOF", "FrEr", "RxOv", "PaEr", "", "", "", "Sent"
1.1       root      916:        };
1.1.1.7   root      917:        MonitorReg(screen, x + 9, y, sr1, sr1_str);
                    918:        screen.Print(x + 29, y, "ResidueCode=%d", (sr1 >> 1) & 7);
1.1       root      919:        y++;
                    920: }
                    921: 
                    922: // レジスタをビットごとに表示する。MonitorUpdate の下請け。
                    923: void
1.1.1.7   root      924: uPD7201Device::MonitorReg(TextScreen& screen,
1.1.1.4   root      925:        int x, int y, uint32 reg, const char * const *names)
1.1       root      926: {
                    927:        for (int i = 0; i < 8; i++) {
1.1.1.8   root      928:                if (names[i][0] == '-') {
                    929:                        screen.Puts(x + i * 5, y, TA::Disable, "----");
1.1       root      930:                } else {
                    931:                        bool b = reg & (1 << (7 - i));
1.1.1.7   root      932:                        screen.Puts(x + i * 5, y, TA::OnOff(b), names[i]);
1.1       root      933:                }
                    934:        }
                    935: }
1.1.1.9 ! root      936: 
        !           937: // ログ表示用のレジスタ名
        !           938: /*static*/ const char * const
        !           939: uPD7201Device::crnames[16] = {
        !           940:        "CR0A",         "CR0B",
        !           941:        "CR1A",         "CR1B",
        !           942:        "CR2A",         "CR2B",
        !           943:        "CR3A",         "CR3B",
        !           944:        "CR4A",         "CR4B",
        !           945:        "CR5A",         "CR5B",
        !           946:        "CR6A",         "CR6B",
        !           947:        "CR7A",         "CR7B",
        !           948: };
        !           949: /*static*/ const char * const
        !           950: uPD7201Device::srnames[16] = {
        !           951:        "SR0A",         "SR0B",
        !           952:        "SR1A",         "SR1B",
        !           953:        "SR2A?",        "SR2B",
        !           954:        "SR3A?",        "SR3B?",
        !           955:        "SR4A?",        "SR4B?",
        !           956:        "SR5A?",        "SR5B?",
        !           957:        "SR6A?",        "SR6B?",
        !           958:        "SR7A?",        "SR7B?",
        !           959: };

unix.superglobalmegacorp.com

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