Annotation of nono/hd64180/hd647180asci.cpp, revision 1.1.1.2

1.1       root        1: //
                      2: // nono
                      3: // Copyright (C) 2025 nono project
                      4: // Licensed under nono-license.txt
                      5: //
                      6: 
                      7: //
                      8: // HD647180 ASCI (非同期シリアル)
                      9: //
                     10: 
                     11: #include "hd647180asci.h"
1.1.1.2 ! root       12: #include "event.h"
1.1       root       13: #include "hostcom.h"
                     14: #include "monitor.h"
                     15: #include "mpu64180.h"
                     16: #include "scheduler.h"
                     17: 
                     18: // コンストラクタ
                     19: HD647180ASCIDevice::HD647180ASCIDevice()
                     20:        : inherited(OBJ_XP_ASCI)
                     21: {
                     22:        // 入力クロックφ= 6.144MHz だが、設定に関わらず必ず 160 分周は
                     23:        // されるので、それをした後の値を基本周波数(周期)とする。
                     24:        // 6.144MHz / 160 = 38400 [bps] = 26.04166... [usec/bit]
                     25:        // 12倍すると 312.5 [usec]
                     26:        xc12_ns = 312.5_usec;
                     27: 
                     28:        for (uint i = 0; i < channels.size(); i++) {
                     29:                channels[i].id = i;
                     30:        }
                     31: 
                     32:        monitor = gMonitorManager->Regist(ID_MONITOR_XPASCI, this);
                     33:        monitor->func = ToMonitorCallback(&HD647180ASCIDevice::MonitorUpdate);
                     34:        monitor->SetSize(63, 12);
                     35: }
                     36: 
                     37: // デストラクタ
                     38: HD647180ASCIDevice::~HD647180ASCIDevice()
                     39: {
                     40:        for (uint n = 0; n < channels.size(); n++) {
                     41:                if ((bool)hostcom[n]) {
                     42:                        hostcom[n]->ResetRxCallback();
                     43:                }
                     44:        }
                     45: }
                     46: 
                     47: bool
                     48: HD647180ASCIDevice::Create()
                     49: {
                     50:        static const char * const names[2] = {
                     51:                "XP ASCI Ch.0",
                     52:                "XP ASCI Ch.1",
                     53:        };
                     54: 
                     55:        // 対応するホストドライバを作成。
                     56:        for (auto& chan : channels) {
                     57:                uint n = chan.id;
                     58:                try {
                     59:                        hostcom[n].reset(new HostCOMDevice(this, n + 1, names[n]));
                     60:                } catch (...) { }
                     61:                if ((bool)hostcom[n] == false) {
                     62:                        warnx("Failed to initialize HostCOMDevice at %s", __method__);
                     63:                        return false;
                     64:                }
                     65:                auto func = ToDeviceCallback(&HD647180ASCIDevice::HostRxCallback);
                     66:                hostcom[n]->SetRxCallback(func, n);
                     67:        }
                     68: 
                     69:        return true;
                     70: }
                     71: 
                     72: // 初期化
                     73: bool
                     74: HD647180ASCIDevice::Init()
                     75: {
                     76:        xp = GetMPU64180Device();
1.1.1.2 ! root       77:        auto evman = GetEventManager();
1.1       root       78: 
                     79:        for (auto& chan : channels) {
                     80:                uint n = chan.id;
                     81: 
                     82:                chan.tdr_empty = true;
                     83:                chan.rdr_full = false;
                     84: 
                     85:                scheduler->ConnectMessage(MessageID::HOSTCOM_RX(n + 1), this,
                     86:                        ToMessageCallback(&HD647180ASCIDevice::RxMessage));
                     87: 
1.1.1.2 ! root       88:                txevent[n] = evman->Regist(this, n,
        !            89:                        ToEventCallback(&HD647180ASCIDevice::TxCallback),
        !            90:                        string_format("XP ASCI Ch%c TX", n + '0'));
        !            91: 
        !            92:                rxevent[n] = evman->Regist(this, n,
        !            93:                        ToEventCallback(&HD647180ASCIDevice::RxCallback),
        !            94:                        string_format("XP ASCI Ch%c RX", n + '0'));
1.1       root       95:        }
                     96: 
                     97:        return true;
                     98: }
                     99: 
                    100: // リセット
                    101: void
                    102: HD647180ASCIDevice::ResetHard(bool poweron)
                    103: {
                    104:        // TDR, RDR はリセットの影響を受けない。
                    105:        // リセットで転送は止まる (.. are stopped during RESET) とは書いてあるが
                    106:        // TSR, RSR がどうなるかは不明。さすがにリセットされるか。
                    107: 
                    108:        nRTS0 = true;
                    109:        cka1_disable = true;
                    110: 
                    111:        for (auto& chan : channels) {
                    112:                uint n = chan.id;
                    113: 
                    114:                chan.rx_enable = false;
                    115:                chan.tx_enable = false;
                    116:                chan.rx_intr_enable = false;
                    117:                chan.tx_intr_enable = false;
                    118:                chan.data8bit = false;
                    119:                chan.parity_en = false;
                    120:                chan.stop2bit = false;
                    121:                chan.parity_odd = false;
                    122:                chan.prescale = false;
                    123:                chan.divratio = false;
                    124:                chan.ss = 7;
                    125:                chan.nCTS = false;      // ?
                    126:                chan.tsr = -1;
                    127:                chan.rsr = -1;
                    128:                ChangeBaudRate(chan.id);
                    129:                ChangeInterrupt(chan.id);
                    130: 
                    131:                scheduler->StopEvent(txevent[n]);
                    132:                scheduler->StopEvent(rxevent[n]);
                    133:        }
                    134: }
                    135: 
                    136: uint32
                    137: HD647180ASCIDevice::ReadCNTLA(uint n)
                    138: {
                    139:        uint32 data = PeekCNTLA(n);
                    140:        putlog(3, "CNTLA%u -> $%02x", n, data);
                    141:        return data;
                    142: }
                    143: 
                    144: uint32
                    145: HD647180ASCIDevice::ReadCNTLB(uint n)
                    146: {
                    147:        uint32 data = PeekCNTLB(n);
                    148:        putlog(3, "CNTLB%u -> $%02x", n, data);
                    149:        return data;
                    150: }
                    151: 
                    152: uint32
                    153: HD647180ASCIDevice::ReadSTAT(uint n)
                    154: {
                    155:        uint32 data = PeekSTAT(n);
                    156:        putlog(3, "STAT%u -> $%02x", n, data);
                    157:        return data;
                    158: }
                    159: 
                    160: uint32
                    161: HD647180ASCIDevice::ReadTDR(uint n)
                    162: {
                    163:        // TDR は副作用なく読み出し可能。
                    164:        uint32 data = PeekTDR(n);
                    165:        putlog(3, "TDR%u -> $%02x", n, data);
                    166:        return data;
                    167: }
                    168: 
                    169: uint32
                    170: HD647180ASCIDevice::ReadRDR(uint n)
                    171: {
                    172:        Channel& chan = channels[n];
                    173: 
                    174:        uint32 data = PeekRDR(n);
                    175:        if (chan.rsr >= 0) {
                    176:                chan.rdr = chan.rsr;
                    177:                chan.rsr = -1;
                    178:        } else {
                    179:                chan.rdr_full = false;
                    180:        }
                    181:        putlog(4, "RDR%u -> $%02x", n, data);
                    182:        return data;
                    183: }
                    184: 
                    185: uint32
                    186: HD647180ASCIDevice::WriteCNTLA(uint n, uint32 data)
                    187: {
                    188:        Channel& chan = channels[n];
                    189:        std::string msg;
                    190: 
                    191:        if ((data & CNTL_MPE)) {
                    192:                putlog(0, "MPE=1 (NOT IMPLEMENTED)");
                    193:        }
                    194: 
                    195:        bool newrxe = (data & CNTL_RE);
                    196:        if (chan.rx_enable != newrxe) {
                    197:                chan.rx_enable = newrxe;
                    198:                if (__predict_false(loglevel >= 1)) {
                    199:                        msg += string_format(" RX=%s", (newrxe ? "Enable" : "Disable"));
                    200:                }
                    201:        }
                    202: 
                    203:        bool newtxe = (data & CNTL_TE);
                    204:        if (chan.tx_enable != newtxe) {
                    205:                chan.tx_enable = newtxe;
                    206:                if (__predict_false(loglevel >= 1)) {
                    207:                        msg += string_format(" TX=%s", (newtxe ? "Enable" : "Disable"));
                    208:                }
                    209:        }
                    210: 
                    211:        if (n == 0) {
                    212:                nRTS0 = (data & CNTL_nRTS0);
                    213:        } else {
                    214:                cka1_disable = (data & CNTL_CKA1D);
                    215:                if (cka1_disable == false) {
                    216:                        putlog(0, "CKA1D=0 (NOT IMPLEMENTED)");
                    217:                }
                    218:        }
                    219: 
                    220:        if ((data & CNTL_EFR)) {
                    221:                // OVRN, FE, PE をクリアする。
                    222:                chan.overrun = false;
                    223:                ChangeInterrupt(n);
                    224:        }
                    225: 
                    226:        bool new8bit = (data & CNTL_DATA8);
                    227:        bool newpen  = (data & CNTL_PAREN);
                    228:        bool newstop = (data & CNTL_STOP2);
                    229:        if (chan.data8bit  != new8bit ||
                    230:                chan.parity_en != newpen  ||
                    231:                chan.stop2bit  != newstop)
                    232:        {
                    233:                chan.data8bit = new8bit;
                    234:                chan.parity_en = newpen;
                    235:                chan.stop2bit = newstop;
                    236:                ChangeBaudRate(n);
                    237:                if (__predict_false(loglevel >= 1)) {
                    238:                        msg += string_format(" data=%u,stop=%u,parity=%s",
                    239:                                (chan.data8bit ? 8 : 7),
                    240:                                (chan.stop2bit ? 2 : 1),
                    241:                                (chan.parity_en ? "on" : "off"));
                    242:                }
                    243:        }
                    244: 
                    245:        if (__predict_false(loglevel >= 1)) {
                    246:                // ログレベル1なら状態が変わった時だけ、2ならすべて表示。
                    247:                int req;
                    248:                if (msg.empty()) {
                    249:                        // 状態が変わっていない。
                    250:                        req = 2;
                    251:                } else {
                    252:                        req = 1;
                    253:                        msg[0] = '(';
                    254:                        msg += ')';
                    255:                }
                    256:                putlog(req, "CNTLA%u <- $%02x %s", n, data, msg.c_str());
                    257:        }
                    258: 
                    259:        return 0;
                    260: }
                    261: 
                    262: uint32
                    263: HD647180ASCIDevice::WriteCNTLB(uint n, uint32 data)
                    264: {
                    265:        Channel& chan = channels[n];
                    266:        std::string msg;
                    267: 
                    268:        if ((data & (CNTL_MPBT | CNTL_MP))) {
                    269:                putlog(0, "MPBT|MP=1 (NOT IMPLEMENTED)");
                    270:        }
                    271: 
                    272:        bool newpo = (data & CNTL_PEO);
                    273:        if (chan.parity_odd != newpo) {
                    274:                chan.parity_odd = newpo;
                    275:                if (__predict_false(loglevel >= 1)) {
                    276:                        msg += string_format(" Parity=%s", (newpo ? "Odd" : "Even"));
                    277:                }
                    278:        }
                    279: 
                    280:        bool   newps = (data & CNTL_PS);
                    281:        bool   newdr = (data & CNTL_DR);
                    282:        uint32 newss = (data & CNTL_SS);
                    283:        if (chan.prescale != newps ||
                    284:                chan.divratio != newdr ||
                    285:                chan.ss != newss)
                    286:        {
                    287:                chan.prescale = newps;
                    288:                chan.divratio = newdr;
                    289:                chan.ss = newss;
                    290:                ChangeBaudRate(n);
                    291:                if (__predict_false(loglevel >= 1)) {
                    292:                        msg += string_format(" PS=%u DR=%u SS=%u",
                    293:                                (uint)newps, (uint)newdr, newss);
                    294:                        if (chan.baudrate > 0) {
                    295:                                msg += string_format(", %u bps", chan.baudrate);
                    296:                        }
                    297:                }
                    298:        }
                    299: 
                    300:        if (__predict_false(loglevel >= 1)) {
                    301:                // ログレベル1なら状態が変わった時だけ、2ならすべて表示。
                    302:                int req;
                    303:                if (msg.empty()) {
                    304:                        // 状態が変わっていない。
                    305:                        req = 2;
                    306:                } else {
                    307:                        req = 1;
                    308:                        msg[0] = '(';
                    309:                        msg += ')';
                    310:                }
                    311:                putlog(req, "CNTLB%u <- $%02x %s", n, data, msg.c_str());
                    312:        }
                    313: 
                    314:        return 0;
                    315: }
                    316: 
                    317: uint32
                    318: HD647180ASCIDevice::WriteSTAT(uint n, uint32 data)
                    319: {
                    320:        Channel& chan = channels[n];
                    321:        std::string msg;
                    322: 
                    323:        if (n == 1) {
                    324:                cts1_enable = (data & STAT_CTS1E);
                    325:                if (cts1_enable) {
                    326:                        putlog(0, "CTS1E=1 (NOT IMPLEMENTED)");
                    327:                }
                    328:        }
                    329: 
                    330:        bool newrie = (data & STAT_RIE);
                    331:        if (chan.rx_intr_enable != newrie) {
                    332:                chan.rx_intr_enable = newrie;
                    333:                ChangeInterrupt(n);
                    334:                msg += string_format(" RIE=%s", newrie ? "Enable" : "Disable");
                    335:        }
                    336: 
                    337:        bool newtie = (data & STAT_TIE);
                    338:        if (chan.tx_intr_enable != newtie) {
                    339:                chan.tx_intr_enable = newtie;
                    340:                ChangeInterrupt(n);
                    341:                msg += string_format(" TIE=%s", newrie ? "Enable" : "Disable");
                    342:        }
                    343: 
                    344:        if (__predict_false(loglevel >= 1)) {
                    345:                // ログレベル1なら状態が変わった時だけ、2ならすべて表示。
                    346:                int req;
                    347:                if (msg.empty()) {
                    348:                        // 状態が変わっていない。
                    349:                        req = 2;
                    350:                } else {
                    351:                        req = 1;
                    352:                        msg[0] = '(';
                    353:                        msg += ')';
                    354:                }
                    355:                putlog(req, "STAT%u <- $%02x %s", n, data, msg.c_str());
                    356:        }
                    357: 
                    358:        return 0;
                    359: }
                    360: 
                    361: uint32
                    362: HD647180ASCIDevice::WriteTDR(uint n, uint32 data)
                    363: {
                    364:        Channel& chan = channels[n];
                    365: 
                    366:        // どちらにしても一旦 TDR には置く。
                    367:        chan.tdr = data;
                    368:        putlog(4, "TDR%u <- $%02x", n, data);
                    369: 
                    370:        // TDR  TSR     TDR  TSR
                    371:        // ---  ---     ---  ---
                    372:        // なし なし -> なし data イベント始動
                    373:        // なし 有り -> data 有り (イベントは動いてるはず)
                    374:        // 有り なし              (すぐ1行上に遷移するのでこの状態にはならない)
                    375:        // 有り 有り -> data 有り
                    376: 
                    377:        if (chan.tsr < 0) {
                    378:                // TSR が空なら即コピーして、送信イベント開始。
                    379:                chan.tsr = chan.tdr;
                    380:                chan.tdr_empty = true;
1.1.1.2 ! root      381:                if (txevent[n]->IsRunning() == false) {
1.1       root      382:                        scheduler->StartEvent(txevent[n]);
                    383:                }
                    384:        } else {
                    385:                // TSR が埋まっていれば何もしない。(イベントは動いてるはず)
                    386:                chan.tdr_empty = false;
                    387:        }
                    388: 
                    389:        ChangeInterrupt(n);
                    390:        return 0;
                    391: }
                    392: 
                    393: uint32
                    394: HD647180ASCIDevice::WriteRDR(uint n, uint32 data)
                    395: {
                    396:        Channel& chan = channels[n];
                    397: 
                    398:        // RDR が空の時に限り、書き込み出来る。(p.69)
                    399:        if (chan.rdr_full) {
                    400:                putlog(1, "RDR%u <- $%02x (Write Ignored)", n, data);
                    401:        } else {
                    402:                chan.rdr = data;
                    403:                putlog(4, "RDR%u <- $%02x", n, data);
                    404:        }
                    405:        return 0;
                    406: }
                    407: 
                    408: uint32
                    409: HD647180ASCIDevice::PeekCNTLA(uint n) const
                    410: {
                    411:        const Channel& chan = channels[n];
                    412:        uint32 data = 0;
                    413: 
                    414:        // MPE Not implemented
                    415: 
                    416:        if (chan.rx_enable) {
                    417:                data |= CNTL_RE;
                    418:        }
                    419:        if (chan.tx_enable) {
                    420:                data |= CNTL_TE;
                    421:        }
                    422:        if (n == 0) {
                    423:                if (nRTS0) {
                    424:                        data |= CNTL_nRTS0;
                    425:                }
                    426:        } else {
                    427:                if (cka1_disable) {
                    428:                        data |= CNTL_CKA1D;
                    429:                }
                    430:        }
                    431:        if (chan.data8bit) {
                    432:                data |= CNTL_DATA8;
                    433:        }
                    434:        if (chan.parity_en) {
                    435:                data |= CNTL_PAREN;
                    436:        }
                    437:        if (chan.stop2bit) {
                    438:                data |= CNTL_STOP2;
                    439:        }
                    440: 
                    441:        return data;
                    442: }
                    443: 
                    444: uint32
                    445: HD647180ASCIDevice::PeekCNTLB(uint n) const
                    446: {
                    447:        const Channel& chan = channels[n];
                    448:        uint32 data = 0;
                    449: 
                    450:        // MPBT, MP: Not implemented
                    451: 
                    452:        if (chan.nCTS) {
                    453:                data |= CNTL_nCTS;
                    454:        }
                    455:        if (chan.parity_odd) {
                    456:                data |= CNTL_PEO;
                    457:        }
                    458:        if (chan.divratio) {
                    459:                data |= CNTL_DR;
                    460:        }
                    461:        data |= chan.ss;
                    462: 
                    463:        return data;
                    464: }
                    465: 
                    466: uint32
                    467: HD647180ASCIDevice::PeekSTAT(uint n) const
                    468: {
                    469:        const Channel& chan = channels[n];
                    470:        uint32 data = 0;
                    471: 
                    472:        if (chan.rdr_full) {
                    473:                data |= STAT_RDRF;
                    474:        }
                    475:        if (chan.overrun) {
                    476:                data |= STAT_OVRN;
                    477:        }
                    478: 
                    479:        // PE, FE は立たない。
                    480: 
                    481:        if (chan.rx_intr_enable) {
                    482:                data |= STAT_RIE;
                    483:        }
                    484:        if (n == 0) {
                    485:                if (nDCD0) {
                    486:                        data |= STAT_nDCD0;
                    487:                }
                    488:        } else {
                    489:                if (cts1_enable) {
                    490:                        data |= STAT_CTS1E;
                    491:                }
                    492:        }
                    493:        if (chan.tdr_empty) {
                    494:                data |= STAT_TDRE;
                    495:        }
                    496:        if (chan.tx_intr_enable) {
                    497:                data |= STAT_TIE;
                    498:        }
                    499: 
                    500:        return data;
                    501: }
                    502: 
                    503: uint32
                    504: HD647180ASCIDevice::PeekTDR(uint n) const
                    505: {
                    506:        const Channel& chan = channels[n];
                    507: 
                    508:        return chan.tdr;
                    509: }
                    510: 
                    511: uint32
                    512: HD647180ASCIDevice::PeekRDR(uint n) const
                    513: {
                    514:        const Channel& chan = channels[n];
                    515: 
                    516:        return chan.rdr;
                    517: }
                    518: 
                    519: void
                    520: HD647180ASCIDevice::MonitorUpdate(Monitor *, TextScreen& screen)
                    521: {
                    522:        screen.Clear();
                    523: 
                    524:        MonitorUpdateChan(screen, 0, 0);
                    525:        MonitorUpdateChan(screen, 6, 1);
                    526: }
                    527: 
                    528: void
                    529: HD647180ASCIDevice::MonitorUpdateChan(TextScreen& screen, int y, int n) const
                    530: {
                    531:        Channel tmp = channels[n];
                    532:        uint32 cntla = PeekCNTLA(n);
                    533:        uint32 cntlb = PeekCNTLB(n);
                    534:        uint32 stat  = PeekSTAT(n);
                    535:        int x;
                    536: 
                    537:        screen.Print(0, y++, "<Ch.%c>", n + '0');
                    538: 
                    539:        x = 16;
                    540:        screen.Print(0, y, "%02XH CNTLA%u=$%02x:", 0 + n, n, cntla);
                    541:        screen.Puts(x +  0, y, TA::OnOff(cntla & 0x80), "MPE");
                    542:        screen.Puts(x +  6, y, TA::OnOff(cntla & 0x40), "RE");
                    543:        screen.Puts(x + 12, y, TA::OnOff(cntla & 0x20), "TE");
                    544:        screen.Puts(x + 18, y, TA::OnOff(cntla & 0x10),
                    545:                (n == 0 ? "!RTS0" : "CKA1D"));
                    546:        screen.Puts(x + 24, y, TA::OnOff(cntla & 0x08), "MPBR");
                    547:        screen.Puts(x + 30, y, TA::OnOff(cntla & 0x04), "8BIT");
                    548:        screen.Puts(x + 36, y, TA::OnOff(cntla & 0x02), "ParEn");
                    549:        screen.Puts(x + 42, y, TA::OnOff(cntla & 0x01), "STOP2");
                    550:        y++;
                    551: 
                    552:        screen.Print(0, y, "%02XH CNTLB%u=$%02x:", 2 + n, n, cntlb);
                    553:        screen.Puts(x +  0, y, TA::OnOff(cntlb & 0x80), "MPBT");
                    554:        screen.Puts(x +  6, y, TA::OnOff(cntlb & 0x40), "MP");
                    555:        screen.Puts(x + 12, y, TA::OnOff(cntlb & 0x20), "!CTS");
                    556:        screen.Puts(x + 18, y, TA::OnOff(cntlb & 0x10), "PEO");
                    557:        screen.Print(x + 24, y, "DR=%u", tmp.divratio ? 1 : 0);
                    558:        screen.Print(x + 30, y, "SS[210]=%u", (cntlb & 0x07));
                    559:        screen.Print(x + 42, y, "PS=%u", tmp.prescale ? 1 : 0);
                    560:        y++;
                    561: 
                    562:        screen.Print(0, y, "%02XH STAT%u =$%02x:", 4 + n, n, stat);
                    563:        screen.Puts(x +  0, y, TA::OnOff(stat & 0x80), "RDRF");
                    564:        screen.Puts(x +  6, y, TA::OnOff(stat & 0x40), "OVRN");
                    565:        screen.Puts(x + 12, y, TA::OnOff(stat & 0x20), "PE");
                    566:        screen.Puts(x + 18, y, TA::OnOff(stat & 0x10), "FE");
                    567:        screen.Puts(x + 24, y, TA::OnOff(stat & 0x08), "RIE");
                    568:        screen.Puts(x + 30, y, TA::OnOff(stat & 0x04),
                    569:                (n == 0 ? "!DCD0" : "CTS1E"));
                    570:        screen.Puts(x + 36, y, TA::OnOff(stat & 0x02), "TDRE");
                    571:        screen.Puts(x + 42, y, TA::OnOff(stat & 0x01), "TIE");
                    572:        y++;
                    573: 
                    574:        screen.Print(0, y, "%02XH TDR%u  =", 6 + n, n);
                    575:        screen.Print(11, y, (tmp.tdr_empty ? TA::Disable : TA::Normal),
                    576:                "$%02x", tmp.tdr);
                    577:        screen.Puts(x, y, "TSR:");
                    578:        if (__predict_true(tmp.tsr < 0)) {
                    579:                screen.Puts(x + 4, y, TA::Disable, "---");
                    580:        } else {
                    581:                screen.Print(x + 4, y, "$%02x", tmp.tsr);
                    582:        }
                    583:        y++;
                    584: 
                    585:        screen.Print(0, y, "%02XH RDR%u  =", 8 + n, n);
                    586:        screen.Print(11, y, (tmp.rdr_full ? TA::Normal : TA::Disable),
                    587:                "$%02x", tmp.rdr);
                    588:        screen.Puts(x, y, "RSR:");
                    589:        if (__predict_true(tmp.rsr < 0)) {
                    590:                screen.Puts(x + 4, y, TA::Disable, "---");
                    591:        } else {
                    592:                screen.Print(x + 4, y, "$%02x", tmp.rsr);
                    593:        }
                    594: 
                    595:        // Param: 19200,N,8,2
                    596:        screen.Puts(x + 29, y, "Param:");
                    597:        if (tmp.baudrate == 0) {
                    598:                screen.Puts(x + 36, y, "(ExtClock)");
                    599:        } else {
                    600:                char p;
                    601:                if (tmp.parity_en) {
                    602:                        p = tmp.parity_odd ? 'O' : 'E';
                    603:                } else {
                    604:                        p = 'N';
                    605:                }
                    606:                screen.Print(x + 36, y, "%5u,%c,%u,%u",
                    607:                        tmp.baudrate, p, (tmp.data8bit ? 8 : 7), (tmp.stop2bit ? 2 : 1));
                    608:        }
                    609: }
                    610: 
                    611: 
                    612: // 割り込み状態を更新する。
                    613: // RDFn, OVRNn, RIEn, TDREn, TIEn のいずれかでも変更したら呼ぶこと。
                    614: void
                    615: HD647180ASCIDevice::ChangeInterrupt(uint n)
                    616: {
                    617:        // p.77 Fig 2.10.3 より、片方のチャンネルの割り込み要求ロジック。
                    618:        // ____
                    619:        // DCD0(*) --|OR  (*) Ch0 のみ
                    620:        // RDRFn ----|OR
                    621:        // OVRNn ----|OR-----|&            :  IEF1
                    622:        // PEn  -----|OR     |&            :   |
                    623:        // FEn  -----|OR     |&-----|OR    :   |
                    624:        //                   |&     |OR    :   +--|&
                    625:        //         RIEn -----|&     |OR    :      |&----> ASCIn Int
                    626:        //                          |OR-----------|&
                    627:        //         TDREn ----|&     |OR    :
                    628:        //                   |&-----|OR    :
                    629:        //         TIEn -----|&            :
                    630:        //                                 :
                    631:        // この関数でやってるのはここまで  : こっちは xp->ChangeASCIInt()
                    632: 
                    633:        const Channel& chan = channels[n];
                    634: 
                    635:        // PE, FE (, !DCD0) はない。
                    636:        bool rcond = chan.rdr_full || chan.overrun;
                    637:        bool rintr = rcond && chan.rx_intr_enable;
                    638: 
                    639:        bool tintr = chan.tdr_empty && chan.tx_intr_enable;
                    640: 
                    641:        bool intr = (rintr || tintr);
                    642: 
                    643:        // IEF1 は向こうで処理している。
                    644:        xp->ChangeASCIInt(n, intr);
                    645: }
                    646: 
                    647: static double
                    648: to_freq(uint64 nsec)
                    649: {
                    650:        return (double)1e9 / nsec;
                    651: }
                    652: 
                    653: // 現在の Prescale, DivideRatio, SS からボーレートを再計算する。
                    654: // ここで 1文字分の時間も計算するため、CNTLA の MOD が変わっても呼ぶこと。
                    655: void
                    656: HD647180ASCIDevice::ChangeBaudRate(uint n)
                    657: {
                    658:        Channel& chan = channels[n];
                    659: 
                    660:        if (__predict_false(chan.ss == 7)) {
                    661:                chan.baudrate = 0;
                    662:        } else {
                    663:                uint d = (1U << chan.ss);
                    664: 
                    665:                // PreScaler で 30 か 10 分周が指定出来るが、このうち 10 は計算済み。
                    666:                if (chan.prescale) {
                    667:                        d *= 3;
                    668:                }
                    669: 
                    670:                // DivideRatio で 64 か 16 分周が指定できるが、このうち 16 は計算済み。
                    671:                if (chan.divratio) {
                    672:                        d *= 4;
                    673:                }
                    674: 
                    675:                chan.bit12_ns = xc12_ns * d;
                    676:                chan.baudrate = to_freq(chan.bit12_ns / 12);
                    677: 
                    678:                // 1文字の送受信にかかる時間。
                    679:                uint bits = 1/*start*/ + 7/*data*/ + 1/*stop*/;
                    680:                if (chan.data8bit) {
                    681:                        bits++;
                    682:                }
                    683:                if (chan.parity_en) {
                    684:                        bits++;
                    685:                }
                    686:                if (chan.stop2bit) {
                    687:                        bits++;
                    688:                }
                    689:                uint64 time = chan.bit12_ns * bits / 12;
1.1.1.2 ! root      690:                txevent[n]->time = time;
        !           691:                rxevent[n]->time = time;
1.1       root      692:        }
                    693: }
                    694: 
                    695: // 送信イベント。
                    696: void
