--- nono/vm/syncer.cpp 2026/04/29 17:05:17 1.1.1.1 +++ nono/vm/syncer.cpp 2026/04/29 17:05:50 1.1.1.7 @@ -10,9 +10,9 @@ #include "syncer.h" #include "config.h" -#include "mainapp.h" -#include "mainbus.h" -#include "mainram.h" +#include "event.h" +#include "monitor.h" +#include "mpu680x0.h" #include "scheduler.h" //#define DEBUG @@ -33,10 +33,6 @@ Syncer::Syncer() for (int i = 0; i < perfq.Capacity(); i++) { perfq.Enqueue(1000); } - - sync_event.func = ToEventCallback(&Syncer::SyncCallback); - sync_event.time = 50_msec; - sync_event.Regist("Sync"); } // デストラクタ @@ -48,22 +44,36 @@ Syncer::~Syncer() bool Syncer::Init() { - if (inherited::Init() == false) { - return false; - } + mpu680x0 = dynamic_cast(mpu); - mainbus = GetMainbusDevice(); - mainram = GetMainRAMDevice(); - - mode = SCHED_POWEROFF; + mode = SYNCMODE_POWEROFF; overslept = 0; + dmac_idle = 1; // 高速モード指定 bool fast_mode = gConfig->Find("fast-mode").AsInt(); RequestFullSpeed(fast_mode); + // クロックの同期方法 + const ConfigItem& sync_item = gConfig->Find("clock-sync"); + auto clock_sync = sync_item.AsString(); + if (clock_sync == "real") { + sync_realtime = true; + } else if (clock_sync == "virtual") { + sync_realtime = false; + } else { + sync_item.Err(); + return false; + } + scheduler->ConnectMessage(MessageID::SCHEDULER_SYNCMODE, this, - ToMessageCallback(&Syncer::ChangeModeCallback)); + ToMessageCallback(&Syncer::ChangeModeMessage)); + + auto evman = GetEventManager(); + sync_event = evman->Regist(this, + ToEventCallback(&Syncer::SyncCallback), + "Sync"); + sync_event->time = 50_msec; return true; } @@ -98,6 +108,7 @@ Syncer::StartTime() // パフォーマンス表示用。 // 最初の集計が行われる起動後1秒までは、この値が表示されるので // インチキして 100% にしておく。 + clock_khz = mpu->GetClockSpeed(); perf_counter = 100; last_perf_rtime = rtime_epoch; last_perf_vtime = vtime_epoch; @@ -111,7 +122,23 @@ Syncer::RequestCPUMode(uint32 cpumode) { uint32 newmode; - newmode = (mode & ~SCHED_CPU_MASK) | cpumode; + halt = cpumode & SYNCMODE_CPU_HALT; + cpu_idle = cpumode & SYNCMODE_CPU_STOP; + + newmode = (mode & ~SYNCMODE_CPU_MASK) | halt | (cpu_idle & dmac_idle); + + ChangeMode(newmode); +} + +// DMAC のアクティブ状態を指示する。 +void +Syncer::RequestDMACActive(bool active) +{ + uint32 newmode; + + dmac_idle = active ? 0 : SYNCMODE_IDLE; + + newmode = (mode & ~SYNCMODE_IDLE) | (cpu_idle & dmac_idle); ChangeMode(newmode); } @@ -125,22 +152,6 @@ Syncer::RequestFullSpeed(bool enable) scheduler->SendMessage(MessageID::SCHEDULER_SYNCMODE, enable); } -// ブートページモードの変更を指示する。 -// (VM::SwitchBootPage から呼ぶので個別には呼ばないこと) -void -Syncer::RequestBootPageMode(bool isrom) -{ - uint32 newmode; - - if (isrom) { - newmode = mode | SCHED_BOOT; - } else { - newmode = mode & ~SCHED_BOOT; - } - - ChangeMode(newmode); -} - // キー入力状態の変更を指示する。 void Syncer::RequestKeyPressed(bool pressed) @@ -148,9 +159,9 @@ Syncer::RequestKeyPressed(bool pressed) uint32 newmode; if (pressed) { - newmode = mode | SCHED_KEY; + newmode = mode | SYNCMODE_KEY; } else { - newmode = mode & ~SCHED_KEY; + newmode = mode & ~SYNCMODE_KEY; } ChangeMode(newmode); @@ -163,9 +174,9 @@ Syncer::RequestPowerOffMode(bool powerof uint32 newmode; if (poweroff) { - newmode = mode | SCHED_POWEROFF; + newmode = mode | SYNCMODE_POWEROFF; } else { - newmode = mode & ~SCHED_POWEROFF; + newmode = mode & ~SYNCMODE_POWEROFF; } ChangeMode(newmode); @@ -173,22 +184,22 @@ Syncer::RequestPowerOffMode(bool powerof // 動作状態変更のメッセージコールバック void -Syncer::ChangeModeCallback(MessageID msgid, uint32 arg) +Syncer::ChangeModeMessage(MessageID msgid, uint32 arg) { uint32 newmode; if (msgid == MessageID::SCHEDULER_SYNCMODE) { if (arg) { - newmode = mode & ~SCHED_SYNC; + newmode = mode & ~SYNCMODE_SYNC; } else { - newmode = mode | SCHED_SYNC; + newmode = mode | SYNCMODE_SYNC; } ChangeMode(newmode); } } -// メンバ変数 mode_request に従ってスケジューラの動作状態を変更。 +// newmode に従ってスケジューラの動作状態を変更。 // 自スレッドから呼ぶこと。 void Syncer::ChangeMode(uint32 newmode) @@ -205,17 +216,10 @@ Syncer::ChangeMode(uint32 newmode) if (newmode == 0) { // 高速モードに putlog(2, "Fast mode"); - - // 高速モードでは RAM は直接アクセス - mainbus->direct_ram_size = mainram->GetSize(); - } else { // 同期モードに putlog(2, "Sync mode"); - // 同期モードでは RAM アクセスはデバイス経由 - mainbus->direct_ram_size = 0; - // 同期用の基準点を設置。 // ゲストが STOP 命令による定常状態にいる時は // 割り込みなど短期間だけ高速モードになるのを繰り返す。 @@ -241,7 +245,7 @@ Syncer::ChangeMode(uint32 newmode) // 同期イベント void -Syncer::SyncCallback(Event& ev) +Syncer::SyncCallback(Event *ev) { DPRINTF("SyncCallback\n"); DoSync(); @@ -252,7 +256,6 @@ Syncer::SyncCallback(Event& ev) // 同期処理 // ここで仮想時間を実時間と同期させる。 -// スリープしすぎた実時間を返す。 void Syncer::DoSync() { @@ -268,7 +271,7 @@ Syncer::DoSync() } // XXX 次回 Start する時のイベント間隔をここ(DoSync())で事前に決めている - sync_event.time = 50_msec; + sync_event->time = 50_msec; // 同期モードなら.. if (mode != 0) { @@ -301,7 +304,7 @@ Syncer::DoSync() } else if (realslept < diff) { uint64 under = diff - realslept; if (under > overslept) { - sync_event.time = 0; + sync_event->time = 0; } } } else if (rspan > vspan + overslept) { @@ -326,14 +329,7 @@ Syncer::CalcPerf() // 百分率で小数以下1桁分までとなるよう整数で計算する perfq.EnqueueForce((uint32)(vperf * 1000 / rperf)); // 移動平均を求める (perfq は常に要素数分埋めてある) - int ma = 0; - int qlen = perfq.Length(); - __assume(qlen > 0); - for (int i = 0; i < qlen; i++) { - auto v = perfq.Peek(i); - ma += v; - } - ma /= qlen; + uint ma = perfq.GetMovingAverage(); // 最下位を四捨五入して捨てる (整数%になる) ma = (ma + 5) / 10; perf_counter = ma; @@ -342,6 +338,11 @@ Syncer::CalcPerf() last_sync_count = sync_count; sync_count = 0; + // 関係ないけど、ついでにここで MPU 内の各種移動平均をとる。 + if (mpu680x0) { + mpu680x0->CalcStat(); + } + last_perf_rtime = rtime; last_perf_vtime = vtime; next_perf_rtime = rtime + PERF_INTERVAL; @@ -354,9 +355,9 @@ Syncer::PutlogRealtime() uint64 vtime = scheduler->GetVirtTime(); // 電源オン時からここまでの時間を表示するだけでリセット等はしない。 - putlog(0, "Elapsed time since power-on: %d.%03d sec, %6.2f%%", - (int)(rtime / (1000 * 1000 * 1000)), - (int)((rtime / (1000 * 1000)) % 1000), + putlog(0, "Elapsed since power-on: %u.%03u sec, %6.2f%%", + (uint)(rtime / (1000 * 1000 * 1000)), + (uint)((rtime / (1000 * 1000)) % 1000), (double)vtime / rtime * 100); #if 0 @@ -371,54 +372,67 @@ Syncer::PutlogRealtime() // モニタ更新の下請け (Scheduler から呼ばれる) int -Syncer::MonitorUpdateSub(TextScreen& screen, uint64 vtime) +Syncer::MonitorUpdateSub(TextScreen& screen, uint64 tmp_vtime) { int y = 0; - screen.Print(0, y, "Mode: 0x%04x (", mode); - switch (mode & SCHED_CPU_MASK) { - case SCHED_CPU_NORMAL: + // 一応ローカルコピー。 + uint32 tmp_mode = mode; + uint64 tmp_rtime = rtime; + uint64 sync_rt_delta = tmp_rtime - rtime_epoch; + uint64 sync_vt_delta = tmp_vtime - vtime_epoch; + + screen.Print(0, y, "Mode: 0x%04x (", tmp_mode); + switch (tmp_mode & SYNCMODE_CPU_MASK) { + case SYNCMODE_CPU_NORMAL: screen.Puts(14, y, TA::Off, "Run"); break; - case SCHED_CPU_STOP: + case SYNCMODE_CPU_STOP: screen.Puts(14, y, TA::On, "STOP"); break; - case SCHED_CPU_HALT: + case SYNCMODE_CPU_HALT: screen.Puts(14, y, TA::On, "HALT"); break; } - if ((mode & SCHED_SYNC)) { + if ((tmp_mode & SYNCMODE_SYNC)) { screen.Puts(19, y, TA::On, "Sync"); } else { screen.Puts(19, y, TA::Off, "Full"); } - screen.Puts(24, y, TA::OnOff((mode & SCHED_BOOT)), "Boot"); - screen.Puts(29, y, TA::OnOff((mode & SCHED_KEY)), "Key"); - screen.Puts(34, y, TA::OnOff((mode & SCHED_POWEROFF)), "POff"); - screen.Puts(38, y, ")"); + screen.Puts(24, y, TA::OnOff((tmp_mode & SYNCMODE_KEY)), "Key"); + screen.Puts(29, y, TA::OnOff((tmp_mode & SYNCMODE_POWEROFF)), "POff"); + screen.Puts(33, y, ")"); y++; - uint64 rt = rtime; - uint64 vt = vtime; - auto s_rt = TimeToStr(rt); - auto s_vt = TimeToStr(vt); - std::string s_sync_rt {}; - std::string s_sync_vt {}; - if (mode != 0) { - uint64 sync_rt = rtime - rtime_epoch; - uint64 sync_vt = vtime - vtime_epoch; - s_sync_rt = TimeToStr(sync_rt); - s_sync_vt = TimeToStr(sync_vt); - } // 日まで表示しようとするときは桁位置を動かす - int width = std::max(rt, vt) < 86400_sec ? 20 : 25; - - screen.Print(0, y++, "Total Real Time: %*s", width, s_rt.c_str()); - screen.Print(4, y++, "Virtual Time: %*s", width, s_vt.c_str()); - screen.Print(0, y++, "Sync Real Time: %*s", width, s_sync_rt.c_str()); - screen.Print(4, y++, "Virtual Time: %*s", width, s_sync_vt.c_str()); + int width = std::max(tmp_rtime, tmp_vtime) < 86400_sec ? 20 : 25; - screen.Print(0, y++, "Performance : %4d%%", perf_counter); + std::string trt = TimeToStr(tmp_rtime); + std::string tvt = TimeToStr(tmp_vtime); + // 012345678901234567 + screen.Print(0, y++, "Total Real Time: %*s", width, trt.c_str()); + screen.Print(4, y++, "Virtual Time: %*s", width, tvt.c_str()); + screen.Puts(0, y + 0, "Sync Real Time:"); + screen.Puts(4, y + 1, "Virtual Time:"); + if (tmp_mode != 0) { + std::string srt = TimeToStr(sync_rt_delta); + std::string svt = TimeToStr(sync_vt_delta); + screen.Print(18, y + 0, "%*s", width, srt.c_str()); + screen.Print(18, y + 1, "%*s", width, svt.c_str()); + } + y += 2; + + screen.Puts(0, y, "Rating MPU Speed :"); + if (__predict_true((clock_khz % 1000) == 0)) { + screen.Print(21, y++, "%4u.%1uMHz", + clock_khz / 1000, (clock_khz / 100) % 10); + } else { + screen.Print(21, y++, "%4u.%03uMHz", + clock_khz / 1000, clock_khz % 1000); + } + uint eff_khz = clock_khz * perf_counter / 100; + screen.Print(0, y++, "Effective MPU Speed: %4u.%1uMHz (%4u%%)", + (eff_khz / 1000), (eff_khz / 100) % 10, perf_counter); int x = 52; int y1 = 0;