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