--- nono/vm/vm.cpp 2026/04/29 17:04:53 1.1.1.7 +++ nono/vm/vm.cpp 2026/04/29 17:05:10 1.1.1.8 @@ -4,32 +4,40 @@ // Licensed under nono-license.txt // +// +// VM (基本クラス) +// + #include "vm.h" -#include "bus.h" +#include "debugger_private.h" #include "mainapp.h" #include "mpu.h" -#include "mythread.h" +#include "power.h" #include "ram.h" -#include "renderer.h" -#include "rtc.h" #include "scheduler.h" +#include "signalthread.h" +#include "sync.h" -std::unique_ptr gVM; +// グローバル参照用 +VM *gVM; // コンストラクタ VM::VM() { - // どこでやるのがいいかわからんけど、このコンストラクタはメインスレッドで - // 作られるので、ここでメインスレッドの名前を設定。 - PTHREAD_SETNAME("Main"); + // SignalThread は他のスレッドより先に起動する必要があるので、先頭。 + // Scheduler は以降の他のデバイスからのイベント登録を受け付ける必要が + // あるためその次。 + NEWDV(SignalThread, new SignalThread()); + NEWDV(Scheduler, new Scheduler()); + NEWDV(Sync, new Sync()); + NEWDV(Power, new PowerDevice()); + NEWDV(Debugger, new Debugger()); - // バスエラーデバイスだけここで作成。 - gBusErr.reset(new BusErrDevice()); - - // まず全域をバスエラーで初期化。 + // バスエラーデバイスをここで作成して全域をバスエラーで初期化。 // この後継承先で必要に応じて上書きする。 + NEWDV(BusErr, new BusErrDevice()); for (int i = 0; i < countof(::devtable); i++) { - ::devtable[i] = gBusErr.get(); + ::devtable[i] = gBusErr; } } @@ -37,33 +45,56 @@ VM::VM() VM::~VM() { Dispose(); + gVM = NULL; } // 終了 void VM::Dispose() { - if ((bool)gScheduler) { - // スケジューラを停止。 - // スケジューラ(VMスレッド)からのアクセスさえなくなれば - // 後の有象無象はグローバルデストラクタにお任せでもいいか。 - // だめだったらもっと頑張る。 - gScheduler->Terminate(); - gScheduler.reset(); + // まずスレッドを止める。 + // デバッガスレッドがスケジューラスレッドにアクセスするのでデバッガが先。 + if ((bool)pDebugger) { + gDebugger->TerminateThread(); + } + if ((bool)pScheduler) { + gScheduler->TerminateThread(); + } + + // 残りのスレッドを停止 + for (auto obj : gMainApp.GetObjects()) { + auto th = dynamic_cast(obj); + if (th) { + th->TerminateThread(); + } + } + + // 作ったときと逆順で解放する + if ((bool)pDebugger) { + pDebugger.reset(); } + + if ((bool)pScheduler) { + pScheduler.reset(); + } + + // ほかのオブジェクトの解放はグローバルデストラクタにおまかせ。 + // だめだったらまた考える。 } // コンストラクタ後の初期化 bool VM::Create() { - // d->Create() は gDevices に要素を追加する場合があるため、ここで + // d->Create() は Object を追加する場合があるため、ここで // ranged for は使えない。また追加されたデバイスの Create() も(念のため) // 実行したいため、ループ終了条件で毎回 size() を取り出して比較する。 - for (int i = 0; i < gDevices.size(); i++) { - Device *d = gDevices[i]; - if (!d->Create()) { - return false; + for (int i = 0; i < gMainApp.GetObjects().size(); i++) { + auto dev = dynamic_cast(gMainApp.GetObjects()[i]); + if (dev) { + if (!dev->Create()) { + return false; + } } } @@ -74,9 +105,28 @@ VM::Create() bool VM::Init() { - for (const auto& d : gDevices) { - if (!d->Init()) { - return false; + for (auto obj : gMainApp.GetObjects()) { + auto dev = dynamic_cast(obj); + if (dev) { + if (!dev->Init()) { + return false; + } + } + } + + return true; +} + +// スレッド開始 +bool +VM::StartThread() +{ + for (auto obj : gMainApp.GetObjects()) { + auto th = dynamic_cast(obj); + if (th) { + if (!th->StartThread()) { + return false; + } } } @@ -87,9 +137,12 @@ VM::Init() bool VM::Apply() { - for (const auto& d : gDevices) { - if (!d->Apply()) { - return false; + for (auto obj : gMainApp.GetObjects()) { + auto dev = dynamic_cast(obj); + if (dev) { + if (!dev->Apply()) { + return false; + } } } @@ -108,6 +161,12 @@ VM::SwitchBootPage(Device *parent, bool parent->putlogf(1, lstr("SwitchBootPage RAM (Normal)")); } - // スケジューラに指示 - gScheduler->RequestBootPageMode(isrom); + // 同期モード指示 + gSync->RequestBootPageMode(isrom); +} + +// MPU の RESET 命令によるリセット +void +VM::ResetByMPU() +{ }