--- nono/vm/mpscc.cpp 2026/04/29 17:05:14 1.1.1.2 +++ nono/vm/mpscc.cpp 2026/04/29 17:05:42 1.1.1.9 @@ -22,8 +22,9 @@ #include "bitops.h" #include "hostcom.h" #include "interrupt.h" +#include "monitor.h" #include "scheduler.h" -#include "sync.h" +#include "syncer.h" #include // @@ -59,24 +60,12 @@ 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]; chan.Init(ch); - - // time は SetTxPeriod() でセット。 - // 名前は継承先でセットする。機種ごとに名前を使い分けているため。 - txevent[ch].dev = this; - txevent[ch].func = ToEventCallback(&MPSCCDevice::TxCallback); - txevent[ch].code = ch; - txevent[ch].Regist(); - - rxevent[ch].dev = this; - rxevent[ch].func = ToEventCallback(&MPSCCDevice::RxCallback); - rxevent[ch].code = ch; - rxevent[ch].Regist(); } // モニタは継承先で設定する @@ -86,7 +75,7 @@ MPSCCDevice::MPSCCDevice(const std::stri MPSCCDevice::~MPSCCDevice() { if ((bool)hostcom) { - hostcom->SetCallbackDevice(NULL); + hostcom->SetRxCallback(NULL); } } @@ -95,13 +84,13 @@ MPSCCDevice::Create() { // 対応するホストドライバを作成 try { - hostcom.reset(new HostCOMDevice("HostCOM")); - } catch (...) { + hostcom.reset(new HostCOMDevice(this, "HostCOM")); + } catch (...) { } + if ((bool)hostcom == false) { + warnx("Failed to initialize HostCOMDevice at %s", __method__); return false; } - hostcom->SetRxCallback(ToDeviceCallback(&MPSCCDevice::HostRxCallback)); - hostcom->SetCallbackDevice(this); return true; } @@ -111,16 +100,34 @@ MPSCCDevice::SetLogLevel(int loglevel_) { inherited::SetLogLevel(loglevel_); - assert((bool)hostcom); - hostcom->SetLogLevel(loglevel_); + if ((bool)hostcom) { + hostcom->SetLogLevel(loglevel_); + } } // 初期化 bool MPSCCDevice::Init() { - gScheduler->ConnectMessage(MessageID::HOSTCOM_RX, this, - ToMessageCallback(&MPSCCDevice::RxMessageCallback)); + interrupt = GetInterruptDevice(); + + scheduler->ConnectMessage(MessageID::HOSTCOM_RX, this, + ToMessageCallback(&MPSCCDevice::RxMessage)); + + for (int ch = 0; ch < mpscc.chan.size(); ch++) { + // time は SetTxPeriod() でセット。 + // 名前は継承先でセットする。機種ごとに名前を使い分けているため。 + txevent[ch].dev = this; + txevent[ch].func = ToEventCallback(&MPSCCDevice::TxCallback); + txevent[ch].code = ch; + scheduler->RegistEvent(txevent[ch]); + + rxevent[ch].dev = this; + rxevent[ch].func = ToEventCallback(&MPSCCDevice::RxCallback); + rxevent[ch].code = ch; + scheduler->RegistEvent(rxevent[ch]); + } + return true; } @@ -146,6 +153,12 @@ MPSCCDevice::ResetChannelCommon(MPSCCCha ChangeInterrupt(); } +bool +MPSCCDevice::PokePort(uint32 offset, uint32 data) +{ + return false; +} + // CR0/WR0 レジスタの内容を取得 // (値の取り出しだけなら共通) /*static*/ uint8 @@ -159,7 +172,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 +187,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 +216,7 @@ MPSCCDevice::GetCR3(const MPSCCChan& cha data |= MPSCC::RXBITS_8; break; default: - __unreachable(); + VMPANIC("corrupted chan.rxbits=%u", chan.rxbits); } if (chan.auto_enable) { data |= MPSCC::CR3_AUTO_EN; @@ -217,7 +231,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 +246,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 +274,7 @@ MPSCCDevice::GetCR4(const MPSCCChan& cha data |= MPSCC::CLKRATE_64; break; default: - __unreachable(); + VMPANIC("corrupted chan.clkrate=%u", chan.clkrate); } data |= chan.syncmode; data |= chan.stopbits << 2; @@ -276,7 +291,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 +306,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 +336,7 @@ MPSCCDevice::GetCR5(const MPSCCChan& cha data |= MPSCC::TXBITS_8; break; default: - __unreachable(); + VMPANIC("corrupted chan.txbits=%u", chan.txbits); } if (chan.nDTR) { data |= MPSCC::CR5_nDTR; @@ -389,10 +405,10 @@ MPSCCDevice::GetSR2B() const stat = 3; // VIS_321 とはビット順が逆 data &= ~0x70; - data |= bitrev(stat << 1); + data |= bitrev8(stat << 1); break; default: - __unreachable(); + VMPANIC("corrupted mpscc.vis=%u", (uint)mpscc.vis); } return data; @@ -511,7 +527,7 @@ MPSCCDevice::WriteCR4(MPSCCChan& chan, u putlog(2, "Channel %c Synchronous mode not supported", chan.name); } else { const char *sm[] = { "?", "1", "1.5", "2" }; - putlog(2, "Channel %c Async Mode (x%d clock, stopbit %s)", + putlog(2, "Channel %c Async Mode (x%u clock, stopbit %s)", chan.name, chan.clkrate, sm[chan.stopbits]); @@ -635,7 +651,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 +663,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 +680,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 +728,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 +750,7 @@ MPSCCDevice::RxCallback(Event& ev) if (data >= 0) { Rx(ch, data); - gScheduler->StartEvent(ev); + scheduler->StartEvent(ev); } } @@ -792,8 +820,10 @@ MPSCCDevice::GetStopBits(MPSCCChan& chan return 0; case MPSCC::STOPBITS_2: return 2; + + default: + VMPANIC("corrupted chan.stopbits=$%x", chan.stopbits); } - __unreachable(); } // 受信イベントの時間を設定する。 @@ -802,7 +832,7 @@ MPSCCDevice::GetStopBits(MPSCCChan& chan void MPSCCDevice::SetRxPeriod(MPSCCChan& chan) { - int bit; + uint bit; // 受信データビット数 bit = chan.rxbits; @@ -810,6 +840,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; @@ -831,7 +863,7 @@ MPSCCDevice::SetRxPeriod(MPSCCChan& chan if (loglevel >= 2) { nsstr = string_format(" (%" PRIu64 ")", chan.bit12_ns); } - putlogn("Channel %c RX Enable, %.1f bps%s, %d bits/frame", + putlogn("Channel %c RX Enable, %.1f bps%s, %u bits/frame", chan.name, chan.baudrate, nsstr.c_str(), @@ -855,7 +887,7 @@ MPSCCDevice::SetRxPeriod(MPSCCChan& chan if (chan.id == 0 && chan.rxbits == 5 && chan.stopbits == MPSCC::STOPBITS_2) { - gSync->PutlogRealtime(); + GetSyncer()->PutlogRealtime(); } } @@ -865,7 +897,7 @@ MPSCCDevice::SetRxPeriod(MPSCCChan& chan void MPSCCDevice::SetTxPeriod(MPSCCChan& chan) { - int bit; + uint bit; // 送信データビット数 bit = chan.txbits; @@ -873,6 +905,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; @@ -894,7 +928,7 @@ MPSCCDevice::SetTxPeriod(MPSCCChan& chan if (loglevel >= 2) { nsstr = string_format(" (%" PRIu64 ")", chan.bit12_ns); } - putlogn("Channel %c TX Enable, %.1f bps%s, %d bits/frame", + putlogn("Channel %c TX Enable, %.1f bps%s, %u bits/frame", chan.name, chan.baudrate, nsstr.c_str(), @@ -915,15 +949,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 +971,8 @@ MPSCCDevice::SetTxPeriod(MPSCCChan& chan // // 注2: uPD7201 のみ。Z8530 ではこの選択肢はないので常に true のはず。 // +// 注3: Z8530 のみ。uPD7201 ではこの選択肢はないので常に true にしてある。 +// void MPSCCDevice::ChangeInterrupt() { @@ -987,11 +1028,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 {