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

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

unix.superglobalmegacorp.com

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