--- nono/vm/mpu64180.cpp 2026/04/29 17:05:29 1.1.1.4 +++ nono/vm/mpu64180.cpp 2026/04/29 17:06:00 1.1.1.8 @@ -9,8 +9,11 @@ // #include "mpu64180.h" +#include "config.h" #include "debugger.h" +#include "event.h" #include "hd647180.h" +#include "hd647180asci.h" #include "pio.h" #include "scheduler.h" #include "ssg.h" @@ -24,23 +27,20 @@ MPU64180Device::MPU64180Device() AddAlias("XP"); AddAlias("HD647180"); - // 6.144MHz = 162.7604… [nsec] - clock_nsec = 163; - // レジスタモニター - reg_monitor.func = ToMonitorCallback(&MPU64180Device::MonitorUpdateReg); - reg_monitor.SetSize(38, 6); - reg_monitor.Regist(ID_MONITOR_XPREG); + reg_monitor = gMonitorManager->Regist(ID_MONITOR_XPREG, this); + reg_monitor->SetCallback(&MPU64180Device::MonitorScreenReg); + reg_monitor->SetSize(38, 6); // I/O モニター - io_monitor.func = ToMonitorCallback(&MPU64180Device::MonitorUpdateIO); - io_monitor.SetSize(55, 20); - io_monitor.Regist(ID_MONITOR_XPIO); + io_monitor = gMonitorManager->Regist(ID_MONITOR_XPIO, this); + io_monitor->SetCallback(&MPU64180Device::MonitorScreenIO); + io_monitor->SetSize(55, 20); // 割り込みモニター - intr_monitor.func = ToMonitorCallback(&MPU64180Device::MonitorUpdateIntr); - intr_monitor.SetSize(64, 18); - intr_monitor.Regist(ID_MONITOR_XPINTR); + intr_monitor = gMonitorManager->Regist(ID_MONITOR_XPINTR, this); + intr_monitor->SetCallback(&MPU64180Device::MonitorScreenIntr); + intr_monitor->SetSize(64, 18); } // デストラクタ @@ -59,11 +59,8 @@ MPU64180Device::putlogn(const char *fmt, int len; vt = scheduler->GetVirtTime(); - len = snprintf(buf, sizeof(buf), "%4u.%03u'%03u'%03u %04x %s ", - (uint)(vt / 1000 / 1000 / 1000), - (uint)((vt / 1000 / 1000) % 1000), - (uint)((vt / 1000) % 1000), - (uint)(vt % 1000), + len = snprintf(buf, sizeof(buf), "%16s %04x %s ", + SecToStr(vt).c_str(), GetPPC(), GetName().c_str()); @@ -74,6 +71,20 @@ MPU64180Device::putlogn(const char *fmt, WriteLog(buf); } +bool +MPU64180Device::Create() +{ + try { + asci.reset(new HD647180ASCIDevice()); + } catch (...) { } + if ((bool)asci == false) { + warnx("Failed to initialize HD647180ASCIDevice at %s", __method__); + return false; + } + + return true; +} + // 初期化 bool MPU64180Device::Init() @@ -82,6 +93,28 @@ MPU64180Device::Init() return false; } + // MPU クロック。 + // "xp-clock" は MHz 単位だが、変数は kHz 単位。 + int clock_khz; + const ConfigItem& xp_clock_item = gConfig->Find("xp-clock"); + if (xp_clock_item.TryFixedDecimal(&clock_khz, 3) == false) { + xp_clock_item.Err(); + return false; + } + // 適当な下限値でエラーにする? + if (clock_khz < 100) { + xp_clock_item.Err(); + return false; + } + // 6.144MHz = 162.76… [nsec] であり、変数導入前は 163 をハードコード + // して使っていたので、それとの互換性のため四捨五入する。 + clock_tsec = 10_msec / clock_khz; + clock_tsec = (clock_tsec + 5) / 10; + if (clock_tsec < 1) { + xp_clock_item.Err("Clock speed too high"); + return false; + } + pio0 = GetPIO0Device(); xpbus = GetXPbusDevice(); @@ -92,12 +125,13 @@ MPU64180Device::Init() // 命令実行イベント。func, time は都度設定する。 // 登録は親クラスで行ってある。 - exec_event.SetName("XP(HD647180) Execute"); + exec_event->SetName("XP(HD647180) Execute"); // タイマーイベント。time は都度設定する。 - timer_event.func = ToEventCallback(&MPU64180Device::TimerCallback); - timer_event.SetName("XP(HD647180) Timer"); - scheduler->RegistEvent(timer_event); + auto evman = GetEventManager(); + timer_event = evman->Regist(this, + ToEventCallback(&MPU64180Device::TimerCallback), + "XP(HD647180) Timer"); return true; } @@ -160,7 +194,7 @@ MPU64180Device::Reset() opmode = OpMode::Reset; // 命令実行サイクルを停止 - exec_event.SetName("XP(HD647180) Reset"); + exec_event->SetName("XP(HD647180) Reset"); scheduler->StopEvent(exec_event); // 汎用レジスタの値は不定。目印として $cc で埋めておく。 @@ -218,12 +252,12 @@ MPU64180Device::EnterNormal() opmode = OpMode::Normal; SetExec(ToEventCallback(&MPU64180Device::ExecNormal)); - exec_event.SetName("XP(HD647180) Execute"); + exec_event->SetName("XP(HD647180) Execute"); SetTrace(debugger->IsTrace()); // 3 クロック後から通常サイクル開始? (HD647180.pdf, p23) - exec_event.time = 3 * clock_nsec; + exec_event->time = 3 * clock_tsec; scheduler->RestartEvent(exec_event); } @@ -234,8 +268,8 @@ MPU64180Device::EnterSleep() // ExecNormal() 内で StartEvent() をしないに分岐するのは無駄が多いので、 // ここでは一旦コールバックだけ差し替えて、イベントを停止する。 SetExec(ToEventCallback(&MPU64180Device::ExecSleep)); - exec_event.SetName("XP(HD647180) Sleep"); - exec_event.time = 0; + exec_event->SetName("XP(HD647180) Sleep"); + exec_event->time = 0; // 内蔵デバイスのイベントも停止する。 scheduler->StopEvent(timer_event); @@ -247,21 +281,21 @@ MPU64180Device::EnterWakeup() { // 復帰処理のため一旦 Wakeup へ。 SetExec(ToEventCallback(&MPU64180Device::ExecWakeup)); - exec_event.time = 3 * clock_nsec; + exec_event->time = 3 * clock_tsec; scheduler->StartEvent(exec_event); } // スリープに入る時のイベント void -MPU64180Device::ExecSleep(Event& ev) +MPU64180Device::ExecSleep(Event *ev) { // 実行イベントを停止する。(StartEvent() を呼ばない) } // スリープから復帰するイベント void -MPU64180Device::ExecWakeup(Event& ev) +MPU64180Device::ExecWakeup(Event *ev) { // EI なら、割り込み処理から再開。 // DI なら、次の命令から再開。 @@ -287,7 +321,7 @@ MPU64180Device::TraceMessage(MessageID m // トレース実行 void -MPU64180Device::ExecTrace(Event& ev) +MPU64180Device::ExecTrace(Event *ev) { debugger->ExecXP(); (this->*exec_func)(ev); @@ -299,8 +333,9 @@ MPU64180Device::SetExec(EventCallback_t { exec_func = new_exec; - if (exec_event.func != ToEventCallback(&MPU64180Device::ExecTrace)) { - exec_event.func = exec_func; + auto execTrace = ToEventCallback(&MPU64180Device::ExecTrace); + if (exec_event->GetCallback() != execTrace) { + exec_event->SetCallback(exec_func); } } @@ -308,14 +343,11 @@ MPU64180Device::SetExec(EventCallback_t void MPU64180Device::SetTrace(bool enable) { - EventCallback_t func; - if (enable) { - func = ToEventCallback(&MPU64180Device::ExecTrace); + exec_event->SetCallback(&MPU64180Device::ExecTrace); } else { - func = exec_func; + exec_event->SetCallback(exec_func); } - exec_event.func = func; } // IX/IY 分を考慮したサイクル数 @@ -450,7 +482,7 @@ MPU64180Device::SetSYSCALLCallback(void } void -MPU64180Device::MonitorUpdateReg(Monitor *, TextScreen& screen) +MPU64180Device::MonitorScreenReg(Monitor *, TextScreen& screen) { screen.Clear(); @@ -504,7 +536,7 @@ MPU64180Device::opmode_names[] = { }; void -MPU64180Device::MonitorUpdateIO(Monitor *, TextScreen& screen) +MPU64180Device::MonitorScreenIO(Monitor *, TextScreen& screen) { int y; uint32 val; @@ -551,7 +583,7 @@ MPU64180Device::MonitorUpdateIO(Monitor screen.Puts(16 + 5 * i, y, TA::OnOff(val & (1U << (7 - i))), rcr_str[i]); } - screen.Print(46, y, "RefCyc=%u", (1 << (val & 3)) * 10); + screen.Print(46, y, "RefCyc=%u", (1U << (val & 3)) * 10); y++; y++; @@ -569,11 +601,10 @@ MPU64180Device::MonitorUpdateIO(Monitor y++; for (int ch = 0; ch < timer.size(); ch++) { auto& t = timer[ch]; - uint64 reload_nsec = t.reload * clock_nsec * 20; - screen.Print(4, y++, "Timer%u: Count=$%04x Reload=$%04x(%6u.%03u usec)", + uint64 reload_tsec = t.reload * clock_tsec * 20; + screen.Print(4, y++, "Timer%u: Count=$%04x Reload=$%04x(%10.3f usec)", ch, t.count, t.reload, - (uint)(reload_nsec / 1000), - (uint)(reload_nsec % 1000)); + (double)reload_tsec / 1000); } screen.Print(0, y++, "18H FRC = $%02x", PeekFRC()); @@ -594,7 +625,7 @@ MPU64180Device::MonitorUpdateIO(Monitor } void -MPU64180Device::MonitorUpdateIntr(Monitor *, TextScreen& screen) +MPU64180Device::MonitorScreenIntr(Monitor *, TextScreen& screen) { static const struct { uint offset;