--- nono/vm/mpu64180.cpp 2026/04/29 17:05:25 1.1.1.3 +++ nono/vm/mpu64180.cpp 2026/04/29 17:05:50 1.1.1.7 @@ -9,10 +9,14 @@ // #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" #include "xpbus.h" // コンストラクタ @@ -23,30 +27,20 @@ MPU64180Device::MPU64180Device() AddAlias("XP"); AddAlias("HD647180"); - // 6.144MHz = 162.7604… [nsec] - clock_nsec = 163; - - // 命令実行イベント。func, time は都度設定する。 - exec_event.Regist("XP(HD647180) Execute"); - - // タイマーイベント。time は都度設定する。 - timer_event.func = ToEventCallback(&MPU64180Device::TimerCallback); - timer_event.Regist("XP(HD647180) Timer"); - // レジスタモニター - 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->func = ToMonitorCallback(&MPU64180Device::MonitorUpdateReg); + 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->func = ToMonitorCallback(&MPU64180Device::MonitorUpdateIO); + 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->func = ToMonitorCallback(&MPU64180Device::MonitorUpdateIntr); + intr_monitor->SetSize(64, 18); } // デストラクタ @@ -65,11 +59,11 @@ MPU64180Device::putlogn(const char *fmt, int len; vt = scheduler->GetVirtTime(); - len = snprintf(buf, sizeof(buf), "%4d.%03d'%03d'%03d %04x %s ", - (int)(vt / 1000 / 1000 / 1000), - (int)((vt / 1000 / 1000) % 1000), - (int)((vt / 1000) % 1000), - (int)(vt % 1000), + 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), GetPPC(), GetName().c_str()); @@ -80,6 +74,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() @@ -88,13 +96,46 @@ MPU64180Device::Init() return false; } - debugger = GetDebugger(); + // 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_nsec = 1000 * 1000 * 10 / clock_khz; + clock_nsec = (clock_nsec + 5) / 10; + if (clock_nsec < 1) { + xp_clock_item.Err("Clock speed too high"); + return false; + } + pio0 = GetPIO0Device(); xpbus = GetXPbusDevice(); + ssg = gMainApp.FindObject(OBJ_SSG); + scheduler->ConnectMessage(MessageID::MPU_TRACE_XP, this, ToMessageCallback(&MPU64180Device::TraceMessage)); + // 命令実行イベント。func, time は都度設定する。 + // 登録は親クラスで行ってある。 + exec_event->SetName("XP(HD647180) Execute"); + + // タイマーイベント。time は都度設定する。 + auto evman = GetEventManager(); + timer_event = evman->Regist(this, + ToEventCallback(&MPU64180Device::TimerCallback), + "XP(HD647180) Timer"); + return true; } @@ -156,7 +197,7 @@ MPU64180Device::Reset() opmode = OpMode::Reset; // 命令実行サイクルを停止 - exec_event.SetName("XP(HD647180) Reset"); + exec_event->SetName("XP(HD647180) Reset"); scheduler->StopEvent(exec_event); // 汎用レジスタの値は不定。目印として $cc で埋めておく。 @@ -214,12 +255,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_nsec; scheduler->RestartEvent(exec_event); } @@ -230,8 +271,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); @@ -243,21 +284,21 @@ MPU64180Device::EnterWakeup() { // 復帰処理のため一旦 Wakeup へ。 SetExec(ToEventCallback(&MPU64180Device::ExecWakeup)); - exec_event.time = 3 * clock_nsec; + exec_event->time = 3 * clock_nsec; 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 なら、次の命令から再開。 @@ -283,7 +324,7 @@ MPU64180Device::TraceMessage(MessageID m // トレース実行 void -MPU64180Device::ExecTrace(Event& ev) +MPU64180Device::ExecTrace(Event *ev) { debugger->ExecXP(); (this->*exec_func)(ev); @@ -295,8 +336,8 @@ MPU64180Device::SetExec(EventCallback_t { exec_func = new_exec; - if (exec_event.func != ToEventCallback(&MPU64180Device::ExecTrace)) { - exec_event.func = exec_func; + if (exec_event->func != ToEventCallback(&MPU64180Device::ExecTrace)) { + exec_event->func = exec_func; } } @@ -311,7 +352,7 @@ MPU64180Device::SetTrace(bool enable) } else { func = exec_func; } - exec_event.func = func; + exec_event->func = func; } // IX/IY 分を考慮したサイクル数 @@ -325,10 +366,34 @@ MPU64180Device::CYCLE_IX(int cycle_hl, i } } +// メモリ空間からの読み込み。 uint32 -MPU64180Device::Fetch8() +MPU64180Device::Read1(uint32 laddr) { - uint8 data = Read8(reg.pc++); + uint32 paddr = Translate(laddr); + // XXX 内蔵 RAM はノーウェイト + CYCLE(memwait); + + uint32 data = xpbus->Read1(paddr); + return data; +} + +// メモリ空間への書き出し。 +uint32 +MPU64180Device::Write1(uint32 laddr, uint32 data) +{ + uint32 paddr = Translate(laddr); + // XXX 内蔵 RAM はノーウェイト + CYCLE(memwait); + + uint32 r = xpbus->Write1(paddr, data); + return r; +} + +uint32 +MPU64180Device::Fetch1() +{ + uint8 data = Read1(reg.pc++); ops.push_back(data); if (__predict_false(reg.pc > 0xffff)) { reg.pc = 0; @@ -337,36 +402,47 @@ MPU64180Device::Fetch8() } uint32 -MPU64180Device::Read8(uint32 laddr) +MPU64180Device::Fetch2() { - uint32 paddr = Translate(laddr); - // XXX 内蔵 RAM はノーウェイト - CYCLE(memwait); - return xpbus->Read8(paddr); + uint32 data; + + data = Fetch1(); + data |= Fetch1() << 8; + + return data; } uint32 -MPU64180Device::Write8(uint32 laddr, uint32 data) +MPU64180Device::Read2(uint32 addr) { - uint32 paddr = Translate(laddr); - // XXX 内蔵 RAM はノーウェイト - CYCLE(memwait); - return xpbus->Write8(paddr, data); + uint32 data; + + data = Read1(addr); + data |= Read1(addr + 1) << 8; + + return data; +} + +void +MPU64180Device::Write2(uint32 addr, uint32 data) +{ + Write1(addr, data & 0xff); + Write1(addr + 1, data >> 8); } uint32 -MPU64180Device::Peek8(uint32 laddr) const +MPU64180Device::Peek1(uint32 laddr) const { uint32 addr = TranslatePeek(laddr); - return xpbus->Peek8(addr); + return xpbus->Peek1(addr); } uint32 -MPU64180Device::Peek16(uint32 laddr) const +MPU64180Device::Peek2(uint32 laddr) const { uint32 data; - data = Peek8(laddr); - data |= Peek8(laddr + 1) << 8; + data = Peek1(laddr); + data |= Peek1(laddr + 1) << 8; return data; } @@ -382,7 +458,7 @@ MPU64180Device::Translate(uint32 laddr) } // アドレス変換 (デバッガ用) -busaddr +uint32 MPU64180Device::TranslatePeek(uint32 laddr) const { uint32 paddr; @@ -453,7 +529,7 @@ MPU64180Device::MonitorUpdateReg(Monitor screen.Puts(0, 5, "Operation Mode:"); screen.Puts(16, 5, (opmode == OpMode::Reset) ? TA::On : TA::Normal, - opmode_names[(int)opmode]); + opmode_names[(uint)opmode]); } /*static*/ const char * const @@ -486,8 +562,8 @@ MPU64180Device::MonitorUpdateIO(Monitor screen.Puts(0, y++, ""); val = PeekDCNTL(); screen.Print(0, y, "32H DCNTL= $%02x:", val); - screen.Print(16, y, "MemWait=%d", memwait); - screen.Print(26, y, "IOWait=%d", iowait); + screen.Print(16, y, "MemWait=%u", memwait); + screen.Print(26, y, "IOWait=%u", iowait); y++; screen.Puts(0, y++, ""); @@ -512,7 +588,7 @@ MPU64180Device::MonitorUpdateIO(Monitor screen.Puts(16 + 5 * i, y, TA::OnOff(val & (1U << (7 - i))), rcr_str[i]); } - screen.Print(46, y, "RefCyc=%d", (1 << (val & 3)) * 10); + screen.Print(46, y, "RefCyc=%u", (1U << (val & 3)) * 10); y++; y++; @@ -526,12 +602,12 @@ MPU64180Device::MonitorUpdateIO(Monitor screen.Puts(16 + 5 * i, y, TA::OnOff(val & (1U << (7 - i))), tcr_str[i]); } - screen.Print(16 + 5 * 4, y, "TOC=$%d", timer_toc); + screen.Print(16 + 5 * 4, y, "TOC=$%x", timer_toc); 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%d: Count=$%04x Reload=$%04x(%6u.%03u usec)", + screen.Print(4, y++, "Timer%u: Count=$%04x Reload=$%04x(%6u.%03u usec)", ch, t.count, t.reload, (uint)(reload_nsec / 1000), (uint)(reload_nsec % 1000)); @@ -599,7 +675,7 @@ MPU64180Device::MonitorUpdateIntr(Monito uint32 intvec = (reg_i << 8) + intvec_low; for (int i = 3; i < countof(data); i++) { data[i].vecaddr = intvec + table[i].offset; - data[i].handler = Peek16(data[i].vecaddr); + data[i].handler = Peek2(data[i].vecaddr); } screen.Clear(); @@ -609,7 +685,7 @@ MPU64180Device::MonitorUpdateIntr(Monito screen.Putc(11, 0, '('); screen.Puts(12, 0, TA::OnOff(GetIEF2()), "IEF2"); screen.Putc(16, 0, ')'); - screen.Print(26, 0, "INT0 Mode: %d", int0mode); + screen.Print(26, 0, "INT0 Mode: %u", int0mode); // 0 1 2 3 4 5 6 // 0123456789012345678901234567890123456789012345678901234567890123 @@ -642,7 +718,7 @@ MPU64180Device::MonitorUpdateIntr(Monito // Mode0 はデータバスから命令自体を読み込む方式。 // Mode1 はデータバスからベクタの下位アドレスを読み込む方式。 // どちらもサポートしていない。 - screen.Print(x, y + 2, "(IM%d)", int0mode); + screen.Print(x, y + 2, "(IM%u)", int0mode); } for (int i = 3; i < 15; i++) { screen.Print(x, y + i, "%04XH(%04XH)", @@ -652,7 +728,7 @@ MPU64180Device::MonitorUpdateIntr(Monito // カウンタ x = 38; for (int i = 0; i < 15; i++) { - screen.Print(0, y + i, "%2d", i); + screen.Print(0, y + i, "%2u", i); screen.Print(x, y + i, "%26s", format_number(int_counter[i]).c_str()); } }