--- nono/vm/goldfish_timer.cpp 2026/04/29 17:05:25 1.1 +++ nono/vm/goldfish_timer.cpp 2026/04/29 17:05:43 1.1.1.5 @@ -50,6 +50,8 @@ #include "goldfish_timer.h" #include "goldfish_pic.h" #include "goldfish_rtc.h" +#include "monitor.h" +#include "mpu.h" #include "scheduler.h" #include "syncer.h" @@ -61,14 +63,10 @@ GFTimerDevice::GFTimerDevice() : inherited(OBJ_GFTIMER) { - // func は Init() で設定する - event.code = 0; - event.Regist("Goldfish Timer"); - // モニタは GFRTC + GFTimer で共有。 - monitor.func = ToMonitorCallback(&GFTimerDevice::MonitorUpdate); - monitor.SetSize(38, 7); - monitor.Regist(ID_MONITOR_RTC); + monitor = gMonitorManager->Regist(ID_MONITOR_RTC, this); + monitor->func = ToMonitorCallback(&GFTimerDevice::MonitorUpdate); + monitor->SetSize(38, 7); } // デストラクタ @@ -80,10 +78,6 @@ GFTimerDevice::~GFTimerDevice() bool GFTimerDevice::Init() { - if (inherited::Init() == false) { - return false; - } - // 割り込み信号線の接続先 auto gfpic = GetGFPICDevice(6); gfpic->RegistIRQ(1, "GFTimer", this); @@ -93,13 +87,16 @@ GFTimerDevice::Init() syncer = GetSyncer(); // クロックの同期方法 - sync_rt = GetRTCDevice()->GetSyncRealtime(); + sync_rt = syncer->GetSyncRealtime(); + // それによってイベントを分けてある。(time はどちらも都度セットする) if (sync_rt) { event.func = ToEventCallback(&GFTimerDevice::CallbackRT); } else { event.func = ToEventCallback(&GFTimerDevice::CallbackVT); } + event.SetName("Goldfish Timer"); + scheduler->RegistEvent(event); return true; } @@ -120,9 +117,8 @@ GFTimerDevice::ResetHard(bool poweron) } busdata -GFTimerDevice::Read32(uint32 addr) +GFTimerDevice::ReadPort(uint32 offset) { - uint32 offset = addr & 0xfff; busdata data; switch (offset) { @@ -155,17 +151,18 @@ GFTimerDevice::Read32(uint32 addr) break; default: - putlog(1, "Read unknown $%08x", addr); + putlog(1, "Read unknown $%08x", mpu->GetPaddr()); data.SetBusErr(); break; } + + data |= BusData::Size4; return data; } busdata -GFTimerDevice::Write32(uint32 addr, uint32 data) +GFTimerDevice::WritePort(uint32 offset, uint32 data) { - uint32 offset = addr & 0xfff; busdata r; switch (offset) { @@ -212,68 +209,29 @@ GFTimerDevice::Write32(uint32 addr, uint break; default: - putlog(1, "Write unknown $%08x <- $%08x", addr, data); - r = busdata::BusErr; + putlog(1, "Write unknown $%08x <- $%08x", mpu->GetPaddr(), data); + r = BusData::BusErr; break; } + r |= BusData::Size4; return r; } busdata -GFTimerDevice::Peek8(uint32 addr) +GFTimerDevice::PeekPort(uint32 offset) { - uint32 offset = addr & 0xfff; switch (offset) { - case GFRTC::TIME_LOW + 0: - case GFRTC::TIME_LOW + 1: - case GFRTC::TIME_LOW + 2: - case GFRTC::TIME_LOW + 3: - case GFRTC::TIME_HIGH + 0: - case GFRTC::TIME_HIGH + 1: - case GFRTC::TIME_HIGH + 2: - case GFRTC::TIME_HIGH + 3: - { - uint64 now = Now(); - switch (offset) { - case GFRTC::TIME_LOW + 0: - return (now >> 24) & 0xff; - case GFRTC::TIME_LOW + 1: - return (now >> 16) & 0xff; - case GFRTC::TIME_LOW + 2: - return (now >> 8) & 0xff; - case GFRTC::TIME_LOW + 3: - return now & 0xff; - - case GFRTC::TIME_HIGH + 0: - return (now >> 56) & 0xff; - case GFRTC::TIME_HIGH + 1: - return (now >> 48) & 0xff; - case GFRTC::TIME_HIGH + 2: - return (now >> 40) & 0xff; - case GFRTC::TIME_HIGH + 3: - return (now >> 32) & 0xff; - default: - __unreachable(); - } - } - - case GFRTC::INTR_STATUS + 0: - case GFRTC::INTR_STATUS + 1: - case GFRTC::INTR_STATUS + 2: - return 0; - case GFRTC::INTR_STATUS + 3: + case GFRTC::TIME_LOW: + return Now() & 0xffffffffU; + case GFRTC::TIME_HIGH: + return Now() >> 32; + case GFRTC::INTR_STATUS: return intr_assert ? 1 : 0; - - case GFRTC::ALARM_STATUS + 0: - case GFRTC::ALARM_STATUS + 1: - case GFRTC::ALARM_STATUS + 2: - return 0; - case GFRTC::ALARM_STATUS + 3: + case GFRTC::ALARM_STATUS: return event.IsRunning() ? 1 : 0; - default: - return busdata::BusErr; + return BusData::BusErr; } } @@ -312,17 +270,28 @@ GFTimerDevice::Now() const void GFTimerDevice::StartAlarm() { + uint64 now = Now(); + if (__predict_false(mtime_epoch == 0)) { // 最初のアラーム書き込み時を修正実時間軸の基準点にする。 - mtime_epoch = syncer->GetRealTime(); - mtime = mtime_epoch; + mtime_epoch = now; + mtime = 0; } // 仮想時間モードなら ALARM 時刻に発火するイベントをセットするだけ。 // 実時間モードならひとまず仮に本来の仮想時刻にイベントは起こすが、 // 割り込みを上げるかどうかは向こうで調整する。 // event.code は VT モードの時には不要だが気にせず立てる。 - event.time = alarm - Now(); + // 指定されたアラームがすでに過去の時刻なら QEMU は即発火するようだ。 + if (__predict_true(alarm > now)) { + event.time = alarm - now; + } else { + if (__predict_false(loglevel >= 1)) { + uint64 delta = now - alarm; + putlogn("ALARM: past alarm -%s", TimeToStr(delta).c_str()); + } + event.time = 0; + } event.code = 1; scheduler->RestartEvent(event); } @@ -343,7 +312,7 @@ GFTimerDevice::CallbackRT(Event& ev) // もう一度このイベントに来る。 scheduler->RestartEvent(event); } else { - // システムの実時間軸に追い付いてなければ(通常動作)、アラーム発砲。 + // システムの実時間軸に追い付いてなければ(通常動作)、アラーム発報。 intr_assert = true; ChangeInterrupt(); }