Annotation of nono/vm/upd7201.cpp, revision 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.