--- nono/vm/scc.cpp 2026/04/29 17:04:59 1.1.1.8 +++ nono/vm/scc.cpp 2026/04/29 17:05:06 1.1.1.9 @@ -32,6 +32,9 @@ SCCDevice::SCCDevice() cr.chan[1].desc = "Mouse"; // X680x0 では SCC と呼ぶほうが通りがいい。 + for (int ch = 0; ch < txevent.size(); ch++) { + txevent[ch].SetName(string_format("SCC Ch%s TX", cr.chan[ch].name)); + } monitor.Regist(ID_MONITOR_SCC); } @@ -109,48 +112,40 @@ SCCDevice::Peek(uint32 offset) __unreachable(); } +// CR(WR) レジスタ名を返す。Z8530 では WRn のほうが通りがいい。 +const char * +SCCDevice::CRName(const SIO::channel *chan, int ptr_) const +{ + assert(ptr_ < 16); + int idx = ptr_ * 2 + chan->id; + assert(idx < countof(wrnames)); + return wrnames[idx]; +} + +// SR(RR) レジスタ名を返す。Z8530 では RRn のほうが通りがいい。 +const char * +SCCDevice::SRName(const SIO::channel *chan, int ptr_) const +{ + assert(ptr_ < 16); + int idx = ptr_ * 2 + chan->id; + assert(idx < countof(rrnames)); + return rrnames[idx]; +} + // Z8530 制御ポート読み込み uint8 -SCCDevice::ReadCtrl(struct SIO::channel *chan) +SCCDevice::ReadCtrl(SIO::channel *chan) { return inherited::ReadCtrl(chan); } // Z8530 制御ポート書き込み void -SCCDevice::WriteCtrl(struct SIO::channel *chan, uint32 data) +SCCDevice::WriteCtrl(SIO::channel *chan, uint32 data) { switch (chan->ptr) { case 0: // WR0 - chan->cr0 = data; - - switch ((chan->cr0 & SIO::WR0_CMD) >> 3) { - case 0: - case 1: - // コマンド 0、1 がレジスタ切り替え - chan->ptr = chan->cr0 & SIO::WR0_PTR; - putlog(3, "WR0%s <- $%02x (ptr=%d)", chan->name, data, chan->ptr); - break; - - case 2: // Reset Ext/Status Interrupts - putlog(0, "WR0 Reset Ext/Status Interrupts 未実装"); - break; - case 3: // Send Abort - putlog(0, "WR0 Send Abort 未実装"); - break; - case 4: // Enable Int on Next Rx Character - putlog(0, "WR0 Enable Int on Next Rx Character 未実装"); - break; - case 5: // Reset Tx Int Pending - putlog(0, "WR0 Reset Tx Int Pending 未実装"); - break; - case 6: // Error Reset - putlog(0, "WR0 Error Reset 未実装"); - break; - case 7: // Reset Highest IUS - putlog(0, "WR0 Reset Highest IUS"); - break; - } + WriteCR0(chan, data); break; case 2: // WR2 @@ -177,7 +172,7 @@ SCCDevice::WriteCtrl(struct SIO::channel break; case 9: // WR9 - putlog(2, "WR%d%s <- $%02x", chan->ptr, chan->name, data); + putlog(2, "%s <- $%02x", WRName(chan), data); switch ((data & 0xc0) >> 6) { case 0: // No Reset break; @@ -198,14 +193,14 @@ SCCDevice::WriteCtrl(struct SIO::channel break; case 10: // WR10 - putlog(2, "WR%d%s <- $%02x (未実装)", chan->ptr, chan->name, data); + putlog(2, "%s <- $%02x (未実装)", WRName(chan), data); chan->wr10 = data; // アクセス後は WR0 へ戻す chan->ptr = 0; break; case 11: // WR11 - putlog(2, "WR%d%s <- $%02x (未実装)", chan->ptr, chan->name, data); + putlog(2, "%s <- $%02x (未実装)", WRName(chan), data); chan->wr11 = data; // アクセス後は WR0 へ戻す chan->ptr = 0; @@ -213,41 +208,98 @@ SCCDevice::WriteCtrl(struct SIO::channel case 12: // WR12 chan->tc = (chan->tc & 0xff00) | data; - putlog(2, "WR%d%s TC(L)=%04x", chan->ptr, chan->name, chan->tc); + putlog(2, "%s TC(L)=%04x", WRName(chan), chan->tc); + SetTXC(chan); // アクセス後は WR0 へ戻す chan->ptr = 0; break; case 13: // WR13 chan->tc = (chan->tc & 0x00ff) | (data << 8); - putlog(2, "WR%d%s TC(H)=%04x", chan->ptr, chan->name, chan->tc); + putlog(2, "%s TC(H)=%04x", WRName(chan), chan->tc); + SetTXC(chan); // アクセス後は WR0 へ戻す chan->ptr = 0; break; case 14: // WR14 - putlog(2, "WR%d%s <- $%02x (未実装)", chan->ptr, chan->name, data); + putlog(2, "%s <- $%02x (未実装)", WRName(chan), data); chan->wr14 = data; // アクセス後は WR0 へ戻す chan->ptr = 0; break; case 15: // WR15 - putlog(2, "WR%d%s <- $%02x (未実装)", chan->ptr, chan->name, data); + putlog(2, "%s <- $%02x (未実装)", WRName(chan), data); chan->wr15 = data; // アクセス後は WR0 へ戻す chan->ptr = 0; break; default: - PANIC("未実装レジスタ書き込み WR%d%s <- $%02x", - chan->ptr, chan->name, data); + PANIC("未実装レジスタ書き込み %s <- $%02x", WRName(chan), data); + break; + } +} + +// 内部の送信データクロックの設定 +void +SCCDevice::SetTXC(SIO::channel *chan) +{ + // 5MHz = 200nsec + // 12bit = 2.4usec + txc12_ns = (2 * (chan->tc + 2)) * 2.4_usec; +} + +// CR0(WR0) 書き込み。 +// uPD7201 の CR0 とは微妙に互換性がないので似てるけど違うので注意。 +void +SCCDevice::WriteCR0(SIO::channel *chan, uint32 data) +{ + uint cmd; + + // XXX b7,b6 (CRC Reset Command) は未対応。 + // XXX コマンドが %001、%000 以外の時に PTR(レジスタセレクト) が同時に + // 指定されたらどうなるか。 + chan->cr0 = data; + + if ((chan->cr0 & SIO::WR0_CRC)) { + putlog(0, "%s CRC リセット未実装", WRName(chan, 0)); + } + + cmd = (chan->cr0 & SIO::WR0_CMD) >> 3; + switch (cmd) { + case 0: + case 1: + // コマンド 0、1 がレジスタ切り替え + chan->ptr = chan->cr0 & SIO::WR0_PTR; + putlog(3, "%s <- $%02x (ptr=%d)", WRName(chan, 0), data, chan->ptr); + break; + case 2: // Reset Ext/Status Interrupts + ResetESIntr(chan); + break; + case 3: // Send Abort + SendAbort(chan); + break; + case 4: // Enable Int on Next Rx Character + EnableIntrOnNextRx(chan); + break; + case 5: // Reset Tx Int Pending + ResetTxIntrPending(chan); + break; + case 6: // Error Reset + ErrorReset(chan); break; + case 7: // Reset Highest IUS + ResetHighestIUS(chan); + break; + default: + __unreachable(); } } void -SCCDevice::WriteCR5(struct SIO::channel *chan, uint32 data) +SCCDevice::WriteCR5(SIO::channel *chan, uint32 data) { bool rts = bit_falling(chan->cr5, data, SIO::CR5_RTS); @@ -272,3 +324,51 @@ SCCDevice::InterruptAcknowledge() { return 0x50; /* XXX 実際は WR2 とか要因で変わる */ } + +void +SCCDevice::Tx(int ch, uint32 data) +{ + // TODO: シリアル送信 + // ChA はシリアルポート + // ChB はマウスだが TxD は接続されていない +} + +// ログ表示用のレジスタ名 +/*static*/ const char * const +SCCDevice::wrnames[32] = { + "WR0A", "WR0B", + "WR1A", "WR1B", + "WR2A", "WR2B", + "WR3A", "WR3B", + "WR4A", "WR4B", + "WR5A", "WR5B", + "WR6A", "WR6B", + "WR7A", "WR7B", + "WR8A", "WR8B", + "WR9A", "WR9B", + "WR10A", "WR10B", + "WR11A", "WR11B", + "WR12A", "WR12B", + "WR13A", "WR13B", + "WR14A", "WR14B", + "WR15A", "WR15B", +}; +/*static*/ const char * const +SCCDevice::rrnames[32] = { + "RR0A", "RR0B", + "RR1A", "RR1B", + "RR2A", "RR2B", + "RR3A", "RR3B", + "RR4A?", "RR4A?", + "RR5A?", "RR5A?", + "RR6A?", "RR6A?", + "RR7A?", "RR7A?", + "RR8A", "RR8B", + "RR9A?", "RR9A?", + "RR10A", "RR10B", + "RR11A?", "RR11A?", + "RR12A", "RR12B", + "RR13A", "RR13B", + "RR14A?", "RR14A?", + "RR15A", "RR15B", +};