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

1.1       root        1: //
                      2: // nono
                      3: // Copyright (C) 2018 [email protected]
                      4: //
                      5: 
                      6: #include "upd7201.h"
                      7: 
                      8: // コンストラクタ
                      9: uPD7201Device::uPD7201Device()
                     10: {
                     11:        monitor.Init(48, 19);
                     12:        cr.chan[0].id = 0;
                     13:        cr.chan[0].name = "A";
                     14:        cr.chan[1].id = 1;
                     15:        cr.chan[1].name = "B";
                     16: 
                     17:        cr.chan[0].desc = NULL;
                     18:        cr.chan[1].desc = NULL;
                     19: }
                     20: 
                     21: // デストラクタ
                     22: uPD7201Device::~uPD7201Device()
                     23: {
                     24: }
                     25: 
                     26: // リセット
                     27: // どのタイミングで呼ばれるかは上位による
                     28: void
                     29: uPD7201Device::Reset()
                     30: {
                     31:        putlog(2, "リセット");
                     32: 
                     33:        // CR2A はチップリセットで bit6 以外を '0' に
                     34:        cr.cr2a &= ~0xbf;
                     35: 
                     36:        // チャンネルリセット
                     37:        ResetChannel(&cr.chan[0]);
                     38:        ResetChannel(&cr.chan[1]);
                     39: }
                     40: 
                     41: // チャンネルリセット
                     42: void
                     43: uPD7201Device::ResetChannel(struct SIO::channel *chan)
                     44: {
                     45:        putlog(2, "チャンネル %s リセット", chan->name);
                     46: 
                     47:        // CR0 b2-0
                     48:        chan->cr0 &= ~SIO::CR0_PTR;
                     49:        chan->ptr = 0;
                     50: 
                     51:        // CR1 b0,1,3,4,7
                     52:        chan->cr1 &= ~(SIO::CR1_WAIT_EN | SIO::CR1_RXINT |
                     53:                       SIO::CR1_TXINT_EN | SIO::CR1_ESINT_EN);
                     54: 
                     55:        // CR3 b0-7
                     56:        chan->cr3 = 0;
                     57: 
                     58:        // CR5 b1,2,3,4,7
                     59:        chan->cr5 &= ~(SIO::CR5_DTR | SIO::CR5_SENDBREAK | SIO::CR5_TX_EN |
                     60:                       SIO::CR5_CRC16 | SIO::CR5_RTS);
                     61: 
                     62:        // SR0 は b0,1 が '0'、b2,6 が '1'、残りは不定
                     63:        chan->sr0 &= ~(SIO::SR0_INTPEND | SIO::SR0_RXAVAIL);
                     64:        chan->sr0 |= (SIO::SR0_TXUNDER | SIO::SR0_TXEMPTY);
                     65: 
                     66:        // SR1 は b4-7 が '0'
                     67:        chan->sr1 &= ~(SIO::SR1_ENDOFFRAME | SIO::SR1_CRCERROR |
                     68:                       SIO::SR1_RXOVERRUN | SIO::SR1_PARITYERROR);
                     69: 
                     70:        // E/S ラッチ解除
                     71:        chan->es_ratched = false;
                     72: 
                     73:        // 受信バッファをクリア
                     74:        memset(chan->rxbuf, 0, sizeof(chan->rxbuf));
                     75:        chan->rxlen = 0;
                     76: }
                     77: 
                     78: // 制御ポートの読み込み
                     79: uint8
                     80: uPD7201Device::ReadCtrl(struct SIO::channel *chan)
                     81: {
                     82:        uint8 data;
                     83: 
                     84:        switch (chan->ptr) {
                     85:         case 0:        // SR0
                     86:                // 送信バッファは常に空
                     87:                data = SIO::SR0_TXEMPTY;
                     88:                // 受信データがあるか
                     89:                if (chan->rxlen > 0) {
                     90:                        data |= SIO::SR0_RXAVAIL;
                     91:                }
                     92:                putlog(2, "SR%d%s -> $%02x", chan->ptr, chan->name, data);
                     93:                // アクセス後は SR0 へ戻す
                     94:                chan->ptr = 0;
                     95:                break;
                     96: 
                     97:         case 1:        // SR1
                     98:                // エラーとか起きてないという状態だけ再現。
                     99:                data = SIO::SR1_ALL_SENT;
                    100:                putlog(2, "SR%d%s -> $%02x", chan->ptr, chan->name, data);
                    101:                // アクセス後は SR0 へ戻す
                    102:                chan->ptr = 0;
                    103:                break;
                    104: 
                    105:         case 2:
                    106:                // SR2B はベクタの読み出し
                    107:                if (chan->id == 1) {
                    108:                        data = cr.vector;
                    109:                        putlog(2, "SR%d%s -> $%02x", chan->ptr, chan->name, data);
                    110:                        // アクセス後は SR0 へ戻す
                    111:                        chan->ptr = 0;
                    112:                        break;
                    113:                }
                    114: 
                    115:                // SR2A はない
                    116:                FALLTHROUGH;
                    117: 
                    118:         default:
                    119:                putlog(0, "未実装レジスタ読み込み SR%d%s",
                    120:                        chan->ptr, chan->name);
                    121:                // SR0 へ戻る?
                    122:                chan->ptr = 0;
                    123:                return 0xff;
                    124:        }
                    125:        return data;
                    126: }
                    127: 
                    128: // 制御ポートの書き込み
                    129: void
                    130: uPD7201Device::WriteCtrl(struct SIO::channel *chan, uint32 data)
                    131: {
                    132:        uint cmd;
                    133: 
                    134:        switch (chan->ptr) {
                    135:         case 0:        // CR0
                    136:                // XXX b7,b6 は未対応。
                    137:                // b5,b4,b3 がコマンド。
                    138:                // b2,b1,b0 が次にアクセスするレジスタ(chan->ptr)の切り替え。
                    139:                chan->cr0 = data;
                    140:                chan->ptr = (chan->cr0 & SIO::CR0_PTR);
                    141: 
                    142:                cmd = (chan->cr0 & SIO::CR0_CMD) >> 3;
                    143:                if (cmd == 0) {
                    144:                        // コマンド0 ならレジスタ切り替え
                    145:                        putlog(3, "CR0%s <- $%02x (ptr=%d)", chan->name, data, chan->ptr);
                    146:                } else {
                    147:                        // 0 以外ならコマンド発行
                    148:                        putlog(2, "CR0%s <- $%02x", chan->name, data);
                    149:                }
                    150:                switch (cmd) {
                    151:                 case 0:        // No operation
                    152:                        break;
                    153:                 case 1:        // Send Abort
                    154:                        if (chan->mode == SIO::Mode::HDLC) {
                    155:                                putlog(0, "CR0: Send Abort 未実装");
                    156:                        } else {
                    157:                                // XXX Send Abort コマンドは「HDLC モードのみ有効」と書いて
                    158:                                //     あるがそれ以外の時にどうなるか不明。
                    159:                                putlog(0, "CR0: 未定義コマンド %d", cmd);
                    160:                        }
                    161:                        break;
                    162:                 case 2:        // Reset External/Status Interrupt
                    163:                        putlog(3, "E/S ラッチ解除");
                    164:                        chan->es_ratched = false;
                    165:                        break;
                    166:                 case 3:        // Channel Reset
                    167:                        putlog(1, "チャンネル%sリセット", chan->name);
                    168:                        ResetChannel(chan);
                    169:                        break;
                    170:                 case 4:        // Enable Interrupt On Next Receive Character
                    171:                        putlog(0, "CR0: 未実装コマンド %d", cmd);
                    172:                        break;
                    173:                 case 5:        // Reset Transmitter Interrupt/DMA Pending
                    174:                        // 本来これは上がっている Tx 割り込みを落とすためのようだが、
                    175:                        // SIO から MPU への割り込み通知はもう終わっていて下げる必要は
                    176:                        // ないので、何もすることはない。
                    177:                        break;
                    178:                 case 6:        // Error Reset
                    179:                 case 7:        // End of Interrupt
                    180:                        putlog(0, "CR0: 未実装コマンド %d", cmd);
                    181:                        break;
                    182:                 default:
                    183:                        __unreachable();
                    184:                }
                    185:                break;
                    186: 
                    187:         case 1:        // CR1
                    188:                chan->cr1 = data;
                    189:                putlog(2, "CR%d%s <- $%02x", chan->ptr, chan->name, data);
                    190:                // アクセス後は CR0 へ戻す
                    191:                chan->ptr = 0;
                    192:                break;
                    193: 
                    194:         case 2:
                    195:                if (chan->id == 0) {    // CR2A
                    196:                        putlog(2, "CR2A <- $%02x 書き込み(b7-2未実装)", data);
                    197:                        cr.cr2a = data;
                    198:                } else {                                // CR2B
                    199:                        putlog(2, "CR2B <- $%02x ベクタ設定", data);
                    200:                        cr.vector = data;
                    201:                }
                    202:                // アクセス後は CR0 へ戻す
                    203:                chan->ptr = 0;
                    204:                break;
                    205: 
                    206:         case 3:        // CR3
                    207:                chan->cr3 = data;
                    208:                putlog(2, "CR%d%s <- $%02x", chan->ptr, chan->name, data);
                    209:                putlog(1, "チャンネル%s RX %s, %dbits",
                    210:                        chan->name,
                    211:                        (chan->cr3 & SIO::CR3_RX_EN) ? "Enable" : "Disable",
                    212:                        bits_per_char[(chan->cr3 & SIO::CR3_RXBITS) >> 6]);
                    213:                // アクセス後は CR0 へ戻す
                    214:                chan->ptr = 0;
                    215:                break;
                    216: 
                    217:         case 4:        // CR4
                    218:         {
                    219:                chan->cr4 = data;
                    220:                putlog(2, "CR%d%s <- $%02x", chan->ptr, chan->name, data);
                    221:                uint8 stopbits = (chan->cr4 & SIO::CR4_STOPBITS);
                    222:                uint8 syncmode = (chan->cr4 & SIO::CR4_SYNCMODE);
                    223: 
                    224:                // モード分け、優先順位は分からない
                    225:                if (stopbits == SIO::SYNC_MODE) {
                    226:                        if (syncmode == SIO::SYNC_HDLC) {
                    227:                                chan->mode = SIO::Mode::HDLC;
                    228:                                putlog(2, "チャンネル%s HDLC モード", chan->name);
                    229:                        } else {
                    230:                                chan->mode = SIO::Mode::SYNC;
                    231:                                const char *sm[] = { "8bit", "16bit", "HDLC?", "Ext" };
                    232:                                putlog(2, "チャンネル%s Sync (%s) モード",
                    233:                                        chan->name, sm[syncmode >> 4]);
                    234:                        }
                    235:                } else {
                    236:                        chan->mode = SIO::Mode::ASYNC;
                    237:                        const char *cm[] = { "x1", "x16", "x32", "x64" };
                    238:                        const char *sm[] = { "?", "1", "1.5", "2" };
                    239:                        putlog(2, "チャンネル%s Async (%s clock, stopbit %s) モード",
                    240:                                chan->name,
                    241:                                cm[(chan->cr4 & SIO::CR4_CLKRATE) >> 6],
                    242:                                sm[stopbits >> 2]);
                    243:                }
                    244: 
                    245:                // アクセス後は CR0 へ戻す
                    246:                chan->ptr = 0;
                    247:                break;
                    248:         }
                    249: 
                    250:         case 5:        // CR5
                    251:         {
                    252:                chan->cr5 = data;
                    253:                putlog(2, "CR%d%s <- $%02x", chan->ptr, chan->name, data);
                    254:                putlog(1, "チャンネル%s TX %s, %dbits",
                    255:                        chan->name,
                    256:                        (chan->cr5 & SIO::CR5_TX_EN) ? "Enable" : "Disable",
                    257:                        bits_per_char[(chan->cr5 & SIO::CR5_TXBITS) >> 5]);
                    258:                // アクセス後は CR0 へ戻す
                    259:                chan->ptr = 0;
                    260:                break;
                    261:         }
                    262: 
                    263:         case 6:        // CR6
                    264:                putlog(0, "CR6%s <- $%02x 書き込み(未実装)", chan->name, data);
                    265:                chan->cr6 = data;
                    266:                // アクセス後は CR0 へ戻す
                    267:                chan->ptr = 0;
                    268:                break;
                    269: 
                    270:         case 7:        // CR7
                    271:                putlog(0, "CR7%s <- $%02x 書き込み(未実装)", chan->name, data);
                    272:                chan->cr7 = data;
                    273:                // アクセス後は CR0 へ戻す
                    274:                chan->ptr = 0;
                    275:                break;
                    276: 
                    277:         default:
                    278:                putlog(0, "未実装レジスタ書き込み CR%d%s <- $%02x",
                    279:                        chan->ptr, chan->name, data);
                    280:                break;
                    281:        }
                    282: }
                    283: 
                    284: // データポートの読み込み
                    285: uint8
                    286: uPD7201Device::ReadData(int ch)
                    287: {
                    288:        struct SIO::channel *chan = &cr.chan[ch];
                    289:        uint8 data;
                    290: 
                    291:        if (chan->rxlen > 0) {
                    292:                data = chan->rxbuf[0];
                    293:                chan->rxlen--;
                    294:                // 少ないので毎回前詰めしちゃえ
                    295:                if (chan->rxlen > 0) {
                    296:                        memmove(chan->rxbuf + 1, chan->rxbuf, chan->rxlen);
                    297:                }
                    298:        } else {
                    299:                // XXX 何が読めるか
                    300:                data = 0xff;
                    301:        }
                    302: 
                    303:        return data;
                    304: }
                    305: 
                    306: // データポートの書き込み
                    307: void
                    308: uPD7201Device::WriteData(struct SIO::channel *chan, uint32 data)
                    309: {
                    310:        char charbuf[4];
                    311: 
                    312:        if (isprint((int)data)) {
                    313:                snprintf(charbuf, sizeof(charbuf), "'%c'", data);
                    314:        } else {
                    315:                charbuf[0] = '\0';
                    316:        }
                    317:        putlog(1, "Ch%s データレジスタ書き込み $%02x %s",
                    318:                chan->name, data, charbuf);
                    319: 
                    320:        // 1文字送信
                    321: 
                    322:        // 今のところ内部バッファがなく常に送信できるので
                    323:        // 必ず Tx Buffer Empty が発生する。
                    324:        chan->sr0 |= SIO::SR0_TXEMPTY;
                    325: 
                    326:        // 割り込みをあげる
                    327:        if ((chan->cr1 & SIO::CR1_TXINT_EN)) {
                    328:                putlog(2, "割り込み (TX Empty)");
                    329:                Interrupt();
                    330:        }
                    331: }
                    332: 
                    333: // TX/RX の bits/char のレジスタ値を実際の bits/char の値に変換します。
                    334: /* static */
                    335: const int
                    336: uPD7201Device::bits_per_char[] = { 5, 7, 6, 8 };
                    337: 
                    338: // 1バイト受信する。
                    339: // 受理されれば true を返す。
                    340: bool
                    341: uPD7201Device::Rx(int ch, uint32 data)
                    342: {
                    343:        struct SIO::channel *chan = &cr.chan[ch];
                    344: 
                    345:        // Rx Enable でなければ受け取らない?
                    346:        if ((chan->cr3 & SIO::CR3_RX_EN) == 0) {
                    347:                return false;
                    348:        }
                    349: 
                    350:        // バッファが一杯なら Rx Overrun Error
                    351:        if (chan->rxlen == sizeof(chan->rxbuf)) {
                    352:                putlog(2, "Rx Overrun");
                    353:                chan->sr1 |= SIO::SR1_RXOVERRUN;
                    354:                return false;
                    355:        }
                    356: 
                    357:        // 受信
                    358:        chan->rxbuf[chan->rxlen++] = data;
                    359: 
                    360:        // 必要なら割り込みを上げる
                    361:        if ((chan->cr1 & SIO::CR1_RXINT) == SIO::RXINT_FIRSTCHAR) {
                    362:                // First character interrupt モードなら最初の1バイトでだけ割り込み
                    363:                if (chan->rxrecved == false) {
                    364:                        Interrupt();
                    365:                }
                    366:                chan->rxrecved = true;
                    367:        } else if ((chan->cr1 & SIO::CR1_RXINT) >= SIO::RXINT_ALL_INC_SPECIAL) {
                    368:                // All character interrupt モード (Special のことはちょっと置いとく)
                    369:                chan->rxrecved = true;
                    370:                Interrupt();
                    371:        }
                    372: 
                    373:        return true;
                    374: }
                    375: 
                    376: // モニター
                    377: bool
                    378: uPD7201Device::MonitorUpdate()
                    379: {
                    380:        monitor.Clear();
                    381:        for (int i = 0; i < 2; i++) {
                    382:                int x = 0;
                    383:                int y = i * 10;
                    384:                MonitorUpdateCh(i, x, y);
                    385:        }
                    386:        return true;
                    387: }
                    388: 
                    389: // モニター (1チャンネル)
                    390: void
                    391: uPD7201Device::MonitorUpdateCh(int ch, int xbase, int ybase)
                    392: {
                    393:        struct SIO::channel *chan = &cr.chan[ch];
                    394:        uint cr0;
                    395:        uint cr1;
                    396:        uint cr3;
                    397:        uint cr4;
                    398:        uint cr5;
                    399:        uint sr0;
                    400:        uint sr1;
                    401:        uint rxlen;
                    402:        int x;
                    403:        int y;
                    404: 
                    405:        cr0 = chan->cr0;
                    406:        cr1 = chan->cr1;
                    407:        cr3 = chan->cr3;
                    408:        cr4 = chan->cr4;
                    409:        cr5 = chan->cr5;
                    410:        sr0 = chan->sr0;
                    411:        sr1 = chan->sr1;
                    412:        rxlen = chan->rxlen;
                    413: 
                    414:        // 0         1         2         3         4         5         6
                    415:        // 012345678901234567890123456789012345678901234567890123456789012345
                    416:        //          0123 0123 0123 0123 0123 0123 0123 0123
                    417:        // CR0:$xx  CRC=x     CMD=x          PTR=x
                    418:        // CR1:$xx  WE   0    WR   RXInt=x   0    TXEn ESEn
                    419: 
                    420:        x = xbase;
                    421:        y = ybase;
                    422:        monitor.Print(x, y++, "Channel %s: %s", chan->name, chan->desc);
                    423:        monitor.Print(x, y++, "CR0:$%02x", cr0);
                    424:        monitor.Print(x, y++, "CR1:$%02x", cr1);
                    425:        monitor.Print(x, y++, "CR3:$%02x", cr3);
                    426:        monitor.Print(x, y++, "CR4:$%02x", cr4);
                    427:        monitor.Print(x, y++, "CR5:$%02x", cr5);
                    428:        monitor.Print(x, y++, "SR0:$%02x", sr0);
                    429:        monitor.Print(x, y++, "SR1:$%02x", sr1);
                    430:        monitor.Print(x, y,   "RXbuf:%d", rxlen);
                    431:        int i;
                    432:        for (i = 0; i < rxlen; i++) {
                    433:                monitor.Print(x + 8 + i * 4, y, "$%02x", chan->rxbuf[i]);
                    434:        }
                    435:        for (; i < sizeof(chan->rxbuf); i++) {
                    436:                monitor.Print(x + 8 + i * 4, y, "---");
                    437:        }
                    438: 
                    439:        y = ybase + 1;
                    440:        x = xbase;
                    441:        // CR0
                    442:        monitor.Print(x + 9, y, "CRC=%d", (cr0 >> 6));
                    443:        static const char * const cmd_str[] = {
                    444:        //   0123456789012345
                    445:                "No operation",
                    446:                "Send Abort",
                    447:                "Reset E/S Int",
                    448:                "Channel Reset",
                    449:                "Enable IntNextCh",
                    450:                "Reset TxIntPend",
                    451:                "Error Reset",
                    452:                "End of Interrupt",
                    453:        };
                    454:        uint cmd = (cr0 >> 3) & 7;
                    455:        monitor.Print(x + 19, y, "CMD=%d(%s)", cmd, cmd_str[cmd]);
                    456:        monitor.Print(x + 43, y, "PTR=%d", (cr0 & 7));
                    457:        y++;
                    458: 
                    459:        // CR1
                    460:        static const char * const cr1_str[] = {
                    461:                "WaEn", "----", "WaRx", "", "", "----", "TxIE", "ESEn"
                    462:        };
                    463:        MonitorReg(x + 9, y, cr1, cr1_str);
                    464:        monitor.Print(x + 24, y, "RXInt=%d", (cr1 >> 3) & 3);
                    465:        y++;
                    466: 
                    467:        // CR3
                    468:        static const char * const cr3_str[] = {
                    469:                "", "", "AuEn", "----", "----", "----", "----", "RXEn"
                    470:        };
                    471:        MonitorReg(x + 9, y, cr3, cr3_str);
                    472:        monitor.Print(x + 9, y, "RXbits=%d", 5 + ((cr3 >> 6) & 3));
                    473:        y++;
                    474: 
                    475:        // CR4
                    476:        static const char * const cr4_str[] = {
                    477:                "", "", "", "", "", "", "PaEv", "PaEn"
                    478:        };
                    479:        MonitorReg(x + 9, y, cr4, cr4_str);
                    480: 
                    481:        static const char * const clkrate_str[] = {
                    482:                "1", "16", "32", "64"
                    483:        };
                    484:        monitor.Print(x + 9, y, "Rate=x%s", clkrate_str[(cr4 >> 6) & 3]);
                    485:        static const char * const syncmode_str[] = {
                    486:                "Mono", "Bi", "HDLC", "Ext"
                    487:        };
                    488:        monitor.Print(x + 19, y, "Sync=%s", syncmode_str[(cr4 >> 4) & 3]);
                    489:        static const char * const stopbit_str[] = {
                    490:                "Sync", "1", "1.5", "2"
                    491:        };
                    492:        monitor.Print(x + 29, y, "Stop=%s", stopbit_str[(cr4 >> 2) & 3]);
                    493:        y++;
                    494: 
                    495:        // CR5
                    496:        static const char * const cr5_str[] = {
                    497:                "DTR", "", "", "SBrk", "TXEn", "CRC", "!RTS", "TCEn"
                    498:        };
                    499:        MonitorReg(x + 9, y, cr5, cr5_str);
                    500:        monitor.Print(x + 14, y, "TXbits=%d", 5 + ((cr5 >> 5) & 3));
                    501:        y++;
                    502: 
                    503:        // SR0
                    504:        static const char * const sr0_str[] = {
                    505:                "BrAb", "TxUn", "CTS", "SYNC", "DCD", "TxEm", "IntP", "RxAv"
                    506:        };
                    507:        MonitorReg(x + 9, y, sr0, sr0_str);
                    508:        y++;
                    509: 
                    510:        // SR1
                    511:        static const char * const sr1_str[] = {
                    512:                "EOF", "CRCE", "RxOv", "PaEr", "", "", "", "Sent"
                    513:        };
                    514:        MonitorReg(x + 9, y, sr1, sr1_str);
                    515:        monitor.Print(x + 29, y, "ResidueCode=%d", (sr1 >> 1) & 7);
                    516:        y++;
                    517: }
                    518: 
                    519: // レジスタをビットごとに表示する。MonitorUpdate の下請け。
                    520: void
                    521: uPD7201Device::MonitorReg(int x, int y, uint32 reg, const char * const *names)
                    522: {
                    523:        for (int i = 0; i < 8; i++) {
                    524:                if (strcmp(names[i], "----") == 0) {
                    525:                        monitor.Print(x + i * 5, y, TA::Disable, "%s", names[i]);
                    526:                } else {
                    527:                        bool b = reg & (1 << (7 - i));
                    528:                        uint attr = b ? TA::On : TA::Off;
                    529:                        monitor.Print(x + i * 5, y, attr, "%s", names[i]);
                    530:                }
                    531:        }
                    532: }

unix.superglobalmegacorp.com

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