--- nono/vm/vm.cpp 2026/04/29 17:05:25 1.1.1.11 +++ nono/vm/vm.cpp 2026/04/29 17:05:50 1.1.1.15 @@ -10,14 +10,13 @@ #include "vm.h" #include "debugger.h" +#include "event.h" #include "mainapp.h" #include "mainbus.h" -#include "mainram.h" -#include "mpu.h" -#include "power.h" #include "scheduler.h" #include "signalthread.h" #include "syncer.h" +#include "uimessage.h" // コンストラクタ VM::VM(const char *vmname_) @@ -26,9 +25,13 @@ VM::VM(const char *vmname_) assert(vmname); // SignalThread は他のスレッドより先に起動する必要があるので、先頭。 + // EventManager は Scheduler に必要。 // Scheduler は以降の他のデバイスからのイベント登録を受け付ける必要が // あるためその次。 + // Debugger は HostCOM と stdio ドライバが競合した場合に優先したいため + // もあって必ず先に配置する必要がある。 NEWDV(SignalThread, new SignalThread()); + NEWDV(EventManager, new EventManager()); NEWDV(Scheduler, new Scheduler()); NEWDV(Syncer, new Syncer()); NEWDV(Debugger, new Debugger()); @@ -44,7 +47,10 @@ VM::~VM() void VM::Dispose() { - // まずスレッドを止める。 + // (もう止まってるはずだが) 念のため UIMessage の送出を止める。 + gMainApp.GetUIMessage()->StopUIMessage(); + + // スレッドを止める。 // デバッガスレッドがスケジューラスレッドにアクセスするのでデバッガが先。 if ((bool)pDebugger) { GetDebugger()->TerminateThread(); @@ -70,25 +76,58 @@ VM::Dispose() pScheduler.reset(); } + if ((bool)pEventManager) { + pEventManager.reset(); + } + // ほかのオブジェクトの解放はグローバルデストラクタにおまかせ。 // だめだったらまた考える。 } -// コンストラクタ後の初期化 +// 動的コンストラクション。 bool -VM::Create() +VM::Create(VM::CreationPhase phase) { // d->Create() は Object を追加する場合があるため、ここで - // ranged for は使えない。また追加されたデバイスの Create() も + // ranged for は使えない。また追加されたデバイスの Create()/Create2() も // 実行したいため、ループ終了条件で毎回 size() を取り出して比較する。 for (int i = 0; i < gMainApp.GetObjects().size(); i++) { auto dev = dynamic_cast(gMainApp.GetObjects()[i]); if (dev) { - if (!dev->Create()) { - return false; + if (phase == CreationPhase::First) { + if (!dev->Create()) { + return false; + } + } else { + if (!dev->Create2()) { + return false; + } + } + } + } + + // ログのためのメンバ変数初期化。 + // 同じオブジェクトに対して複数回呼んでも副作用はない。 + for (auto obj : gMainApp.GetObjects()) { + auto dev = dynamic_cast(obj); + if (dev) { + dev->EarlyInit(); + } + } + + // 名無しオブジェクトがあれば開発中に検出したい。 + // 名無しでも動作には影響ないのでリリース版では怒られないでほしい。 +#if !defined(RELEASE) + for (auto obj : gMainApp.GetObjects()) { + if (obj->GetName().empty()) { + printf("Objects:\n"); + for (auto o : gMainApp.GetObjects()) { + printf("%s\n", o->GetName().c_str()); } + assert(obj->GetName().empty() == false); } } +#endif return true; } @@ -112,6 +151,12 @@ VM::Init() return false; } + // イベントが出揃ったのでスケジューラモニタの行数を確定。 + auto scheduler = dynamic_cast(pScheduler.get()); + if (scheduler->Init2() == false) { + return false; + } + return true; } @@ -126,22 +171,6 @@ VM::StartThread() return false; } } - } - - return true; -} - -// 設定の適用 -bool -VM::Apply() -{ - for (auto obj : gMainApp.GetObjects()) { - auto dev = dynamic_cast(obj); - if (dev) { - if (!dev->Apply()) { - return false; - } - } } return true;