--- nono/vm/mpu88xx0.cpp 2026/04/29 17:05:06 1.1.1.10 +++ nono/vm/mpu88xx0.cpp 2026/04/29 17:05:14 1.1.1.12 @@ -4,17 +4,23 @@ // Licensed under nono-license.txt // -// MPU (m88xx0) +// +// MPU (M88xx0) +// #include "mpu88xx0.h" #include "config.h" -#include "sysctlr.h" +#include "debugger.h" +#include "debugger_private.h" +#include "m88100disasm.h" +#include "scheduler.h" +#include "sync.h" // コンストラクタ MPU88xx0Device::MPU88xx0Device() : inherited("MPU(88xx0)") { - cpu.reset(new m88kcpu()); + cpu.reset(new m88kcpu(this)); // LUNA88K では CMMU の ID は次のように割り振ってあるようだ。 // OpenBSD の sys/arch/luna68k/include/board.h より。 @@ -33,7 +39,7 @@ MPU88xx0Device::MPU88xx0Device() cpu->cmmu[1].SetID(6); // レジスタモニター - monitor.func = (MonitorCallback_t)&MPU88xx0Device::MonitorUpdate; + monitor.func = ToMonitorCallback(&MPU88xx0Device::MonitorUpdate); monitor.SetSize(79, 28); monitor.Regist(ID_MONITOR_MPUREG); } @@ -50,26 +56,118 @@ MPU88xx0Device::Init() if (inherited::Init() == false) { return false; } - // MPU クロックは親 Init() で読み込んで、ここで cpu にセットする - cpu->SetClockSpeed(clock_khz); - const ConfigItem& item = gConfig->Find("mpu-pseudo-stop"); - cpu->pseudo_stop_enable = (bool)item.AsInt(); + const ConfigItem& item_stop = gConfig->Find("mpu-pseudo-stop"); + cpu->pseudo_stop_enable = (bool)item_stop.AsInt(); + + const ConfigItem& item_altname = gConfig->Find(".m88k-altname"); + m88100disasm::use_altname = item_altname.AsInt(); return true; } -bool -MPU88xx0Device::PowerOn() +// リセット +void +MPU88xx0Device::ResetHard(bool poweron) { - cpu->PowerOn(); - return true; + if (poweron) { + cpu->PowerOn(); + } + resetting = true; + + // リセット例外を 8+256 クロック後に起こす。 + // 8+256 は、電源オン時に最低これだけアサートしなければならないという値 + // のはずで、実際これだけかかるとかいう値ではない。が、こちら側の都合で + // この後実行される RAM の ResetHard() がブートページを用意した後で + // cpu->Reset() で xip をフェッチするという順序にしないといけないため、 + // リセット例外が起動するまでに時間がかかるというところを都合よく真似て + // おく。 + + exec_event.func = ToEventCallback(&MPU88xx0Device::ResetCallback); + exec_event.time = (8 + 256) * clock_nsec; + exec_event.SetName("MPU Reset"); + gScheduler->RestartEvent(exec_event); +} + +// リセット例外コールバック。 +// MPU リセットから規定時間後に呼ばれる。 +void +MPU88xx0Device::ResetCallback(Event& ev) +{ + resetting = false; + + // リセット例外を実行 + int cycle = cpu->Reset(); + + // コールバックを ResetCallback から Exec* に差し替える前のここで + // トレース状態を初期化する。 + SetTrace(gDebugger->IsTrace()); + + // 以降は通常走行 + exec_event.func = exec_normal; + exec_event.time = cycle * clock_nsec; + exec_event.SetName("MPU Execute"); + gScheduler->StartEvent(exec_event); +} + +// 1命令実行のコールバック +void +MPU88xx0Device::ExecNormal(Event& ev) +{ + int cycle = cpu->Exec(); + + ev.time = cycle * clock_nsec; + gScheduler->StartEvent(ev); } +// STOP 状態中のコールバック void -MPU88xx0Device::ResetHard() +MPU88xx0Device::ExecStop(Event& ev) { - cpu->RequestReset(); + int cycle = cpu->ExecPseudoStop(); + + ev.time = cycle * clock_nsec; + gScheduler->StartEvent(ev); +} + +// トレース実行のコールバック +void +MPU88xx0Device::ExecTrace(Event& ev) +{ + gDebugger->Exec(); + ExecNormal(ev); +} + +// トレース状態を設定する +void +MPU88xx0Device::SetTrace(bool enable) +{ + if (enable) { + exec_normal = ToEventCallback(&MPU88xx0Device::ExecTrace); + exec_stop = ToEventCallback(&MPU88xx0Device::ExecTrace); + } else { + exec_normal = ToEventCallback(&MPU88xx0Device::ExecNormal); + exec_stop = ToEventCallback(&MPU88xx0Device::ExecStop); + } + exec_event.func = exec_normal; +} + +// コアからの動作変更通知 +void +MPU88xx0Device::NotifyCPUMode(uint32 new_mode) +{ + // new_mode (m88kcpu::CPU_STATE_*) と + // RequestCPUMode() の引数 Sync::SCHED_CPU_* は + // 実は同じ値なのでそのまま渡してよいことにする。 + static_assert(m88kcpu::CPU_STATE_NORMAL == Sync::SCHED_CPU_NORMAL, ""); + static_assert(m88kcpu::CPU_STATE_STOP == Sync::SCHED_CPU_STOP, ""); + + gSync->RequestCPUMode(new_mode); + if (new_mode == Sync::SCHED_CPU_NORMAL) { + exec_event.func = exec_normal; + } else { + exec_event.func = exec_stop; + } } // アクセス中の論理アドレスを取得