--- nono/vm/mpu.cpp 2026/04/29 17:04:42 1.1.1.4 +++ nono/vm/mpu.cpp 2026/04/29 17:05:54 1.1.1.18 @@ -4,23 +4,40 @@ // Licensed under nono-license.txt // -// MPU 共通部 +// +// MPU (共通部分) +// + +// Device +// | +-----------+ +// +--| MPUDevice | (全 MPU の共通部) +// +-----------+ +// | +// | +---------------+ +// +--| MainMPUDevice | (680x0/88xx0 の共通部) +// | +---------------+ +// | | +// | +-- MPU680x0Device +// | +-- MPU88xx0Device +// | +// +-- MPU64180Device #include "mpu.h" +#include "config.h" +#include "debugger.h" +#include "event.h" +#include "mainbus.h" +#include "scheduler.h" +#include "syncer.h" -std::unique_ptr gMPU; +// +// 全 MPU 共通 +// // コンストラクタ -MPUDevice::MPUDevice() +MPUDevice::MPUDevice(uint objid_) + : inherited(objid_) { - logname = "mpu"; - devname = "MPU"; - - // リセット例外を起こすイベント - // ハンドラは MPU ごとに異なるので継承クラス側で用意している - reset_event.dev = this; - reset_event.time = 0; - reset_event.SetName("MPU Reset"); } // デストラクタ @@ -28,10 +45,112 @@ MPUDevice::~MPUDevice() { } -// リセット +// 初期化 +bool +MPUDevice::Init() +{ + debugger = GetDebugger(); + + auto evman = GetEventManager(); + exec_event = evman->Regist(this, NULL, "MPU Execute"); + + return true; +} + +void +MPUDevice::PowerOff() +{ + scheduler->StopEvent(exec_event); +} + + +// +// メイン MPU (680x0/88xx0) 共通部 +// + +// コンストラクタ +MainMPUDevice::MainMPUDevice() + : inherited(OBJ_MPU) +{ +} + +// デストラクタ +MainMPUDevice::~MainMPUDevice() +{ +} + +// 初期化 +bool +MainMPUDevice::Init() +{ + if (inherited::Init() == false) { + return false; + } + + mainbus = GetMainbusDevice(); + syncer = GetSyncer(); + + // MPU クロック。 + // 設定の "mpu-clock" は MHz 単位だが、変数 clock_khz は kHz 単位。 + int val; + const ConfigItem& item = gConfig->Find("mpu-clock"); + if (item.TryFixedDecimal(&val, 3) == false) { + item.Err(); + return false; + } + clock_khz = (uint)val; + // 1MHz 未満はエラー。実際 10MHz 未満でもいい気がするけど + if (clock_khz < 1000) { + item.Err(); + return false; + } + clock_nsec = 1000 * 1000 / clock_khz; + if (clock_nsec < 1) { + item.Err("Clock speed too high"); + return false; + } + + scheduler->ConnectMessage(MessageID::MPU_TRACE_MAIN, this, + ToMessageCallback(&MainMPUDevice::TraceMessage)); + + return true; +} + +// MPU トレース状態設定要求メッセージ void -MPUDevice::ResetHard() +MainMPUDevice::TraceMessage(MessageID msgid, uint32 arg) { - // 0 サイクル後にリセット例外を起こす - reset_event.Start(); + // リセット中は SetTrace しない + if (resetting) { + return; + } + + // デバッガから MPU のトレース状態を設定してくれと言われた + SetTrace((bool)arg); } + +void +MainMPUDevice::ChangeState(uint32 new_state) +{ + // new_mode (CPU_STATE_*) と + // NotifyCPUMode() の引数 Syncer::SYNCMODE_CPU_* は + // 実は同じ値なのでそのまま渡してよいことにする。 + static_assert(CPU_STATE_NORMAL == Syncer::SYNCMODE_CPU_NORMAL, ""); + static_assert(CPU_STATE_STOP == Syncer::SYNCMODE_CPU_STOP, ""); + static_assert(CPU_STATE_HALT == Syncer::SYNCMODE_CPU_HALT, ""); + + if (cpu_state != new_state) { + cpu_state = new_state; + // スケジューラに通知 + syncer->NotifyCPUMode(cpu_state); + } +} + +// Round Mode (モニタ表示用) +/*static*/ const char * const +MainMPUDevice::rmstr[4] = { + "Near", + "Zero", + "Minus", + "Plus", +};