--- nono/vm/scc.cpp 2026/04/29 17:05:14 1.1.1.11 +++ nono/vm/scc.cpp 2026/04/29 17:05:59 1.1.1.18 @@ -10,49 +10,85 @@ #include "scc.h" #include "bitops.h" +#include "event.h" #include "hostcom.h" #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; - // X680x0 では SCC と呼ぶほうが通りがいい。 - // イベントの登録は親クラスで行ってある。 - for (int ch = 0; ch < txevent.size(); ch++) { - auto& chan = mpscc.chan[ch]; - txevent[ch].SetName(string_format("SCC Ch%c TX", chan.name)); - rxevent[ch].SetName(string_format("SCC Ch%c RX", chan.name)); + // 5MHz + pclk_tsec = 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_tsec = 250_nsec; } - monitor.func = ToMonitorCallback(&SCCDevice::MonitorUpdate); - monitor.SetSize(70, 35); - monitor.Regist(ID_MONITOR_SCC); + monitor = gMonitorManager->Regist(ID_MONITOR_SCC, this); + monitor->SetCallback(&SCCDevice::MonitorScreen); + monitor->SetSize(70, 35); } // デストラクタ SCCDevice::~SCCDevice() { - gSCC = NULL; +} + +// 初期化 +bool +SCCDevice::Init() +{ + if (inherited::Init() == false) { + return false; + } + + hostcom->SetPortName("SCC Ch.A"); + + if (gMainApp.IsX68030()) { + keyboard = GetKeyboard(); + } + + // X680x0 では SCC と呼ぶほうが通りがいい。 + // イベントの登録は親クラスで行ってある。 + for (int ch = 0; ch < txevent.size(); ch++) { + auto& chan = mpscc.chan[ch]; + txevent[ch]->SetName(string_format("SCC Ch%c TX", chan.name)); + rxevent[ch]->SetName(string_format("SCC Ch%c RX", chan.name)); + } + + return true; } // リセット @@ -135,6 +171,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 @@ -154,12 +192,10 @@ SCCDevice::ResetChannel(MPSCCChan& chan) ResetChannelCommon(chan); } -uint64 -SCCDevice::Read(uint32 offset) +busdata +SCCDevice::ReadPort(uint32 offset) { - uint64 data; - - gMPU->AddCycle(41); // InsideOut p.135 + busdata data; switch (offset) { case 0: // $E98001 @@ -172,20 +208,20 @@ SCCDevice::Read(uint32 offset) data = ReadCtrl(mpscc.chan[0]); break; case 3: // $E98007 - putlog(0, "Read ChA Data Register (NOT IMPLEMENTED)"); data = ReadData(mpscc.chan[0]); break; default: - __unreachable(); + VMPANIC("corrupted offset=%u", offset); } + + data |= read_wait; + data |= BusData::Size1; return data; } -uint64 -SCCDevice::Write(uint32 offset, uint32 data) +busdata +SCCDevice::WritePort(uint32 offset, uint32 data) { - gMPU->AddCycle(49); // InsideOut p.135 - switch (offset) { case 0: // $E98001 WriteCtrl(mpscc.chan[1], data); @@ -200,13 +236,16 @@ SCCDevice::Write(uint32 offset, uint32 d WriteData(mpscc.chan[0], data); break; default: - __unreachable(); + VMPANIC("corrupted offset=%u", offset); } - return 0; + + busdata r = write_wait; + r |= BusData::Size1; + return r; } -uint64 -SCCDevice::Peek(uint32 offset) +busdata +SCCDevice::PeekPort(uint32 offset) { uint64 data; @@ -224,27 +263,28 @@ SCCDevice::Peek(uint32 offset) data = PeekData(mpscc.chan[0]); break; default: - __unreachable(); + data = 0xff; + break; } return data; } // 書き込みレジスタ名を返す。 const char * -SCCDevice::CRName(const MPSCCChan& chan, int ptr_) const +SCCDevice::CRName(const MPSCCChan& chan, uint ptr_) const { assert(ptr_ < 16); - int idx = ptr_ * 2 + chan.id; + uint idx = ptr_ * 2 + chan.id; assert(idx < countof(wrnames)); return wrnames[idx]; } // 読み込みレジスタ名を返す。 const char * -SCCDevice::SRName(const MPSCCChan& chan, int ptr_) const +SCCDevice::SRName(const MPSCCChan& chan, uint ptr_) const { assert(ptr_ < 16); - int idx = ptr_ * 2 + chan.id; + uint idx = ptr_ * 2 + chan.id; assert(idx < countof(rrnames)); return rrnames[idx]; } @@ -301,12 +341,12 @@ SCCDevice::ReadCtrl(MPSCCChan& chan) case 14: case 15: case 11: - putlog(0, "ReadCtrl %d (NOT IMPLEMENTED)", chan.ptr); + putlog(0, "ReadCtrl %u (NOT IMPLEMENTED)", chan.ptr); data = 0xff; break; default: - __unreachable(); + VMPANIC("corrupted chan.ptr=%u", chan.ptr); } chan.ptr = 0; return data; @@ -370,7 +410,7 @@ SCCDevice::WriteCtrl(MPSCCChan& chan, ui WriteWR15(chan, data); break; default: - __unreachable(); + VMPANIC("corrupted chan.ptr=%u", chan.ptr); } // アクセス後は WR0 へ戻す chan.ptr = 0; @@ -427,7 +467,7 @@ SCCDevice::PeekCtrl(const MPSCCChan& cha break; default: - __unreachable(); + VMPANIC("corrupted chan.ptr=%u", chan.ptr); } return data; } @@ -457,7 +497,7 @@ SCCDevice::GetWR1(const MPSCCChan& chan) data |= MPSCC::WR1_RXINT_SPONLY; break; default: - __unreachable(); + VMPANIC("corrupted rxint_mode=%u", (uint)chan.rxint_mode); } if (chan.sp_parity) data |= MPSCC::WR1_SP_INC_PE; @@ -538,14 +578,14 @@ SCCDevice::WriteWR0(MPSCCChan& chan, uin if (chan.crc_cmd != 0) { // CRC は非同期モードでは不要のはず - putlog(3, "%s CRC Reset %d (NOT IMPLEMENTED)", + putlog(3, "%s CRC Reset %u (NOT IMPLEMENTED)", WRName(chan, 0), chan.crc_cmd); } if (chan.cmd == 0 || chan.cmd == 1) { // コマンド 0、1 がレジスタ切り替え chan.ptr = data & MPSCC::WR0_PTR; - putlog(3, "%s <- $%02x (ptr=%d)", WRName(chan, 0), data, chan.ptr); + putlog(3, "%s <- $%02x (ptr=%u)", WRName(chan, 0), data, chan.ptr); } else { // それ以外ならコマンド発行 putlog(2, "%s <- $%02x", CRName(chan, 0), data); @@ -570,7 +610,7 @@ SCCDevice::WriteWR0(MPSCCChan& chan, uin ResetHighestIUS(chan); break; default: - __unreachable(); + VMPANIC("corrupted chan.cmd=%u", chan.cmd); } } } @@ -613,7 +653,9 @@ SCCDevice::WriteWR5(MPSCCChan& chan, uin inherited::WriteCR5(chan, data); if (chan.id == 1 && rts) { - gKeyboard->MouseSendStart(); + if (keyboard) { + keyboard->MouseSendStart(); + } } } @@ -638,7 +680,7 @@ SCCDevice::WriteWR9(uint32 data) ResetHard(false); break; default: - __unreachable(); + VMPANIC("corrupted mpscc.wr9_cmd=%u", mpscc.wr9_cmd); } // これらはハードウェアリセットと同時に指定されたら、 @@ -707,7 +749,7 @@ SCCDevice::WriteWR15(MPSCCChan& chan, ui // モニター void -SCCDevice::MonitorUpdate(Monitor *, TextScreen& screen) +SCCDevice::MonitorScreen(Monitor *, TextScreen& screen) { uint wr9; uint rr3a; @@ -720,7 +762,7 @@ SCCDevice::MonitorUpdate(Monitor *, Text for (int i = 0; i < 2; i++) { int x = 0; y = i * 16; - MonitorUpdateCh(screen, i, x, y); + MonitorScreenCh(screen, i, x, y); } y = 32; @@ -755,7 +797,7 @@ SCCDevice::MonitorUpdate(Monitor *, Text // モニター (1チャンネル) void -SCCDevice::MonitorUpdateCh(TextScreen& screen, int ch, int xbase, int ybase) +SCCDevice::MonitorScreenCh(TextScreen& screen, int ch, int xbase, int ybase) { const MPSCCChan& chan = mpscc.chan[ch]; uint crc; @@ -825,7 +867,7 @@ SCCDevice::MonitorUpdateCh(TextScreen& s screen.Print(x, y++, "RR0: $%02x", rr0); screen.Print(x, y++, "RR1: $%02x", rr1); screen.Print(x, y++, "RR10:$%02x", rr10); - screen.Print(x, y, "RXbuf: %d", rxlen); + screen.Print(x, y, "RXbuf: %u", rxlen); int i; for (i = 0; i < rxlen; i++) { screen.Print(x + 9 + i * 4, y, "$%02x", chan.rxbuf[i]); @@ -837,7 +879,7 @@ SCCDevice::MonitorUpdateCh(TextScreen& s y = ybase + 1; x = xbase; // WR0 - screen.Print(x + 9, y, "CRC=%d", crc); + screen.Print(x + 9, y, "CRC=%u", crc); static const char * const cmd_str[] = { // 012345678901234 "Null command", @@ -849,8 +891,8 @@ SCCDevice::MonitorUpdateCh(TextScreen& s "Error Reset", "ResetHighestIUS", }; - screen.Print(x + 19, y, "CMD=%d(%s)", cmd, cmd_str[cmd]); - screen.Print(x + 43 - (ptr > 9 ? 1 : 0), y, "PTR=%d", ptr); + screen.Print(x + 19, y, "CMD=%u(%s)", cmd, cmd_str[cmd]); + screen.Print(x + 43 - (ptr > 9 ? 1 : 0), y, "PTR=%u", ptr); y++; // WR1 @@ -869,7 +911,7 @@ SCCDevice::MonitorUpdateCh(TextScreen& s y++; // WR3,WR4,WR5 - y = MonitorUpdateCR345(screen, x, y, wr3, wr4, wr5); + y = MonitorScreenCR345(screen, x, y, wr3, wr4, wr5); // WR10 screen.Puts(x + 9, y, TA::Disable, (wr10 & 0x80) ? "CRC1" : "CRC0"); @@ -947,7 +989,7 @@ SCCDevice::MonitorUpdateCh(TextScreen& s y++; // RR1 - MonitorUpdateSR1(screen, x, y, rr1); + MonitorScreenSR1(screen, x, y, rr1); y++; // RR10 @@ -962,26 +1004,29 @@ SCCDevice::MonitorUpdateCh(TextScreen& s // 右列 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.rxframebits); - screen.Print(x, y++, "Tx Bits/Frame: %2d", chan.txframebits); + screen.Print(x, y++, "Param:%13s", GetParamStr(chan).c_str()); + screen.Print(x, y++, "Rx Bits/Frame: %2u", chan.rxframebits); + screen.Print(x, y++, "Tx Bits/Frame: %2u", chan.txframebits); } // 内部の送信データクロックの設定 void SCCDevice::SetXC(MPSCCChan& chan) { - // 5MHz = 200nsec - // 12bit = 2.4usec - chan.xc12_ns = (2 * (chan.tc + 2)) * 2.4_usec; + chan.xc12_tsec = (2 * (chan.tc + 2)) * pclk_tsec * 12; ChangeBaudrate(chan); } // 割り込みアクノリッジ -int +busdata SCCDevice::InterruptAcknowledge() { return GetSR2B(); @@ -1016,7 +1061,7 @@ SCCDevice::Tx(int ch, uint32 data) // ChB はマウスだが TxD は接続されていない break; default: - __unreachable(); + VMPANIC("corrupted ch=%u", ch); } }