--- nono/vm/mpscc.cpp 2026/04/29 17:05:14 1.1.1.2 +++ nono/vm/mpscc.cpp 2026/04/29 17:05:25 1.1.1.5 @@ -23,7 +23,7 @@ #include "hostcom.h" #include "interrupt.h" #include "scheduler.h" -#include "sync.h" +#include "syncer.h" #include // @@ -59,8 +59,8 @@ MPSCCChan::Init(int id_) // // コンストラクタ -MPSCCDevice::MPSCCDevice(const std::string& objname_) - : inherited(objname_) +MPSCCDevice::MPSCCDevice() + : inherited(OBJ_MPSCC) { for (int ch = 0; ch < mpscc.chan.size(); ch++) { auto& chan = mpscc.chan[ch]; @@ -86,7 +86,7 @@ MPSCCDevice::MPSCCDevice(const std::stri MPSCCDevice::~MPSCCDevice() { if ((bool)hostcom) { - hostcom->SetCallbackDevice(NULL); + hostcom->SetRxCallback(NULL); } } @@ -94,14 +94,11 @@ bool MPSCCDevice::Create() { // 対応するホストドライバを作成 - try { - hostcom.reset(new HostCOMDevice("HostCOM")); - } catch (...) { + hostcom.reset(new HostCOMDevice(this, "HostCOM")); + if ((bool)hostcom == false) { return false; } - hostcom->SetRxCallback(ToDeviceCallback(&MPSCCDevice::HostRxCallback)); - hostcom->SetCallbackDevice(this); return true; } @@ -119,8 +116,14 @@ MPSCCDevice::SetLogLevel(int loglevel_) bool MPSCCDevice::Init() { - gScheduler->ConnectMessage(MessageID::HOSTCOM_RX, this, - ToMessageCallback(&MPSCCDevice::RxMessageCallback)); + if (inherited::Init() == false) { + return false; + } + + interrupt = GetInterruptDevice(); + + scheduler->ConnectMessage(MessageID::HOSTCOM_RX, this, + ToMessageCallback(&MPSCCDevice::RxMessage)); return true; } @@ -159,7 +162,8 @@ MPSCCDevice::GetCR0(const MPSCCChan& cha /*static*/ void MPSCCDevice::SetCR3(MPSCCChan& chan, uint32 data) { - switch (data & MPSCC::CR3_RXBITS) { + uint cr3_rxbits = data & MPSCC::CR3_RXBITS; + switch (cr3_rxbits) { case MPSCC::RXBITS_5: chan.rxbits = 5; break; @@ -173,7 +177,7 @@ MPSCCDevice::SetCR3(MPSCCChan& chan, uin chan.rxbits = 8; break; default: - __unreachable(); + VMPANIC("corrupted cr3_rxbits=$%x", cr3_rxbits); } chan.auto_enable = (data & MPSCC::CR3_AUTO_EN); @@ -202,7 +206,7 @@ MPSCCDevice::GetCR3(const MPSCCChan& cha data |= MPSCC::RXBITS_8; break; default: - __unreachable(); + VMPANIC("corrupted chan.rxbits=%d", chan.rxbits); } if (chan.auto_enable) { data |= MPSCC::CR3_AUTO_EN; @@ -217,7 +221,8 @@ MPSCCDevice::GetCR3(const MPSCCChan& cha /*static*/void MPSCCDevice::SetCR4(MPSCCChan& chan, uint32 data) { - switch (data & MPSCC::CR4_CLKRATE) { + uint cr4_clkrate = data & MPSCC::CR4_CLKRATE; + switch (cr4_clkrate) { case MPSCC::CLKRATE_1: chan.clkrate = 1; break; @@ -231,7 +236,7 @@ MPSCCDevice::SetCR4(MPSCCChan& chan, uin chan.clkrate = 64; break; default: - __unreachable(); + VMPANIC("corrupted cr4_clkrate=$%x", cr4_clkrate); } chan.syncmode = (data & MPSCC::CR4_SYNCMODE); chan.stopbits = (data & MPSCC::CR4_STOPBITS) >> 2; @@ -259,7 +264,7 @@ MPSCCDevice::GetCR4(const MPSCCChan& cha data |= MPSCC::CLKRATE_64; break; default: - __unreachable(); + VMPANIC("corrupted chan.clkrate=%d", chan.clkrate); } data |= chan.syncmode; data |= chan.stopbits << 2; @@ -276,7 +281,8 @@ MPSCCDevice::GetCR4(const MPSCCChan& cha /*static*/ void MPSCCDevice::SetCR5(MPSCCChan& chan, uint32 data) { - switch (data & MPSCC::CR5_TXBITS) { + uint cr5_txbits = data & MPSCC::CR5_TXBITS; + switch (cr5_txbits) { case MPSCC::TXBITS_5: chan.txbits = 5; break; @@ -290,7 +296,7 @@ MPSCCDevice::SetCR5(MPSCCChan& chan, uin chan.txbits = 8; break; default: - __unreachable(); + VMPANIC("corrupted cr5_txbits=$%x", cr5_txbits); } chan.nDTR = (data & MPSCC::CR5_nDTR); chan.sendbreak = (data & MPSCC::CR5_SENDBREAK); @@ -320,7 +326,7 @@ MPSCCDevice::GetCR5(const MPSCCChan& cha data |= MPSCC::TXBITS_8; break; default: - __unreachable(); + VMPANIC("corrupted chan.txbits=%d", chan.txbits); } if (chan.nDTR) { data |= MPSCC::CR5_nDTR; @@ -392,7 +398,7 @@ MPSCCDevice::GetSR2B() const data |= bitrev(stat << 1); break; default: - __unreachable(); + VMPANIC("corrupted mpscc.vis=%d", (int)mpscc.vis); } return data; @@ -635,7 +641,7 @@ MPSCCDevice::TrySend(MPSCCChan& chan) // 送信する chan.tx_shiftreg = chan.txbuf; chan.txlen = 0; - gScheduler->StartEvent(txevent[chan.id]); + scheduler->StartEvent(txevent[chan.id]); putlog(2, "Ch%c send $%02x", chan.name, chan.tx_shiftreg); // XXX たぶん送信してから割り込みを上げるまでにいくらか遅れがあるはず @@ -647,9 +653,9 @@ MPSCCDevice::TrySend(MPSCCChan& chan) // 送信のイベントコールバック void -MPSCCDevice::TxCallback(Event& event) +MPSCCDevice::TxCallback(Event& ev) { - int ch = event.code; + int ch = ev.code; MPSCCChan& chan = mpscc.chan[ch]; // 接続デバイスの呼び出し @@ -664,8 +670,20 @@ MPSCCDevice::TxCallback(Event& event) void MPSCCDevice::HostRxCallback() { - // スレッドを超えるためにメッセージを投げる - gScheduler->SendMessage(MessageID::HOSTCOM_RX); + // XXX 暫定 + // HostCom からメッセージが大量に送られると、スケジューラの + // メッセージキューが溢れてしまうことがあったので、とりあえず + // ここでメッセージを送るかどうかを見ているが、 + // 本当はたぶんこうではなくて、送る側が速度調節するか、 + // またはスケジューラにメッセージではないなにか別の方法で + // 通知を出すようにする必要がある。 + + Event& ev = rxevent[COM_CH]; + + if (ev.IsRunning() == false) { + // スレッドを超えるためにメッセージを投げる + scheduler->SendMessage(MessageID::HOSTCOM_RX); + } } // 1バイト受信する。 @@ -700,13 +718,13 @@ MPSCCDevice::Rx(int ch, uint32 data) // ホストシリアルからの1バイト受信メッセージ void -MPSCCDevice::RxMessageCallback(MessageID msgid, uint32 arg) +MPSCCDevice::RxMessage(MessageID msgid, uint32 arg) { Event& ev = rxevent[COM_CH]; // 受信ループが止まっていれば開始 if (ev.IsRunning() == false) { - gScheduler->StartEvent(ev); + scheduler->StartEvent(ev); } } @@ -722,7 +740,7 @@ MPSCCDevice::RxCallback(Event& ev) if (data >= 0) { Rx(ch, data); - gScheduler->StartEvent(ev); + scheduler->StartEvent(ev); } } @@ -792,8 +810,10 @@ MPSCCDevice::GetStopBits(MPSCCChan& chan return 0; case MPSCC::STOPBITS_2: return 2; + + default: + VMPANIC("corrupted chan.stopbits=$%x", chan.stopbits); } - __unreachable(); } // 受信イベントの時間を設定する。 @@ -810,6 +830,8 @@ MPSCCDevice::SetRxPeriod(MPSCCChan& chan bit += AdditionalBits(chan, chan.rx_enable); chan.rxframebits = bit; + rxevent[chan.id].time = bit * chan.bit12_ns / 12; + if (loglevel >= 1) { bool old_enable = chan.old_cr3 & MPSCC::CR3_RX_EN; bool new_enable = chan.rx_enable; @@ -855,7 +877,7 @@ MPSCCDevice::SetRxPeriod(MPSCCChan& chan if (chan.id == 0 && chan.rxbits == 5 && chan.stopbits == MPSCC::STOPBITS_2) { - gSync->PutlogRealtime(); + GetSyncer()->PutlogRealtime(); } } @@ -873,6 +895,8 @@ MPSCCDevice::SetTxPeriod(MPSCCChan& chan bit += AdditionalBits(chan, chan.tx_enable); chan.txframebits = bit; + txevent[chan.id].time = bit * chan.bit12_ns / 12; + if (loglevel >= 1) { bool old_enable = chan.old_cr5 & MPSCC::CR5_TX_EN; bool new_enable = chan.tx_enable; @@ -915,15 +939,20 @@ MPSCCDevice::SetTxPeriod(MPSCCChan& chan // All/First RxChar ----|& |OR |&--+ // |OR---------|& | // o Special Rx Condition -----|OR +---|OR -// |OR --- -// o External/Status ------------------------------|OR-->o-- INT // |OR -// o Tx Buffer Empty ----------|& +---|OR -// |&-----|& | -// Tx INT/DMA Enable --------|& |& | -// (CR1 b1) |&-------+ -// |& -// INT/DMA Mode (CR2A b1,0) --------|& (注2) +// o External/Status ------------------------------|OR----|& ___ +// |OR |&-->o-- INT +// o Tx Buffer Empty ----------|& +---|OR +-|& +// |&-----|& | | +// Tx INT/DMA Enable --------|& |& | | +// (CR1 b1) |&-------+ | +// |& | +// INT/DMA Mode (CR2A b1,0) --------|& (注2) | +// | +// Master Interrupt Enable ---------------------------+ (注3) +// (Z8530 Only, WR9) +// +// 左端の o 印は割り込み要因(チャンネルあたり4種類)。他は制御フラグ。 // // 注1: uPD7201/7201A Figure 3-2 では "Rx Disable (CR1:D1)" だがそこは // Tx INT/DMA Enable ビットなので名称もビット位置も誤り。 @@ -932,6 +961,8 @@ MPSCCDevice::SetTxPeriod(MPSCCChan& chan // // 注2: uPD7201 のみ。Z8530 ではこの選択肢はないので常に true のはず。 // +// 注3: Z8530 のみ。uPD7201 ではこの選択肢はないので常に true にしてある。 +// void MPSCCDevice::ChangeInterrupt() { @@ -987,11 +1018,16 @@ MPSCCDevice::ChangeInterrupt() total_intpend |= chan.intpend; } + // Z8530 の MIE。uPD7201 では true 固定にしてある。 + if (mpscc.master_int_enable == false) { + total_intpend = 0; + } + // いずれかでもあれば割り込みをアサート - gInterrupt->ChangeINT(this, total_intpend); + interrupt->ChangeINT(this, total_intpend); } -// "9600,N,8,1" みたいなのを返す +// "9600,N,8,1" みたいなのを返す。最大13桁? std::string MPSCCDevice::GetParamStr(const MPSCCChan& chan) const {