--- nono/vm/goldfish_timer.cpp 2026/04/29 17:05:25 1.1 +++ nono/vm/goldfish_timer.cpp 2026/04/29 17:05:50 1.1.1.6 @@ -48,8 +48,11 @@ // 読み込み時は割り込み許可なら $1、禁止なら $0。 #include "goldfish_timer.h" +#include "event.h" #include "goldfish_pic.h" #include "goldfish_rtc.h" +#include "monitor.h" +#include "mpu.h" #include "scheduler.h" #include "syncer.h" @@ -61,14 +64,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 +79,6 @@ GFTimerDevice::~GFTimerDevice() bool GFTimerDevice::Init() { - if (inherited::Init() == false) { - return false; - } - // 割り込み信号線の接続先 auto gfpic = GetGFPICDevice(6); gfpic->RegistIRQ(1, "GFTimer", this); @@ -92,13 +87,17 @@ GFTimerDevice::Init() gfrtc = dynamic_cast(GetRTCDevice()); syncer = GetSyncer(); + auto evman = GetEventManager(); + event = evman->Regist(this, NULL, "Goldfish Timer"); + // クロックの同期方法 - sync_rt = GetRTCDevice()->GetSyncRealtime(); + sync_rt = syncer->GetSyncRealtime(); + // それによってイベントを分けてある。(time はどちらも都度セットする) if (sync_rt) { - event.func = ToEventCallback(&GFTimerDevice::CallbackRT); + event->func = ToEventCallback(&GFTimerDevice::CallbackRT); } else { - event.func = ToEventCallback(&GFTimerDevice::CallbackVT); + event->func = ToEventCallback(&GFTimerDevice::CallbackVT); } return true; @@ -120,9 +119,8 @@ GFTimerDevice::ResetHard(bool poweron) } busdata -GFTimerDevice::Read32(uint32 addr) +GFTimerDevice::ReadPort(uint32 offset) { - uint32 offset = addr & 0xfff; busdata data; switch (offset) { @@ -150,22 +148,23 @@ GFTimerDevice::Read32(uint32 addr) break; case GFRTC::ALARM_STATUS: - data = event.IsRunning() ? 1 : 0; + data = event->IsRunning() ? 1 : 0; putlog(2, "ALARM_STATUS -> $%08x", data.Data()); 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 +211,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: - return event.IsRunning() ? 1 : 0; - + case GFRTC::ALARM_STATUS: + return event->IsRunning() ? 1 : 0; default: - return busdata::BusErr; + return BusData::BusErr; } } @@ -312,29 +272,40 @@ 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(); - event.code = 1; + // event->code は VT モードの時には不要だが気にせず立てる。 + // 指定されたアラームがすでに過去の時刻なら 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); } // 実時間モードでのコールバック。 void -GFTimerDevice::CallbackRT(Event& ev) +GFTimerDevice::CallbackRT(Event *ev) { // アラーム開始後最初の1回だけ自分の時間軸をアラーム分だけ進める。 - if (event.code) { - mtime += ev.time; - event.code = 0; + if (event->code) { + mtime += event->time; + event->code = 0; } uint64 mnow = syncer->GetRealTime() - mtime_epoch; @@ -343,7 +314,7 @@ GFTimerDevice::CallbackRT(Event& ev) // もう一度このイベントに来る。 scheduler->RestartEvent(event); } else { - // システムの実時間軸に追い付いてなければ(通常動作)、アラーム発砲。 + // システムの実時間軸に追い付いてなければ(通常動作)、アラーム発報。 intr_assert = true; ChangeInterrupt(); } @@ -351,7 +322,7 @@ GFTimerDevice::CallbackRT(Event& ev) // 仮想時間モードでのコールバック。 void -GFTimerDevice::CallbackVT(Event& ev) +GFTimerDevice::CallbackVT(Event *ev) { // 仮想時間モードなら、イベントが起きたここがゴール。 // アラームは単発イベントなのでリスタート不要。