--- nono/vm/upd7201.cpp 2026/04/29 17:04:56 1.1.1.7 +++ nono/vm/upd7201.cpp 2026/04/29 17:05:07 1.1.1.9 @@ -19,6 +19,14 @@ uPD7201Device::uPD7201Device(const std:: cr.chan[0].desc = NULL; cr.chan[1].desc = NULL; + for (int ch = 0; ch < txevent.size(); ch++) { + // time は SetTXPeriod() でセット + txevent[ch].dev = this; + txevent[ch].func = (DeviceCallback_t)&uPD7201Device::TXCallback; + txevent[ch].code = ch; + // 名前は継承先でセットする。機種ごとに名前を使い分けているため。 + } + monitor.func = (MonitorCallback_t)&uPD7201Device::MonitorUpdate; monitor.SetSize(48, 22); // 登録は継承先で行う。機種ごとに通りのいい名前を使い分けているため。 @@ -45,7 +53,7 @@ uPD7201Device::ResetHard() // チャンネルリセット void -uPD7201Device::ResetChannel(struct SIO::channel *chan) +uPD7201Device::ResetChannel(SIO::channel *chan) { putlog(2, "Channel %s Reset", chan->name); @@ -63,6 +71,7 @@ uPD7201Device::ResetChannel(struct SIO:: // CR5 b1,2,3,4,7 chan->cr5 &= ~(SIO::CR5_DTR | SIO::CR5_SENDBREAK | SIO::CR5_TX_EN | SIO::CR5_CRC16 | SIO::CR5_RTS); + SetTXPeriod(chan); // SR0 は b0,1 が '0'、b2,6 が '1'、残りは不定 chan->sr0 &= ~(SIO::SR0_INTPEND | SIO::SR0_RXAVAIL); @@ -74,30 +83,59 @@ uPD7201Device::ResetChannel(struct SIO:: // 内部状態をリセット chan->es_ratched = false; - chan->reset_txint_pend = true; + chan->txint = false; // 受信バッファをクリア memset(chan->rxbuf, 0, sizeof(chan->rxbuf)); chan->rxlen = 0; + + chan->txbuf = 0; + chan->txlen = 0; + chan->tx_shiftreg = 0; + // 送信の停止 + // XXX 送信途中のデータをぶちきることはサポートしない + txevent[chan->id].Stop(); + + ChangeInterrupt(); +} + +// CR(WR) レジスタ名を返す。uPD7201 では CRn のほうが通りがいい。 +const char * +uPD7201Device::CRName(const SIO::channel *chan, int ptr_) const +{ + assert(ptr_ < 8); + int idx = ptr_ * 2 + chan->id; + assert(idx < countof(crnames)); + return crnames[idx]; +} + +// SR(RR) レジスタ名を返す。uPD7201 では SRn のほうが通りがいい。 +const char * +uPD7201Device::SRName(const SIO::channel *chan, int ptr_) const +{ + assert(ptr_ < 8); + int idx = ptr_ * 2 + chan->id; + assert(idx < countof(srnames)); + return srnames[idx]; } // 制御ポートの読み込み uint8 -uPD7201Device::ReadCtrl(struct SIO::channel *chan) +uPD7201Device::ReadCtrl(SIO::channel *chan) { uint8 data; switch (chan->ptr) { case 0: // SR0 data = chan->sr0; - putlog(2, "SR%d%s -> $%02x", chan->ptr, chan->name, data); + putlog(2, "%s -> $%02x", SRName(chan), data); // アクセス後は SR0 へ戻す chan->ptr = 0; break; case 1: // SR1 data = chan->sr1; - putlog(2, "SR%d%s -> $%02x", chan->ptr, chan->name, data); + putlog(2, "%s -> $%02x", SRName(chan), data); // アクセス後は SR0 へ戻す chan->ptr = 0; break; @@ -106,7 +144,7 @@ uPD7201Device::ReadCtrl(struct SIO::chan // SR2B はベクタの読み出し if (chan->id == 1) { data = cr.vector; - putlog(2, "SR%d%s -> $%02x", chan->ptr, chan->name, data); + putlog(2, "%s -> $%02x", SRName(chan), data); // アクセス後は SR0 へ戻す chan->ptr = 0; break; @@ -116,8 +154,7 @@ uPD7201Device::ReadCtrl(struct SIO::chan FALLTHROUGH; default: - putlog(0, "未実装レジスタ読み込み SR%d%s", - chan->ptr, chan->name); + putlog(0, "未実装レジスタ読み込み %s", SRName(chan)); // SR0 へ戻る? chan->ptr = 0; return 0xff; @@ -127,7 +164,7 @@ uPD7201Device::ReadCtrl(struct SIO::chan // 制御ポートの書き込み void -uPD7201Device::WriteCtrl(struct SIO::channel *chan, uint32 data) +uPD7201Device::WriteCtrl(SIO::channel *chan, uint32 data) { // CR0 はコマンドかまたは次にアクセスするレジスタを指定する。 // CR0 以外のレジスタをアクセスすると、次のアクセスは CR0 に戻る。 @@ -158,9 +195,7 @@ uPD7201Device::WriteCtrl(struct SIO::cha WriteCR7(chan, data); break; default: - putlog(0, "未実装レジスタ書き込み CR%d%s <- $%02x", - chan->ptr, chan->name, data); - break; + __unreachable(); } // アクセス後は CR0 へ戻す chan->ptr = 0; @@ -169,7 +204,7 @@ uPD7201Device::WriteCtrl(struct SIO::cha // 制御ポートの Peek uint8 -uPD7201Device::PeekCtrl(const struct SIO::channel *chan) const +uPD7201Device::PeekCtrl(const SIO::channel *chan) const { switch (chan->ptr) { case 0: // SR0 @@ -192,8 +227,9 @@ uPD7201Device::PeekCtrl(const struct SIO } // CR0 への書き込み +// Z8530 の WR0 とは微妙に互換性がなく、scc.cpp に似た別物があるので注意。 void -uPD7201Device::WriteCR0(struct SIO::channel *chan, uint32 data) +uPD7201Device::WriteCR0(SIO::channel *chan, uint32 data) { uint cmd; @@ -206,52 +242,108 @@ uPD7201Device::WriteCR0(struct SIO::chan cmd = (chan->cr0 & SIO::CR0_CMD) >> 3; if (cmd == 0) { // コマンド0 ならレジスタ切り替え - putlog(3, "CR0%s <- $%02x (ptr=%d)", chan->name, data, chan->ptr); + putlog(3, "%s <- $%02x (ptr=%d)", CRName(chan, 0), data, chan->ptr); } else { // 0 以外ならコマンド発行 - putlog(2, "CR0%s <- $%02x", chan->name, data); + putlog(2, "%s <- $%02x", CRName(chan, 0), data); } switch (cmd) { case 0: // No operation break; case 1: // Send Abort - if (chan->mode == SIO::Mode::HDLC) { - putlog(0, "CR0: Send Abort 未実装"); - } else { - // XXX Send Abort コマンドは「HDLC モードのみ有効」と書いて - // あるがそれ以外の時にどうなるか不明。 - putlog(0, "CR0: 未定義コマンド %d", cmd); - } + SendAbort(chan); break; case 2: // Reset External/Status Interrupt - putlog(3, "CR0%s: Reset E/S Interrupt", chan->name); - chan->es_ratched = false; + ResetESIntr(chan); break; case 3: // Channel Reset ResetChannel(chan); break; case 4: // Enable Interrupt On Next Receive Character - putlog(0, "CR0: 未実装コマンド %d", cmd); + EnableIntrOnNextRx(chan); break; case 5: // Reset Transmitter Interrupt/DMA Pending - putlog(1, "CR0%s: Reset Tx Int/DMA Pending", chan->name); - chan->reset_txint_pend = false; - ChangeInterrupt(); + ResetTxIntrPending(chan); break; case 6: // Error Reset + ErrorReset(chan); + break; case 7: // End of Interrupt - putlog(0, "CR0: 未実装コマンド %d", cmd); + // uPD7201 ではチャンネル A のみ有効。 + // (チャンネル B でどうなるかは書いてない) + if (chan->id == 0) { + ResetHighestIUS(chan); + } else { + putlog(0, "%s: End of Intterupt 未定義", CRName(chan, 0)); + } break; default: __unreachable(); } } +// CR0(WR0) Send Abort コマンド +void +uPD7201Device::SendAbort(SIO::channel *chan) +{ + if (chan->mode == SIO::Mode::HDLC) { + putlog(0, "%s: Send Abort 未実装", CRName(chan, 0)); + } else { + // XXX Send Abort コマンドは「HDLC モードのみ有効」と書いて + // あるがそれ以外の時にどうなるか不明。 + uint cmd = (chan->cr0 & SIO::CR0_CMD) >> 3; + putlog(0, "%s: 未定義コマンド %d", CRName(chan, 0), cmd); + } +} + +// CR0(WR0) Reset External/Status Interrupt コマンド +void +uPD7201Device::ResetESIntr(SIO::channel *chan) +{ + putlog(3, "%s: Reset E/S Interrupt", CRName(chan, 0)); + chan->es_ratched = false; +} + +// CR0(WR0) Enable Interrupt on Next Rx Character コマンド +void +uPD7201Device::EnableIntrOnNextRx(SIO::channel *chan) +{ + putlog(0, "%s: Enable Intr on Next Rx Character 未実装", CRName(chan, 0)); +} + +// CR0(WR0) Reset Tx Interrupt/DMA Pending コマンド +void +uPD7201Device::ResetTxIntrPending(SIO::channel *chan) +{ + putlog(1, "%s: Reset Tx Intr/DMA Pending", CRName(chan, 0)); + chan->txint = false; + ChangeInterrupt(); +} + +// CR0(WR0) Error Reset コマンド +void +uPD7201Device::ErrorReset(SIO::channel *chan) +{ + putlog(1, "%s: Error Reset", CRName(chan, 0)); + chan->sr1 &= ~(SIO::SR1_ENDOFFRAME | SIO::SR1_CRCERROR | + SIO::SR1_RXOVERRUN | SIO::SR1_PARITYERROR); + // XXX Special Rx Condition は未実装 +} + +// CR0 End of Interrupt コマンド +// WR0 Reset Highest IUS コマンド +// たぶん名前が違うだけで同じ。後者のほうが分かりやすいのでこっちを使う +void +uPD7201Device::ResetHighestIUS(SIO::channel *chan) +{ + putlog(0, "%s: Reset Highest IUS 未実装", CRName(chan, 0)); +} + // CR1 への書き込み void -uPD7201Device::WriteCR1(struct SIO::channel *chan, uint32 data) +uPD7201Device::WriteCR1(SIO::channel *chan, uint32 data) { - putlog(2, "CR%d%s <- $%02x", chan->ptr, chan->name, data); + putlog(2, "%s <- $%02x", CRName(chan), data); chan->cr1 = data; @@ -263,39 +355,51 @@ uPD7201Device::WriteCR1(struct SIO::chan // CR2 への書き込み void -uPD7201Device::WriteCR2(struct SIO::channel *chan, uint32 data) +uPD7201Device::WriteCR2(SIO::channel *chan, uint32 data) { if (chan->id == 0) { // CR2A - putlog(2, "CR2A <- $%02x 書き込み(b7,b2-0未実装)", data); + putlog(2, "%s <- $%02x 書き込み(b7,b2-0未実装)", CRName(chan), data); cr.cr2a = data; } else { // CR2B - putlog(2, "CR2B <- $%02x (Set vector)", data); + putlog(2, "%s <- $%02x (Set vector)", CRName(chan), data); cr.vector = data; } } // CR3 への書き込み void -uPD7201Device::WriteCR3(struct SIO::channel *chan, uint32 data) +uPD7201Device::WriteCR3(SIO::channel *chan, uint32 data) { + uint8 oldcr3; + + oldcr3 = chan->cr3; chan->cr3 = data; - putlog(2, "CR%d%s <- $%02x", chan->ptr, chan->name, data); - putlog(1, "Channel %s RX %s, %dbits", - chan->name, - (chan->cr3 & SIO::CR3_RX_EN) ? "Enable" : "Disable", - bits_per_char[(chan->cr3 & SIO::CR3_RXBITS) >> 6]); + putlog(2, "%s <- $%02x", CRName(chan), data); + + // Disable は Disable に変化した時だけ表示 + if ((oldcr3 & SIO::CR3_RX_EN) != 0 && (chan->cr3 & SIO::CR3_RX_EN) == 0) { + putlog(1, "Channel %s RX Disable", chan->name); + } + // Enable はパラメータ変更があるかもなので常に表示 + if ((chan->cr3 & SIO::CR3_RX_EN)) { + putlog(1, "Channel %s RX Enable, %d bits/frame", + chan->name, + bits_per_char[(chan->cr3 & SIO::CR3_RXBITS) >> 6]); + } } // CR4 への書き込み void -uPD7201Device::WriteCR4(struct SIO::channel *chan, uint32 data) +uPD7201Device::WriteCR4(SIO::channel *chan, uint32 data) { chan->cr4 = data; - putlog(2, "CR%d%s <- $%02x", chan->ptr, chan->name, data); + putlog(2, "%s <- $%02x", CRName(chan), data); uint8 stopbits = (chan->cr4 & SIO::CR4_STOPBITS); uint8 syncmode = (chan->cr4 & SIO::CR4_SYNCMODE); + // TODO: 優先順位逆じゃない? + // モード分け、優先順位は分からない if (stopbits == SIO::SYNC_MODE) { if (syncmode == SIO::SYNC_HDLC) { @@ -309,49 +413,58 @@ uPD7201Device::WriteCR4(struct SIO::chan } } else { chan->mode = SIO::Mode::ASYNC; - const char *cm[] = { "x1", "x16", "x32", "x64" }; const char *sm[] = { "?", "1", "1.5", "2" }; - putlog(2, "Channel %s Async (%s clock, stopbit %s) Mode", + putlog(2, "Channel %s Async (x%d clock, stopbit %s) Mode", chan->name, - cm[(chan->cr4 & SIO::CR4_CLKRATE) >> 6], + clkrate[(chan->cr4 & SIO::CR4_CLKRATE) >> 6], sm[stopbits >> 2]); } + + SetTXPeriod(chan); } // CR5 への書き込み void -uPD7201Device::WriteCR5(struct SIO::channel *chan, uint32 data) +uPD7201Device::WriteCR5(SIO::channel *chan, uint32 data) { + uint8 oldcr5; + + oldcr5 = chan->cr5; chan->cr5 = data; - putlog(2, "CR%d%s <- $%02x", chan->ptr, chan->name, data); - putlog(1, "Channel %s TX %s, %dbits", - chan->name, - (chan->cr5 & SIO::CR5_TX_EN) ? "Enable" : "Disable", - bits_per_char[(chan->cr5 & SIO::CR5_TXBITS) >> 5]); + putlog(2, "%s <- $%02x", CRName(chan), data); + + // Disable は Disable に変化した時だけ表示 + // (Enable は SetTXPeriod() 内で表示) + if ((oldcr5 & SIO::CR5_TX_EN) != 0 && (chan->cr5 & SIO::CR5_TX_EN) == 0) { + putlog(1, "Channel %s TX Disable", chan->name); + } + + SetTXPeriod(chan); + TrySend(chan); } // CR6 への書き込み void -uPD7201Device::WriteCR6(struct SIO::channel *chan, uint32 data) +uPD7201Device::WriteCR6(SIO::channel *chan, uint32 data) { chan->cr6 = data; - putlog(0, "CR6%s <- $%02x 書き込み(未実装)", chan->name, data); + putlog(0, "%s <- $%02x 書き込み(未実装)", CRName(chan), data); } // CR7 への書き込み void -uPD7201Device::WriteCR7(struct SIO::channel *chan, uint32 data) +uPD7201Device::WriteCR7(SIO::channel *chan, uint32 data) { chan->cr7 = data; - putlog(0, "CR7%s <- $%02x 書き込み(未実装)", chan->name, data); + putlog(0, "%s <- $%02x 書き込み(未実装)", CRName(chan), data); } // データポートの読み込み uint8 -uPD7201Device::ReadData(struct SIO::channel *chan) +uPD7201Device::ReadData(SIO::channel *chan) { uint8 data; @@ -378,7 +491,7 @@ uPD7201Device::ReadData(struct SIO::chan // データポートの書き込み void -uPD7201Device::WriteData(struct SIO::channel *chan, uint32 data) +uPD7201Device::WriteData(SIO::channel *chan, uint32 data) { char charbuf[4]; @@ -389,19 +502,68 @@ uPD7201Device::WriteData(struct SIO::cha } putlog(3, "Ch%s Data <- $%02x %s", chan->name, data, charbuf); - // 1文字送信 + // XXX: EMPTY でないときにデータを書いたらどうなるかは未定義 - // 今のところ内部バッファがなく常に送信できるので - // 必ず Tx Buffer Empty が発生する。 - chan->sr0 |= SIO::SR0_TXEMPTY; + // 1byte の TX Buffer + chan->txlen = 1; + chan->txbuf = data; + chan->sr0 &= ~SIO::SR0_TXEMPTY; + + // TX 割り込みのクリア + chan->txint = false; + ChangeInterrupt(); + + TrySend(chan); +} + +// 送信できるか調べて送信する +void +uPD7201Device::TrySend(SIO::channel *chan) +{ + if ((chan->cr5 & SIO::CR5_TX_EN) == false) { + // 送信可でなければなにもしない + return; + } + if (chan->txlen == 0) { + // 送信バッファが空なら何もしない + return; + } + if (txevent[chan->id].IsRunning()) { + // 送信中なので何もしない + return; + } + + // 送信する + chan->tx_shiftreg = chan->txbuf; + txevent[chan->id].Start(); + putlog(2, "Ch%s sending $%02x", chan->name, chan->tx_shiftreg); + chan->txlen = 0; - // 割り込み状態を変える + // XXX たぶん送信してから割り込みを上げるまでにいくらか遅れがあるはず + + // 送信割り込み + chan->sr0 |= SIO::SR0_TXEMPTY; + chan->txint = true; ChangeInterrupt(); } +// 送信のイベントコールバック +void +uPD7201Device::TXCallback(Event& event) +{ + int ch = event.code; + SIO::channel *chan = &cr.chan[ch]; + + // 接続デバイスの呼び出し + Tx(ch, chan->tx_shiftreg); + + // 次の送信データが来てたら送信 + TrySend(chan); +} + // データポートの Peek uint8 -uPD7201Device::PeekData(const struct SIO::channel *chan) const +uPD7201Device::PeekData(const SIO::channel *chan) const { if (chan->rxlen > 0) { // 受信バッファにデータがあれば先頭バイトが見える @@ -413,16 +575,19 @@ uPD7201Device::PeekData(const struct SIO } // TX/RX の bits/char のレジスタ値を実際の bits/char の値に変換する。 -/* static */ -const int +/*static*/ const int uPD7201Device::bits_per_char[] = { 5, 7, 6, 8 }; +// CR4 CLKRATE のレジスタ値を実際の倍率に変換する。 +/*static*/ const int +uPD7201Device::clkrate[] = { 1, 16, 32, 64 }; + // 1バイト受信する。 // 受理されれば true を返す。 bool uPD7201Device::Rx(int ch, uint32 data) { - struct SIO::channel *chan = &cr.chan[ch]; + SIO::channel *chan = &cr.chan[ch]; // Rx Enable でなければ受け取らない? if ((chan->cr3 & SIO::CR3_RX_EN) == 0) { @@ -449,6 +614,69 @@ uPD7201Device::Rx(int ch, uint32 data) return true; } +static double +to_freq(uint64 nsec) +{ + return (double)1.0 / nsec * 1e9; +} + +// 送信イベントの時間を設定する (CR4, CR5 の変更で呼ぶ) +void +uPD7201Device::SetTXPeriod(SIO::channel *chan) +{ + uint64 bit12_ns; + int bit; + + // 誤差を減らすため 12bit 単位が基準 + // 12bit 時間 + bit12_ns = txc12_ns * clkrate[(chan->cr4 & SIO::CR4_CLKRATE) >> 6]; + + // start bit + bit = 1; + + // data bit + bit += bits_per_char[(chan->cr5 & SIO::CR5_TXBITS) >> 5]; + + // parity bit + bit += (chan->cr4 & SIO::CR4_PARITY_EN) ? 1 : 0; + + switch (chan->cr4 & SIO::CR4_STOPBITS) { + case 0: + // 非同期モードでの STOPBITS 0 は未定義 (Enable ならログ表示) + if ((chan->cr5 & SIO::CR5_TX_EN)) { + putlog(0, "%s 未定義ストップビット長 0", CRName(chan, 4)); + } + break; + case SIO::STOP_BITS_1: + bit += 1; + break; + case SIO::STOP_BITS_1_5: + // サポートしない (Enable ならログ表示) + if ((chan->cr5 & SIO::CR5_TX_EN)) { + putlog(0, "%s 未実装ストップビット長 1.5", CRName(chan, 4)); + } + break; + case SIO::STOP_BITS_2: + bit += 2; + break; + } + + txevent[chan->id].time = bit * bit12_ns / 12; + + // TX Enable (CR5) ならパラメータを含めて表示 + if ((chan->cr5 & SIO::CR5_TX_EN)) { + std::string nsstr; + if (loglevel >= 2) { + nsstr = string_format(" (%" PRIu64 ")", bit12_ns); + } + putlog(1, "Channel %s TX Enable, %.1f baud%s, %d bits/frame", + chan->name, + (double)to_freq(bit12_ns) * 12, + nsstr.c_str(), + bit); + } +} + // 割り込み状態を変更 void uPD7201Device::ChangeInterrupt() @@ -456,7 +684,7 @@ uPD7201Device::ChangeInterrupt() uint int_asserted = 0; for (int ch = 0; ch < 2; ch++) { - struct SIO::channel *chan = &cr.chan[ch]; + SIO::channel *chan = &cr.chan[ch]; // Rx bool rx_avail = (chan->rxlen > 0) && chan->all_or_first; @@ -475,11 +703,8 @@ uPD7201Device::ChangeInterrupt() // XXX E/S not yet // Tx - bool tx_empty = (chan->sr0 & SIO::SR0_TXEMPTY); bool tx_enable = (chan->cr1 & SIO::CR1_TXINT_EN); - // reset_txint_pend は通常 true、コマンド発行で false に落ちる。 - // XXX INT DMA Mode はよく分からんのでスルー - bool tx_int = (tx_empty && tx_enable && chan->reset_txint_pend); + bool tx_int = tx_enable && chan->txint; // 4つの要因の合成 chan->int_asserted = 0; @@ -515,7 +740,7 @@ uPD7201Device::MonitorUpdate(Monitor *, } else { screen.Print(9, y, "RTSB"); } - screen.Print(14, y, "----"); + screen.Print(14, y, TA::Disable, "----"); screen.Print(19, y, TA::OnOff((cr2a & 0x20)), "Vect"); if ((cr2a & 0x18) == 0x10) { screen.Print(24, y, "IM=V4-V2"); @@ -543,7 +768,7 @@ void uPD7201Device::MonitorUpdateCh(TextScreen& screen, int ch, int xbase, int ybase) { - struct SIO::channel *chan = &cr.chan[ch]; + SIO::channel *chan = &cr.chan[ch]; uint cr0; uint cr1; uint cr3; @@ -618,25 +843,27 @@ uPD7201Device::MonitorUpdateCh(TextScree // CR1 static const char * const cr1_str[] = { - "WaEn", "----", "WaRx", "", "", "----", "TxIE", "ESEn" + "Wait", "-", "", "", "", "VMod", "TxIE", "ESIE" }; MonitorReg(screen, x + 9, y, cr1, cr1_str); - static const char * const rxint_str[] = { - // 2345678 - "=SpOnly", - "=AllChr", - "=1stChr", - "Disable", - }; - screen.Print(x + 24, y, "RI%s", rxint_str[(cr1 >> 3) & 3]); + if ((cr1 & SIO::CR1_WAIT_EN)) { + screen.Puts(x + 19, y, ((cr1 & SIO::CR1_WAIT_RX) ? "OnRx" : "OnTx")); + } else { + screen.Puts(x + 19, y, TA::Disable, "TxRx"); + } + screen.Print(x + 24, y, "RxIntMod%d", (cr1 >> 3) & 3); + // CR1 の bit2 (Modified Vector) は CR1B のみ。 + if (ch == 0) { + screen.Puts(x + 34, y, TA::Disable, "----"); + } y++; // CR3 static const char * const cr3_str[] = { - "", "", "AuEn", "----", "----", "----", "----", "RXEn" + "", "", "Auto", "-", "-", "-", "-", "RxEn" }; MonitorReg(screen, x + 9, y, cr3, cr3_str); - screen.Print(x + 9, y, "RXbits=%d", 5 + ((cr3 >> 6) & 3)); + screen.Print(x + 9, y, "RxBits=%d", 5 + ((cr3 >> 6) & 3)); y++; // CR4 @@ -652,35 +879,40 @@ uPD7201Device::MonitorUpdateCh(TextScree static const char * const syncmode_str[] = { "Mono", "Bi", "HDLC", "Ext" }; - screen.Print(x + 19, y, "Sync=%s", syncmode_str[(cr4 >> 4) & 3]); + uint stopbit = (cr4 >> 2) & 3; + screen.Print(x + 19, y, (stopbit == 0 ? TA::Normal : TA::Disable), + "Sync=%s", syncmode_str[(cr4 >> 4) & 3]); static const char * const stopbit_str[] = { - "Sync", "1", "1.5", "2" + "SyncMode", + "StopBit=1", + "Stop=1.5", + "StopBit=2" }; - screen.Print(x + 29, y, "Stop=%s", stopbit_str[(cr4 >> 2) & 3]); + screen.Puts(x + 29, y, stopbit_str[stopbit]); y++; // CR5 static const char * const cr5_str[] = { - "DTR", "", "", "SBrk", "TXEn", "CRC", "!RTS", "TCEn" + "!DTR", "", "", "SBrk", "TxEn", "CRC", "!RTS", "TCEn" }; MonitorReg(screen, x + 9, y, cr5, cr5_str); - screen.Print(x + 14, y, "TXbits=%d", 5 + ((cr5 >> 5) & 3)); + screen.Print(x + 14, y, "TxBits=%d", 5 + ((cr5 >> 5) & 3)); y++; // SR0 static const char * const sr0_str[] = { - "BrAb", "TxUn", "CTS", "SYNC", "DCD", "TxEm", "IntP", "RxAv" + "BrAb", "TxUn", "!CTS", "!SYN", "!DCD", "TxEm", "IntP", "RxAv" }; MonitorReg(screen, x + 9, y, sr0, sr0_str); // SR0 の bit1 (Interrupt Pending) は SR0A のみ。SR0B では 0。 if (ch == 1) { - screen.Print(39, y, "----"); + screen.Print(39, y, TA::Disable, "----"); } y++; // SR1 static const char * const sr1_str[] = { - "EOF", "CRCE", "RxOv", "PaEr", "", "", "", "Sent" + "EOF", "FrEr", "RxOv", "PaEr", "", "", "", "Sent" }; MonitorReg(screen, x + 9, y, sr1, sr1_str); screen.Print(x + 29, y, "ResidueCode=%d", (sr1 >> 1) & 7); @@ -693,11 +925,35 @@ uPD7201Device::MonitorReg(TextScreen& sc int x, int y, uint32 reg, const char * const *names) { for (int i = 0; i < 8; i++) { - if (strcmp(names[i], "----") == 0) { - screen.Puts(x + i * 5, y, TA::Disable, names[i]); + if (names[i][0] == '-') { + screen.Puts(x + i * 5, y, TA::Disable, "----"); } else { bool b = reg & (1 << (7 - i)); screen.Puts(x + i * 5, y, TA::OnOff(b), names[i]); } } } + +// ログ表示用のレジスタ名 +/*static*/ const char * const +uPD7201Device::crnames[16] = { + "CR0A", "CR0B", + "CR1A", "CR1B", + "CR2A", "CR2B", + "CR3A", "CR3B", + "CR4A", "CR4B", + "CR5A", "CR5B", + "CR6A", "CR6B", + "CR7A", "CR7B", +}; +/*static*/ const char * const +uPD7201Device::srnames[16] = { + "SR0A", "SR0B", + "SR1A", "SR1B", + "SR2A?", "SR2B", + "SR3A?", "SR3B?", + "SR4A?", "SR4B?", + "SR5A?", "SR5B?", + "SR6A?", "SR6B?", + "SR7A?", "SR7B?", +};