--- nono/vm/newsctlr.cpp 2026/04/29 17:05:21 1.1.1.2 +++ nono/vm/newsctlr.cpp 2026/04/29 17:05:42 1.1.1.6 @@ -44,6 +44,8 @@ #include "ethernet.h" #include "interrupt.h" #include "scheduler.h" +#include "syncer.h" +#include "textscreen.h" // コンストラクタ NewsCtlrDevice::NewsCtlrDevice() @@ -51,10 +53,6 @@ NewsCtlrDevice::NewsCtlrDevice() { // ROM のうち固定のもの oidrom[0] = 0x0d; // ModelID = NWS-1750 - - timer_event.func = ToEventCallback(&NewsCtlrDevice::TimerCallback); - timer_event.time = 10_msec; - timer_event.Regist("SystemTimer"); } // デストラクタ @@ -66,18 +64,17 @@ NewsCtlrDevice::~NewsCtlrDevice() bool NewsCtlrDevice::Init() { - if (inherited::Init() == false) { - return false; - } - dipsw = GetDipswDevice(); + // クロックの同期方法。 + sync_rt = GetSyncer()->GetSyncRealtime(); + // ステータス読み出しのためにキャストしたのを持っておく interrupt = dynamic_cast(GetInterruptDevice()); assert(interrupt); // MAC アドレスを ROM にセット。 - macaddr_t macaddr; + MacAddr macaddr; if (EthernetDevice::GetConfigMacAddr(0, &macaddr, false) == false) { // エラーメッセージは表示済み return false; @@ -85,6 +82,11 @@ NewsCtlrDevice::Init() putmsg(1, "macaddr=%s", macaddr.ToString(':').c_str()); memcpy(&oidrom[8], &macaddr, sizeof(macaddr)); + timer_event.func = ToEventCallback(&NewsCtlrDevice::TimerCallback); + timer_event.time = TIMER_PERIOD; + timer_event.SetName("SystemTimer"); + scheduler->RegistEvent(timer_event); + return true; } @@ -94,108 +96,104 @@ NewsCtlrDevice::ResetHard(bool poweron) // たぶん止まるだろう。知らんけど。 timer_intr = false; timer_enable = false; + ChangeInterrupt(); // たぶん消すだろう。知らんけど。 led = 0; // たぶん電源オンで即起動? 知らんけど。 if (poweron) { + if (sync_rt) { + stime = GetSyncer()->GetRealTime(); + } scheduler->StartEvent(timer_event); } } -uint64 -NewsCtlrDevice::Read8(uint32 addr) +busdata +NewsCtlrDevice::Read(busaddr addr) { - uint64 data = -1; - - addr |= 0xc0000000; + uint32 paddr = addr.Addr() | 0xc0000000; - if ((addr >> 16) == 0xe1c0) { - uint idx = (addr >> 8) & 3; + if ((paddr >> 16) == 0xe1c0) { + uint idx = (paddr >> 8) & 3; + busdata data; switch (idx) { case 0: // e1c0'00xx - data = GetIDROM(addr); - putlog(2, "$%08x.B (IDROM) -> $%02x", addr, (uint32)data); + data = GetIDROM(paddr); + putlog(2, "$%08x.B (IDROM) -> $%02x", paddr, data.Data()); break; case 2: // e1c0'02xx // 割り込みステータス data = interrupt->PeekStatus(); - putlog(1, "$%08x.B (IntStat) -> $%02x", addr, (uint32)data); + putlog(1, "$%08x.B (IntStat) -> $%02x", paddr, data.Data()); break; default: // e1c0'01xx // DIP-SW data = GetDIPSW(); - putlog(1, "$%08x.B (DIPSW) -> $%02x", addr, (uint32)data); + putlog(1, "$%08x.B (DIPSW) -> $%02x", paddr, data.Data()); break; } + data |= BusData::Size1; return data; } - - VMPANIC("Read8($%08x)", addr); - return data; + VMPANIC("Read($%08x)", paddr); } -uint64 -NewsCtlrDevice::Write8(uint32 addr, uint32 data) +busdata +NewsCtlrDevice::Write(busaddr addr, uint32 data) { - addr |= 0xc0000000; + uint32 paddr = addr.Addr() | 0xc0000000; + uint32 reqsize = addr.GetSize(); + data >>= (reqsize - 1) * 8; - if (addr == 0xe0c8'0000) { + if (paddr == 0xe0c8'0000) { // PWS-1560 FDC? putlog(0, "FDC <- $%02x (NOT IMPLEMENTED)", data); - return 0; - } - if (addr == 0xe0dc'0000) { + + } else if (paddr == 0xe0dc'0000) { WriteLED(data); - return 0; - } - if (addr == 0xe100'0000) { + + } else if (paddr == 0xe100'0000) { WriteTimer(data); - return 0; - } - if (addr == 0xe108'0000) { + + } else if (paddr == 0xe108'0000) { // Parity enable? putlog(0, "Parity enable? <- $%02x (NOT IMPLEMENTED)", data); - return 0; - } - if (addr == 0xe118'0000) { + + } else if (paddr == 0xe118'0000) { // Level2 Interrupt ? putlog(0, "Lv2 Interrupt disable? <- $%02x (NOT IMPLEMENTED)", data); - return 0; - } - if (addr == 0xe128'0000) { + + } else if (paddr == 0xe128'0000) { putlog(0, "AST disable? <- $%02x (NOT IMPLEMENTED)", data); - return 0; - } - if (addr == 0xe130'0000) { + + } else if (paddr == 0xe130'0000) { putlog(0, "L2 cache enable? <- $%02x (NOT IMPLEMENTED)", data); - return 0; - } - if (addr == 0xe138'0000) { + + } else if (paddr == 0xe138'0000) { putlog(0, "Power Control <- $%02x (NOT IMPLEMENTED)", data); - return 0; - } - if (addr == 0xe190'0000) { + + } else if (paddr == 0xe190'0000) { putlog(0, "L2 cache disable? <- $%02x (NOT IMPLEMENTED)", data); - return 0; - } - if (addr == 0xe1a0'0000) { + + } else if (paddr == 0xe1a0'0000) { putlog(0, "Parity disable? <- $%02x (NOT IMPLEMENTED)", data); - return 0; - } - if (addr == 0xe1c0'0200) { + + } else if (paddr == 0xe1c0'0200) { // XXX たぶん 0xe1c0'02ff まで全部同じかも putlog(0, "Parity Vector? <- $%02x (NOT IMPLEMENTED)", data); - return 0; + + } else { + VMPANIC("Write($%08x) <- $%02x", paddr, data); } - VMPANIC("Write8($%08x) <- $%02x", addr, data); - return (uint64)-1; + busdata r = BusData::Size1; + return r; } -uint64 -NewsCtlrDevice::Peek8(uint32 addr) +busdata +NewsCtlrDevice::Peek1(uint32 addr) { addr |= 0xc0000000; @@ -211,7 +209,47 @@ NewsCtlrDevice::Peek8(uint32 addr) } } - return (uint64)-1; + return BusData::BusErr; +} + +// NewsIO の下請けとして呼ばれる。 +void +NewsCtlrDevice::MonitorUpdateNewsCtlr(TextScreen& screen, int y) +{ + // テーブル方式ではないので、Read/Write と手動で揃える…。 + + uint32 addr = 0xe100; + for (int i = 0; i < 32; i++) { + screen.Print(0, y, "$%04x'0000:", addr); + + const char *name = NULL; + TA attr; + for (int j = 0; j < 8; j++) { + switch (addr) { + case 0xe100: name = "Timer"; break; + case 0xe108: name = "ParEn?"; break; + case 0xe118: name = "Lv2Int?"; break; + case 0xe128: name = "ASTDis?"; break; + case 0xe130: name = "L2CE?"; break; + case 0xe138: name = "Power"; break; + case 0xe190: name = "L2CD?"; break; + case 0xe1a0: name = "ParDis?"; break; + case 0xe1c0: name = "Misc"; break; + default: + name = NULL; + break; + } + if (name) { + attr = TA::Normal; + } else { + name = "NopIO"; + attr = TA::Disable; + } + screen.Puts(12 + j * 8, y, attr, name); + addr++; + } + y++; + } } // IDROM の値を返す。この関数は副作用を起こしてはいけない。 @@ -286,8 +324,13 @@ NewsCtlrDevice::TimerCallback(Event& ev) timer_intr = true; ChangeInterrupt(); - // XXX clock-sync はまた後ほど - scheduler->RestartEvent(ev); + // 足す前は前回の割り込み発生時刻なので period を足すと現在時刻。 + if (sync_rt) { + stime += TIMER_PERIOD; + scheduler->StartRealtimeEvent(ev, stime, TIMER_PERIOD); + } else { + scheduler->RestartEvent(ev); + } } // 割り込み信号線の状態を変える