--- nono/vm/scheduler.cpp 2026/04/29 17:04:39 1.1.1.5 +++ nono/vm/scheduler.cpp 2026/04/29 17:04:42 1.1.1.6 @@ -130,7 +130,7 @@ Scheduler::ThreadRun() rtimestart = GetRealTime(); rtc_last_clock = rtimestart; - cycle = INT64_MAX; + cycle = 0; mode = 0; for (;;) { req = atomic_reqflag.exchange(0); @@ -138,10 +138,14 @@ Scheduler::ThreadRun() if ((req & REQ_SYNC)) { // スケジューラを同期モードに mode |= SCHED_SYNC; + // 同期モードでは RAM アクセスはデバイス経由 + ::direct_ram_size = 0; } if ((req & REQ_FAST)) { // スケジューラを高速モードに mode &= ~SCHED_SYNC; + // 高速モードでは RAM は直接アクセス + ::direct_ram_size = ::ram_size; } if ((req & REQ_RUN)) { // MPU が通常状態になった @@ -178,6 +182,15 @@ Scheduler::ThreadRun() req &= ~REQ_POWER_OFF; } + if ((req & REQ_RESET)) { + // リセット要求の場合 + + // 全デバイスをリセット + gVM->ResetHard(); + + req &= ~REQ_RESET; + } + if ((req & REQ_EXIT)) { // 終了要求 // この for ブロックをいきなり抜けるだけなので @@ -197,42 +210,46 @@ Scheduler::ThreadRun() rtc_last_clock += 31.25_msec; } - // まず CPU を駆動する。MPU::Run() はデバイスアクセスなどによって - // スケジューラにイベントが登録されると、その命令の終了とともに - // 処理を打ち切って戻ってくる。 - // ここでイベントリストを調べ、その時点から最も早く発生するイベント - // までの必要サイクル数が、次のループでの駆動サイクル数になる。 - - // CPU 駆動 - uint32 outer; - outer = gMPU->Run(cycle); + // イベントリストを調べ現時点から最も早く発生するイベントまでの必要 + // サイクル数を求めて、このサイクル数だけ MPU を駆動する。 + // MPU 実行中にデバイスアクセスなどによってスケジューラにイベントが + // 登録されると、その命令の終了とともに処理を打ち切って戻ってくる。 + // また、電源オン(リセット)時には MPU デバイスが 0 サイクル目で + // MPU リセット例外イベントを起こすようになっている。 // イベント for (;;) { - evcs.lock(); - if (eventlist.empty()) { - cycle = INT64_MAX; - break; - } - Event *e = eventlist.front(); - if (gMPU->total_cycle() < e->cycle) { - // まだ時刻に到達していない - cycle = e->cycle - gMPU->total_cycle(); - break; + Event *e; + // ロック区間 + { + std::lock_guard lock(evcs); + + if (eventlist.empty()) { + cycle = INT64_MAX; + break; + } + e = eventlist.front(); + if (gMPU->total_cycle() < e->cycle) { + // まだ時刻に到達していない + cycle = e->cycle - gMPU->total_cycle(); + break; + } + + // 到達したのでこのイベントをリストから削除 + e->active = false; + eventlist.pop_front(); } - // 到達したのでこのイベントをリストから削除 - e->active = false; - eventlist.pop_front(); - evcs.unlock(); - // コールバック e->dev->putlog(3, "イベント '%s' 時刻到達", e->GetName().c_str()); - ((e->dev)->*(e->func))(e->code); + ((e->dev)->*(e->func))(*e); // 同時刻のイベントがあるかも知れないのでなくなるまで調べる } - evcs.unlock(); + + // CPU 駆動 + uint32 outer; + outer = gMPU->Run(cycle); // 同期モードなら実時間調整。 // あるいは高速モードであってもストップ状態なら実時間駆動する。 @@ -443,7 +460,6 @@ Scheduler::MonitorUpdate(TextScreen& mon monitor.Print(0, y++, "Req: %08x", (uint32)atomic_reqflag); monitor.Print(0, y++, "MPU Speed: %d.%03dMHz", (mpu_clock / 1000), (mpu_clock % 1000)); - uint64 cycle = gMPU->total_cycle(); uint64 vt = GetVirtTime(); uint64 rt = GetRealTime(); uint64 relvt = vt - vtimebase; @@ -473,12 +489,22 @@ Scheduler::MonitorUpdate(TextScreen& mon monitor.Puts(x + 32, y, "Description"); monitor.Puts(x + 58, y, "Code"); y++; + + uint64 cycle = gMPU->total_cycle(); for (const auto& e : gEvents) { uint64 rem; TA attr; if (e->active) { attr = TA::Normal; - rem = Cycle2Vtime(e->cycle - cycle); + if (e->cycle > cycle) { + rem = Cycle2Vtime(e->cycle - cycle); + } else { + // XXX 実際には起きないけど、この表示をするにあたって + // スケジューラスレッドと一切調停していないので、仮想時刻が + // e->cycle (イベント発生時刻) をすぎていることがある。 + // すぎてるので残り時間 0 と表示しておく。 + rem = 0; + } } else { attr = TA::Disable; rem = 0;