--- nono/vm/upd7201.cpp 2026/04/29 17:04:28 1.1 +++ nono/vm/upd7201.cpp 2026/04/29 17:04:39 1.1.1.4 @@ -1,6 +1,7 @@ // // nono -// Copyright (C) 2018 isaki@NetBSD.org +// Copyright (C) 2020 nono project +// Licensed under nono-license.txt // #include "upd7201.h" @@ -8,7 +9,7 @@ // コンストラクタ uPD7201Device::uPD7201Device() { - monitor.Init(48, 19); + monitor_size = nnSize(48, 19); cr.chan[0].id = 0; cr.chan[0].name = "A"; cr.chan[1].id = 1; @@ -83,20 +84,14 @@ uPD7201Device::ReadCtrl(struct SIO::chan switch (chan->ptr) { case 0: // SR0 - // 送信バッファは常に空 - data = SIO::SR0_TXEMPTY; - // 受信データがあるか - if (chan->rxlen > 0) { - data |= SIO::SR0_RXAVAIL; - } + data = ReadSR0(chan); putlog(2, "SR%d%s -> $%02x", chan->ptr, chan->name, data); // アクセス後は SR0 へ戻す chan->ptr = 0; break; case 1: // SR1 - // エラーとか起きてないという状態だけ再現。 - data = SIO::SR1_ALL_SENT; + data = ReadSR1(chan); putlog(2, "SR%d%s -> $%02x", chan->ptr, chan->name, data); // アクセス後は SR0 へ戻す chan->ptr = 0; @@ -281,11 +276,58 @@ uPD7201Device::WriteCtrl(struct SIO::cha } } +// 制御ポートの Peek +uint8 +uPD7201Device::PeekCtrl(const struct SIO::channel *chan) const +{ + switch (chan->ptr) { + case 0: // SR0 + return ReadSR0(chan); + + case 1: // SR1 + return ReadSR1(chan); + + case 2: // SR2 + // SR2A はない。SR2B はベクタの読み出し + if (chan->id == 1) { + return cr.vector; + } + FALLTHROUGH; + + default: + // 未調査 + return 0xff; + } +} + +// SR0 の読み込み (Read, Peek 共通) +uint8 +uPD7201Device::ReadSR0(const struct SIO::channel *chan) const +{ + uint32 data; + + // 送信バッファは常に空 + data = SIO::SR0_TXEMPTY; + // 受信データがあるか + if (chan->rxlen > 0) { + data |= SIO::SR0_RXAVAIL; + } + return data; +} + +// SR1 の読み込み (Read, Peek 共通) +uint8 +uPD7201Device::ReadSR1(const struct SIO::channel *chan) const +{ + // エラーとか起きてないという状態だけ再現。 + return SIO::SR1_ALL_SENT; +} + + // データポートの読み込み uint8 -uPD7201Device::ReadData(int ch) +uPD7201Device::ReadData(struct SIO::channel *chan) { - struct SIO::channel *chan = &cr.chan[ch]; uint8 data; if (chan->rxlen > 0) { @@ -330,7 +372,20 @@ uPD7201Device::WriteData(struct SIO::cha } } -// TX/RX の bits/char のレジスタ値を実際の bits/char の値に変換します。 +// データポートの Peek +uint8 +uPD7201Device::PeekData(const struct SIO::channel *chan) const +{ + if (chan->rxlen > 0) { + // 受信バッファにデータがあれば先頭バイトが見える + return chan->rxbuf[0]; + } else { + // 空の時は? + return 0xff; + } +} + +// TX/RX の bits/char のレジスタ値を実際の bits/char の値に変換する。 /* static */ const int uPD7201Device::bits_per_char[] = { 5, 7, 6, 8 }; @@ -374,21 +429,21 @@ uPD7201Device::Rx(int ch, uint32 data) } // モニター -bool -uPD7201Device::MonitorUpdate() +void +uPD7201Device::MonitorUpdate(TextScreen& monitor) { monitor.Clear(); for (int i = 0; i < 2; i++) { int x = 0; int y = i * 10; - MonitorUpdateCh(i, x, y); + MonitorUpdateCh(monitor, i, x, y); } - return true; } // モニター (1チャンネル) void -uPD7201Device::MonitorUpdateCh(int ch, int xbase, int ybase) +uPD7201Device::MonitorUpdateCh(TextScreen& monitor, + int ch, int xbase, int ybase) { struct SIO::channel *chan = &cr.chan[ch]; uint cr0; @@ -460,7 +515,7 @@ uPD7201Device::MonitorUpdateCh(int ch, i static const char * const cr1_str[] = { "WaEn", "----", "WaRx", "", "", "----", "TxIE", "ESEn" }; - MonitorReg(x + 9, y, cr1, cr1_str); + MonitorReg(monitor, x + 9, y, cr1, cr1_str); monitor.Print(x + 24, y, "RXInt=%d", (cr1 >> 3) & 3); y++; @@ -468,7 +523,7 @@ uPD7201Device::MonitorUpdateCh(int ch, i static const char * const cr3_str[] = { "", "", "AuEn", "----", "----", "----", "----", "RXEn" }; - MonitorReg(x + 9, y, cr3, cr3_str); + MonitorReg(monitor, x + 9, y, cr3, cr3_str); monitor.Print(x + 9, y, "RXbits=%d", 5 + ((cr3 >> 6) & 3)); y++; @@ -476,7 +531,7 @@ uPD7201Device::MonitorUpdateCh(int ch, i static const char * const cr4_str[] = { "", "", "", "", "", "", "PaEv", "PaEn" }; - MonitorReg(x + 9, y, cr4, cr4_str); + MonitorReg(monitor, x + 9, y, cr4, cr4_str); static const char * const clkrate_str[] = { "1", "16", "32", "64" @@ -496,7 +551,7 @@ uPD7201Device::MonitorUpdateCh(int ch, i static const char * const cr5_str[] = { "DTR", "", "", "SBrk", "TXEn", "CRC", "!RTS", "TCEn" }; - MonitorReg(x + 9, y, cr5, cr5_str); + MonitorReg(monitor, x + 9, y, cr5, cr5_str); monitor.Print(x + 14, y, "TXbits=%d", 5 + ((cr5 >> 5) & 3)); y++; @@ -504,29 +559,29 @@ uPD7201Device::MonitorUpdateCh(int ch, i static const char * const sr0_str[] = { "BrAb", "TxUn", "CTS", "SYNC", "DCD", "TxEm", "IntP", "RxAv" }; - MonitorReg(x + 9, y, sr0, sr0_str); + MonitorReg(monitor, x + 9, y, sr0, sr0_str); y++; // SR1 static const char * const sr1_str[] = { "EOF", "CRCE", "RxOv", "PaEr", "", "", "", "Sent" }; - MonitorReg(x + 9, y, sr1, sr1_str); + MonitorReg(monitor, x + 9, y, sr1, sr1_str); monitor.Print(x + 29, y, "ResidueCode=%d", (sr1 >> 1) & 7); y++; } // レジスタをビットごとに表示する。MonitorUpdate の下請け。 void -uPD7201Device::MonitorReg(int x, int y, uint32 reg, const char * const *names) +uPD7201Device::MonitorReg(TextScreen& monitor, + int x, int y, uint32 reg, const char * const *names) { for (int i = 0; i < 8; i++) { if (strcmp(names[i], "----") == 0) { - monitor.Print(x + i * 5, y, TA::Disable, "%s", names[i]); + monitor.Puts(x + i * 5, y, TA::Disable, names[i]); } else { bool b = reg & (1 << (7 - i)); - uint attr = b ? TA::On : TA::Off; - monitor.Print(x + i * 5, y, attr, "%s", names[i]); + monitor.Puts(x + i * 5, y, TA::OnOff(b), names[i]); } } }