1.1.1.2 ! root      697: HD647180ASCIDevice::TxCallback(Event *ev)
1.1       root      698: {
1.1.1.2 ! root      699:        uint n = ev->code;
1.1       root      700:        Channel& chan = channels[n];
                    701: 
                    702:        // 1文字分の時間が経過したので TSR の文字をホストに送信。
                    703:        hostcom[n]->Tx(chan.tsr);
                    704: 
                    705:        if (chan.tdr_empty) {
                    706:                // 次がなければ終わり。
                    707:                chan.tsr = -1;
                    708:        } else {
                    709:                // 次の文字がある。
                    710:                chan.tsr = chan.tdr;
                    711:                chan.tdr_empty = true;
                    712:                ChangeInterrupt(n);
                    713: 
                    714:                scheduler->StartEvent(ev);
                    715:        }
                    716: }
                    717: 
                    718: // ホストスレッドからの受信通知。
                    719: // (HostCOM スレッドで呼ばれる)
                    720: void
                    721: HD647180ASCIDevice::HostRxCallback(uint32 arg)
                    722: {
                    723:        // XXX mpscc.cpp の同関数のコメント参照。
                    724: 
                    725:        uint n = arg;
1.1.1.2 ! root      726:        const Event *ev = rxevent[n];
1.1       root      727: 
1.1.1.2 ! root      728:        if (ev->IsRunning() == false) {
1.1       root      729:                // スレッドを超えるためにメッセージを投げる。
                    730:                scheduler->SendMessage(MessageID::HOSTCOM_RX(n + 1));
                    731:        }
                    732: }
                    733: 
                    734: // ホストシリアルからの1バイト受信メッセージ
                    735: // (VM スレッドで呼ばれる)
                    736: void
                    737: HD647180ASCIDevice::RxMessage(MessageID msgid, uint32 arg)
                    738: {
                    739:        uint n = msgid - MessageID::HOSTCOM1_RX;
1.1.1.2 ! root      740:        Event *ev = rxevent[n];
1.1       root      741: 
                    742:        // 受信ループが止まっていれば開始。
1.1.1.2 ! root      743:        if (ev->IsRunning() == false) {
1.1       root      744:                scheduler->StartEvent(ev);
                    745:        }
                    746: }
                    747: 
                    748: // 受信イベントコールバック。
                    749: void
