--- nono/vm/scc.cpp 2026/04/29 17:05:10 1.1.1.10 +++ nono/vm/scc.cpp 2026/04/29 17:05:24 1.1.1.13 @@ -14,27 +14,47 @@ #include "keyboard.h" #include "mpu.h" -// グローバル参照用 -SCCDevice *gSCC; +// InsideOut p.135 +static const busdata read_wait = busdata::Wait(41 * 40_nsec); +static const busdata write_wait = busdata::Wait(49 * 40_nsec); // コンストラクタ SCCDevice::SCCDevice() - : inherited("SCC") + : inherited() { - devaddr = baseaddr; - devlen = 0x2000; + SetName("SCC"); + ClearAlias(); + AddAlias("SCC"); + AddAlias("MPSCC"); - mpscc.chan[0].desc = "Serial Port"; - mpscc.chan[1].desc = "Mouse"; - - // ポートアドレス。 + // チャンネル名とポートアドレスは機種ごとに異なる。 + // // デバイス自身は自分が配置されるアドレスを知らなくてよい構造になって // いるが、直接アクセスしたりする場合などに毎回アドレスを確認するのが // 面倒なので(全機種で向きと間隔が異なる)、モニタで表示されてほしい。 - mpscc.chan[1].ctrladdr = 0xe98001; - mpscc.chan[1].dataaddr = 0xe98003; - mpscc.chan[0].ctrladdr = 0xe98005; - mpscc.chan[0].dataaddr = 0xe98007; + if (gMainApp.IsX68030()) { + mpscc.chan[0].desc = "Serial Port"; + mpscc.chan[1].desc = "Mouse"; + mpscc.chan[1].ctrladdr = 0xe98001; + mpscc.chan[1].dataaddr = 0xe98003; + mpscc.chan[0].ctrladdr = 0xe98005; + mpscc.chan[0].dataaddr = 0xe98007; + + // 5MHz + pclk_ns = 200_nsec; + } else { + // NWS-1750 + mpscc.chan[0].desc = "Serial Port #0"; + mpscc.chan[1].desc = "Serial Port #1 (NotConnected)"; + mpscc.chan[1].ctrladdr = 0xe0d40000; + mpscc.chan[1].dataaddr = 0xe0d40001; + mpscc.chan[0].ctrladdr = 0xe0d40002; + mpscc.chan[0].dataaddr = 0xe0d40003; + + // たぶん 4MHz + // http://www.ceres.dti.ne.jp/~tsutsui/netbsd/port-news68k.html#19990727 + pclk_ns = 250_nsec; + } // X680x0 では SCC と呼ぶほうが通りがいい。 // イベントの登録は親クラスで行ってある。 @@ -52,7 +72,21 @@ SCCDevice::SCCDevice() // デストラクタ SCCDevice::~SCCDevice() { - gSCC = NULL; +} + +// 初期化 +bool +SCCDevice::Init() +{ + if (inherited::Init() == false) { + return false; + } + + if (gMainApp.IsX68030()) { + keyboard = GetKeyboard(); + } + + return true; } // リセット @@ -70,6 +104,8 @@ SCCDevice::ResetHard(bool poweron) // XXX Reset for (auto& chan : mpscc.chan) { + // XC 設定は ResetChannel() の前に必要。 + SetXC(chan); ResetChannel(chan); // WR10 b5,6 = %0 @@ -93,6 +129,8 @@ SCCDevice::ResetHard(bool poweron) void SCCDevice::ResetChannel(MPSCCChan& chan) { + uint8 val; + // WR0 b0-7 = %0 chan.crc_cmd = 0; chan.cmd = 0; @@ -111,11 +149,12 @@ SCCDevice::ResetChannel(MPSCCChan& chan) // WR4 b2 = %1 // b2,3 が StopBits 設定だが b2 だけ %1 にするらしい…。 // 少なくとも非同期モードにしときたいということだろうか。 - chan.cr4 |= 0x04; + val = GetCR4(chan); + SetCR4(chan, val | 0x04); // WR5 b1,2,3,4,7 = %0 - chan.cr5 &= 0x61; - chan.tx_enable = false; + val = GetCR5(chan); + SetCR5(chan, val & 0x61); // WR9 b5 = %0 (未実装ビット) @@ -130,6 +169,8 @@ SCCDevice::ResetChannel(MPSCCChan& chan) chan.wr15 = 0xf8; // RR0 b0,1=%0、b2,6=%1 + chan.rxlen = 0; + chan.txlen = 0; chan.tx_underrun = true; // RR1 b1,2=%1、b3-7=%0 @@ -149,12 +190,10 @@ SCCDevice::ResetChannel(MPSCCChan& chan) ResetChannelCommon(chan); } -uint64 +busdata SCCDevice::Read(uint32 offset) { - uint64 data; - - gMPU->AddCycle(41); // InsideOut p.135 + busdata data; switch (offset) { case 0: // $E98001 @@ -167,20 +206,19 @@ SCCDevice::Read(uint32 offset) data = ReadCtrl(mpscc.chan[0]); break; case 3: // $E98007 - putlog(0, "ChA データレジスタ読み込み (未実装)"); data = ReadData(mpscc.chan[0]); break; default: - __unreachable(); + VMPANIC("corrupted offset=%d", offset); } + + data |= read_wait; return data; } -uint64 +busdata SCCDevice::Write(uint32 offset, uint32 data) { - gMPU->AddCycle(49); // InsideOut p.135 - switch (offset) { case 0: // $E98001 WriteCtrl(mpscc.chan[1], data); @@ -195,12 +233,13 @@ SCCDevice::Write(uint32 offset, uint32 d WriteData(mpscc.chan[0], data); break; default: - __unreachable(); + VMPANIC("corrupted offset=%d", offset); } - return 0; + + return write_wait; } -uint64 +busdata SCCDevice::Peek(uint32 offset) { uint64 data; @@ -219,7 +258,8 @@ SCCDevice::Peek(uint32 offset) data = PeekData(mpscc.chan[0]); break; default: - __unreachable(); + data = 0xff; + break; } return data; } @@ -296,13 +336,14 @@ SCCDevice::ReadCtrl(MPSCCChan& chan) case 14: case 15: case 11: - putlog(0, "ReadCtrl 未実装 %d", chan.ptr); + putlog(0, "ReadCtrl %d (NOT IMPLEMENTED)", chan.ptr); data = 0xff; break; default: - __unreachable(); + VMPANIC("corrupted chan.ptr=%d", chan.ptr); } + chan.ptr = 0; return data; } @@ -364,7 +405,7 @@ SCCDevice::WriteCtrl(MPSCCChan& chan, ui WriteWR15(chan, data); break; default: - __unreachable(); + VMPANIC("corrupted chan.ptr=%d", chan.ptr); } // アクセス後は WR0 へ戻す chan.ptr = 0; @@ -417,12 +458,11 @@ SCCDevice::PeekCtrl(const MPSCCChan& cha case 14: case 15: case 11: - putlog(0, "PeekCtrl 未実装 %d", chan.ptr); data = 0xff; break; default: - __unreachable(); + VMPANIC("corrupted chan.ptr=%d", chan.ptr); } return data; } @@ -452,7 +492,7 @@ SCCDevice::GetWR1(const MPSCCChan& chan) data |= MPSCC::WR1_RXINT_SPONLY; break; default: - __unreachable(); + VMPANIC("corrupted rxint_mode=%d", (int)chan.rxint_mode); } if (chan.sp_parity) data |= MPSCC::WR1_SP_INC_PE; @@ -533,7 +573,8 @@ SCCDevice::WriteWR0(MPSCCChan& chan, uin if (chan.crc_cmd != 0) { // CRC は非同期モードでは不要のはず - putlog(3, "%s CRC リセット未実装 %d", WRName(chan, 0), chan.crc_cmd); + putlog(3, "%s CRC Reset %d (NOT IMPLEMENTED)", + WRName(chan, 0), chan.crc_cmd); } if (chan.cmd == 0 || chan.cmd == 1) { @@ -564,7 +605,7 @@ SCCDevice::WriteWR0(MPSCCChan& chan, uin ResetHighestIUS(chan); break; default: - __unreachable(); + VMPANIC("corrupted chan.cmd=%d", chan.cmd); } } } @@ -598,12 +639,18 @@ SCCDevice::WriteWR2(uint32 data) void SCCDevice::WriteWR5(MPSCCChan& chan, uint32 data) { - bool rts = bit_falling(chan.cr5, data, MPSCC::WR5_nRTS); + // ~RTS 端子の立ち下がりでマウスに送信要求。 + // ~RTS 端子の立ち下がりは nRTS ビットでは立ち上がりになる。 + bool old_nRTS = chan.nRTS; + bool new_nRTS = (data & MPSCC::WR5_nRTS); + bool rts = (old_nRTS == false && new_nRTS); inherited::WriteCR5(chan, data); if (chan.id == 1 && rts) { - gKeyboard->MouseSendStart(); + if (keyboard) { + keyboard->MouseSendStart(); + } } } @@ -628,7 +675,7 @@ SCCDevice::WriteWR9(uint32 data) ResetHard(false); break; default: - __unreachable(); + VMPANIC("corrupted mpscc.wr9_cmd=%d", mpscc.wr9_cmd); } // これらはハードウェアリセットと同時に指定されたら、 @@ -654,14 +701,14 @@ SCCDevice::WriteWR9(uint32 data) void SCCDevice::WriteWR10(MPSCCChan& chan, uint32 data) { - putlog(2, "%s <- $%02x (未実装)", WRName(chan), data); + putlog(2, "%s <- $%02x (NOT IMPLEMENTED)", WRName(chan), data); chan.wr10 = data; } void SCCDevice::WriteWR11(MPSCCChan& chan, uint32 data) { - putlog(2, "%s <- $%02x (未実装)", WRName(chan), data); + putlog(2, "%s <- $%02x (NOT IMPLEMENTED)", WRName(chan), data); chan.wr11 = data; } @@ -684,14 +731,14 @@ SCCDevice::WriteWR13(MPSCCChan& chan, ui void SCCDevice::WriteWR14(MPSCCChan& chan, uint32 data) { - putlog(2, "%s <- $%02x (未実装)", WRName(chan), data); + putlog(2, "%s <- $%02x (NOT IMPLEMENTED)", WRName(chan), data); chan.wr14 = data; } void SCCDevice::WriteWR15(MPSCCChan& chan, uint32 data) { - putlog(2, "%s <- $%02x (未実装)", WRName(chan), data); + putlog(2, "%s <- $%02x (NOT IMPLEMENTED)", WRName(chan), data); chan.wr15 = data; } @@ -756,6 +803,8 @@ SCCDevice::MonitorUpdateCh(TextScreen& s uint wr3; uint wr4; uint wr5; + uint wr6; + uint wr7; uint wr10; uint wr11; uint wr14; @@ -774,8 +823,10 @@ SCCDevice::MonitorUpdateCh(TextScreen& s ptr = chan.ptr; wr1 = GetWR1(chan); wr3 = GetCR3(chan); - wr4 = chan.cr4; + wr4 = GetCR4(chan); wr5 = GetCR5(chan); + wr6 = chan.cr6; + wr7 = chan.cr7; wr10 = chan.wr10; wr11 = chan.wr11; tc = chan.tc; @@ -792,6 +843,7 @@ SCCDevice::MonitorUpdateCh(TextScreen& s // Channel A: Serial Console DataAddr $000000 // WR0: $xx CRC=x CMD=x PTR=x CtrlAddr $000000 // WR1: $xx WE 0 WR RXInt=x 0 TXEn ESEn + // WR13/WR12: $001f (196000bps) WR7/WR6:$1234 x = xbase; y = ybase; @@ -805,7 +857,8 @@ SCCDevice::MonitorUpdateCh(TextScreen& s screen.Print(x, y++, "WR11:$%02x", wr11); screen.Print(x, y++, "WR14:$%02x", wr14); screen.Print(x, y++, "WR15:$%02x", wr15); - screen.Print(x, y++, "WR12/WR13:$%04x", tc); + screen.Print(x, y, "WR13/WR12:$%04x (%.1fbps)", tc, chan.baudrate); + screen.Print(x + 35, y++, "WR7/WR6:$%02x%02x", wr7, wr6); screen.Print(x, y++, "RR0: $%02x", rr0); screen.Print(x, y++, "RR1: $%02x", rr1); screen.Print(x, y++, "RR10:$%02x", rr10); @@ -944,27 +997,31 @@ SCCDevice::MonitorUpdateCh(TextScreen& s y++; // 右列 - y = ybase; + y = ybase + 1; x = xbase + 51; - screen.Print(x, y++, "DataAddr $%06x", chan.dataaddr); - screen.Print(x, y++, "CtrlAddr $%06x", chan.ctrladdr); + if (chan.dataaddr > 0x01000000) { + screen.Print(x, y++, "DataAddr: $%08x", chan.dataaddr); + screen.Print(x, y++, "CtrlAddr: $%08x", chan.ctrladdr); + } else { + screen.Print(x, y++, "DataAddr: $%06x", chan.dataaddr); + screen.Print(x, y++, "CtrlAddr: $%06x", chan.ctrladdr); + } y++; - screen.Print(x, y++, "Param %12s", GetParamStr(chan).c_str()); - screen.Print(x, y++, "Rx Bits/Frame %2d", chan.rxbits); - screen.Print(x, y++, "Tx Bits/Frame %2d", chan.txbits); + screen.Print(x, y++, "Param:%13s", GetParamStr(chan).c_str()); + screen.Print(x, y++, "Rx Bits/Frame: %2d", chan.rxframebits); + screen.Print(x, y++, "Tx Bits/Frame: %2d", chan.txframebits); } // 内部の送信データクロックの設定 void SCCDevice::SetXC(MPSCCChan& chan) { - // 5MHz = 200nsec - // 12bit = 2.4usec - xc12_ns = (2 * (chan.tc + 2)) * 2.4_usec; + chan.xc12_ns = (2 * (chan.tc + 2)) * pclk_ns * 12; + ChangeBaudrate(chan); } // 割り込みアクノリッジ -int +busdata SCCDevice::InterruptAcknowledge() { return GetSR2B(); @@ -999,7 +1056,7 @@ SCCDevice::Tx(int ch, uint32 data) // ChB はマウスだが TxD は接続されていない break; default: - __unreachable(); + VMPANIC("corrupted ch=%d", ch); } }