--- nono/vm/sysclk.cpp 2026/04/29 17:05:10 1.1.1.10 +++ nono/vm/sysclk.cpp 2026/04/29 17:05:59 1.1.1.20 @@ -11,51 +11,50 @@ // システムクロックは実時間または仮想時間のいずれかに同期するため、 // システムクロック独自の時刻 stime を持つ。 // stime は、割り込みを発生させるごとに、LUNA-I なら 16.67msec、 -// LUNA88k なら 10msec 進行する。 +// LUNA-88K なら 10msec 進行する。 #include "sysclk.h" #include "config.h" +#include "event.h" #include "interrupt.h" -#include "rtc.h" +#include "monitor.h" #include "scheduler.h" -#include "sync.h" - -// グローバル参照用 -SysClkDevice *gSysClk; +#include "syncer.h" // コンストラクタ SysClkDevice::SysClkDevice() - : inherited("SystemClock") + : inherited(OBJ_SYSCLK) { - AddAlias("SysClk"); - - devaddr = 0x63000000; - - monitor.func = ToMonitorCallback(&SysClkDevice::MonitorUpdate); - monitor.SetSize(31, 2); - monitor.Regist(ID_MONITOR_SYSCLK); - - event.func = ToEventCallback(&SysClkDevice::Callback); - event.code = 0; - event.Regist("System Clock"); + monitor = gMonitorManager->Regist(ID_MONITOR_SYSCLK, this); + monitor->SetCallback(&SysClkDevice::MonitorScreen); + monitor->SetSize(32, 4); } // デストラクタ SysClkDevice::~SysClkDevice() { - gSysClk = NULL; } +// 初期化 bool SysClkDevice::Init() { + interrupt = GetInterruptDevice(); + // クロックは機種ごとに異なる - const ConfigItem& item = gConfig->Find("!sysclk-period"); - period = item.AsInt(); - event.time = period; + const ConfigItem& item = gConfig->Find("!sysclk-freq"); + freq = item.AsInt(); + period = 1_sec / freq; // クロックの同期方法 - sync_rt = gRTC->GetSyncRealtime(); + syncer = GetSyncer(); + sync_rt = syncer->GetSyncRealtime(); + + auto evman = GetEventManager(); + event = evman->Regist(this, + ToEventCallback(&SysClkDevice::Callback), + "System Clock"); + event->time = period; return true; } @@ -67,40 +66,53 @@ SysClkDevice::ResetHard(bool poweron) // XXX たぶん電源オンだけで作用する? if (poweron) { if (sync_rt) { - stime = gSync->GetRealTime(); + stime = GetSyncer()->GetRealTime(); } // 電源オンですぐ起動 - sysint = false; - gScheduler->RestartEvent(event); + scheduler->RestartEvent(event); } + + // さすがに割り込みネゲートくらいするよな? + sysint = false; + ChangeInterrupt(); } -uint64 -SysClkDevice::Read(uint32 offset) +busdata +SysClkDevice::ReadPort(uint32 offset) { // 1 ポートしかない - return GetInt(); + busdata data = GetInt(); + data |= BusData::Size1; + return data; } -uint64 -SysClkDevice::Write(uint32 offset, uint32 data) +busdata +SysClkDevice::WritePort(uint32 offset, uint32 data) { // 何か書き込まれたら、フラグをクリア - putlog(1, "システムクロック割り込みクリア"); + putlog(3, "Clear system clock interrupt"); sysint = false; - gInterrupt->NegateINT(this); - return 0; + ChangeInterrupt(); + + busdata r = BusData::Size1; + return r; } -uint64 -SysClkDevice::Peek(uint32 offset) +busdata +SysClkDevice::PeekPort(uint32 offset) { return GetInt(); } +bool +SysClkDevice::PokePort(uint32 offset, uint32 data) +{ + return false; +} + void -SysClkDevice::MonitorUpdate(Monitor *, TextScreen& screen) +SysClkDevice::MonitorScreen(Monitor *, TextScreen& screen) { int y; @@ -108,8 +120,26 @@ SysClkDevice::MonitorUpdate(Monitor *, T y = 0; int width = stime < 86400_sec ? 20 : 25; - screen.Print(0, y++, "Sync: %s", sync_rt ? "Real Time" : "Virtual Time"); - screen.Print(0, y++, "Time: %*s", width, TimeToStr(stime).c_str()); + screen.Print(0, y++, "Freq: %u Hz", freq); + if (sync_rt) { + screen.Puts(0, y++, "Sync: Real Time"); + screen.Print(0, y++, "Time: %*s", width, TimeToStr(stime).c_str()); + + // TimeToStr は負は想定していないし、符号は数値の直前に足したい。 + screen.Puts(0, y, "Diff:"); + bool neg = false; + if (delta < 0) { + delta = -delta; + neg = true; + } + std::string s = TimeToStr(delta); + int offset = width - s.size(); + screen.Print(6 + offset, y++, "%c%s", (neg ? '-' : '+'), s.c_str()); + } else { + screen.Puts(0, y++, "Sync: Virtual Time"); + screen.Puts(0, y++, TA::Disable, "Time:"); + screen.Puts(0, y++, TA::Disable, "Diff:"); + } } // 割り込み状態を取得(?) @@ -126,20 +156,31 @@ SysClkDevice::GetInt() const // イベントハンドラ void -SysClkDevice::Callback(Event& ev) +SysClkDevice::Callback(Event *ev) { - putlog(3, "システムクロック割り込み発生"); - - // システムクロックとしての現在時刻。 - // 足す前は前回の割り込み発生時刻なので period を足すと現在時刻。 - stime += period; + putlog(3, "Interrupt occured"); sysint = true; - gInterrupt->AssertINT(this); + ChangeInterrupt(); if (sync_rt) { - gScheduler->StartRealtimeEvent(ev, stime, period); + // システムクロックとしての現在時刻。 + // 足す前は前回の割り込み発生時刻なので period を足すと現在時刻。 + stime += period; + + // ホスト時間とここで作った実時間との差。 + uint64 now = syncer->GetRealTime(); + delta = (int64)(now - stime); + + scheduler->StartRealtimeEvent(ev, stime, period); } else { - gScheduler->StartEvent(ev); + scheduler->StartEvent(ev); } } + +// 割り込み信号線の状態を変える。 +void +SysClkDevice::ChangeInterrupt() +{ + interrupt->ChangeINT(this, sysint); +}