1.1.1.2 ! root      750: HD647180ASCIDevice::RxCallback(Event *ev)
1.1       root      751: {
1.1.1.2 ! root      752:        uint n = ev->code;
1.1       root      753:        int data;
                    754: 
                    755:        data = hostcom[n]->Rx();
                    756:        if (data >= 0) {
                    757:                Rx(n, data);
                    758: 
                    759:                scheduler->StartEvent(ev);
                    760:        }
                    761: }
                    762: 
                    763: // 1バイト受信する。
                    764: bool
                    765: HD647180ASCIDevice::Rx(uint n, uint32 data)
                    766: {
                    767:        Channel& chan = channels[n];
                    768: 
                    769:        // Rx Enable でなければ受け取らない?
                    770:        if (chan.rx_enable == false) {
                    771:                return false;
                    772:        }
                    773: 
                    774:        // 受信前       受信後の状態
                    775:        // RDR  RSR     RDR  RSR
                    776:        // ---  ---     ---  ---
                    777:        // なし なし -> data なし
                    778:        // なし 有り              (すぐに1行下の状態に遷移するためこの状態はない)
                    779:        // 有り なし -> 有り data
                    780:        // 有り 有り -> 有り 有り (Overrun)
                    781: 
                    782:        // バッファが一杯なら Overrun。
                    783:        if (chan.rdr_full && chan.rsr >= 0) {
                    784:                putlog(2, "Ch%u Rx Overrun", n);
                    785:                chan.overrun = true;
                    786:                ChangeInterrupt(n);
                    787:                return false;
                    788:        }
                    789: 
                    790:        // 受信。
                    791:        putlog(2, "Ch%u recv $%02x", n, data);
                    792:        if (chan.rdr_full) {
                    793:                chan.rsr = data;
                    794:        } else {
                    795:                chan.rdr = data;
                    796:                chan.rdr_full = true;
                    797:                chan.rsr = -1;
                    798:                ChangeInterrupt(n);
                    799:        }
                    800: 
                    801:        return true;
                    802: }

unix.superglobalmegacorp.com

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