--- nono/vm/mpu88xx0.cpp 2026/04/29 17:05:25 1.1.1.14 +++ nono/vm/mpu88xx0.cpp 2026/04/29 17:06:00 1.1.1.20 @@ -11,9 +11,9 @@ #include "mpu88xx0.h" #include "config.h" #include "debugger.h" +#include "event.h" #include "m88100disasm.h" #include "scheduler.h" -#include "syncer.h" // コンストラクタ MPU88xx0Device::MPU88xx0Device() @@ -37,10 +37,25 @@ MPU88xx0Device::MPU88xx0Device() cmmu[0].reset(new m88200(this, 7)); cmmu[1].reset(new m88200(this, 6)); + // 設定の初期値。 + + // MPU のデフォルトは xxx.usr バグ修正済みのバージョンに設定する。 + // 所有している実機にあわせ 0xb。OpenBSD の + // sys/arch/m88k/m88k/m88100_machdep.c::m88100_apply_patches() 参照。 + gConfig->SetDefault("m88100-version", 0xb); + + // CMMU のデフォルトは xmem の writeback バグが修正されているバージョンに + // 設定する。所有している実機にあわせ 0x9。 + // OpenBSD の sys/arch/m88k/m88k/m8820x_machdep.c::m8820x_apr_cmode() 参照。 + gConfig->SetDefault("m88200-version", 0x9); + + // 例外カウンタ + excep_counter.resize(512); + // レジスタモニター - monitor.func = ToMonitorCallback(&MPU88xx0Device::MonitorUpdate); - monitor.SetSize(79, 28); - monitor.Regist(ID_MONITOR_MPUREG); + monitor = gMonitorManager->Regist(ID_MONITOR_MPUREG, this); + monitor->SetCallback(&MPU88xx0Device::MonitorScreen); + monitor->SetSize(79, 25); } // デストラクタ @@ -56,13 +71,20 @@ MPU88xx0Device::Init() return false; } - debugger = GetDebugger(); + pseudo_stop_enable = gConfig->Find("mpu-pseudo-stop").AsBool(); - const ConfigItem& item_stop = gConfig->Find("mpu-pseudo-stop"); - pseudo_stop_enable = (bool)item_stop.AsInt(); + m88100disasm::use_altname = gConfig->Find(".m88k-altname").AsBool(); - const ConfigItem& item_altname = gConfig->Find(".m88k-altname"); - m88100disasm::use_altname = item_altname.AsInt(); + // MPU のバージョン。 + const ConfigItem& item_88100ver = gConfig->Find("m88100-version"); + uint ver88100 = item_88100ver.AsInt(); + reg.pid = (ver88100 << 1) | M88100::PID_MASTER; + + // CMMU のバージョン。 + const ConfigItem& item_88200ver = gConfig->Find("m88200-version"); + uint ver88200 = item_88200ver.AsInt(); + cmmu[0]->SetVersion(ver88200); + cmmu[1]->SetVersion(ver88200); return true; } @@ -111,7 +133,9 @@ MPU88xx0Device::ResetHard(bool poweron) // なるので、これだけここでも初期化しておく。 reg.xip = 0; } + resetting = true; + Exception(EXCPRI_RESET); // リセット例外を 8+256 クロック後に起こす。 // 8+256 は、電源オン時に最低これだけアサートしなければならないという値 @@ -121,31 +145,29 @@ MPU88xx0Device::ResetHard(bool poweron) // リセット例外が起動するまでに時間がかかるというところを都合よく真似て // おく。 - exec_event.func = ToEventCallback(&MPU88xx0Device::ResetCallback); - exec_event.time = (8 + 256) * clock_nsec; - exec_event.SetName(GetName() + " Reset"); + exec_event->SetCallback(&MPU88xx0Device::ResetCallback); + exec_event->time = (8 + 256) * clock_tsec; + exec_event->SetName(GetName() + " Reset"); scheduler->RestartEvent(exec_event); } // リセット例外コールバック。 // MPU リセットから規定時間後に呼ばれる。 void -MPU88xx0Device::ResetCallback(Event& ev) +MPU88xx0Device::ResetCallback(Event *ev) { - resetting = false; - // リセット例外を実行 uint64 cycle_start = used_cycle; // 例外履歴に記録 (例外発生はブランチ履歴にも記録) // リセット例外も発生時の XIP を記録する。(LUNA-88K の PROM 1.20) + last_vector = 0; exhist.AddEntry(reg.xip | 1, 0, 0xfc000000 | 0); brhist.AddEntry(reg.xip | 1, 0, 0xfc000000 | 0); - // デバッガに通知 (例外ブレーク用) - debugger->NotifyExceptionMain(0); - // 内部の割り込み状態をクリア - intr_pending = 0; + // 内部の例外状態をクリア + resetting = false; + excep_pending = 0; ChangeState(CPU_STATE_NORMAL); // 実際どこかは分からんけど PSR 設定の前にリセットしておきたい @@ -192,15 +214,15 @@ MPU88xx0Device::ResetCallback(Event& ev) // 以降は通常走行 int cycle = used_cycle - cycle_start; - exec_event.func = exec_normal; - exec_event.time = cycle * clock_nsec; - exec_event.SetName(GetName() + " Execute"); + exec_event->SetCallback(exec_normal); + exec_event->time = cycle * clock_tsec; + exec_event->SetName(GetName() + " Execute"); scheduler->StartEvent(exec_event); } // トレース実行のコールバック void -MPU88xx0Device::ExecTrace(Event& ev) +MPU88xx0Device::ExecTrace(Event *ev) { debugger->ExecMain(); ExecNormal(ev); @@ -215,54 +237,48 @@ MPU88xx0Device::SetTrace(bool enable) } else { exec_normal = ToEventCallback(&MPU88xx0Device::ExecNormal); } - exec_event.func = exec_normal; + exec_event->SetCallback(exec_normal); } +// Interrupt void -MPU88xx0Device::ChangeState(uint32 new_state) +MPU88xx0Device::Interrupt(int level) { - // new_state (CPU_STATE_*) と - // RequestCPUMode() の引数 Syncer::SCHED_CPU_* は - // 実は同じ値なのでそのまま渡してよいことにする。 - static_assert(CPU_STATE_NORMAL == Syncer::SCHED_CPU_NORMAL, ""); - static_assert(CPU_STATE_STOP == Syncer::SCHED_CPU_STOP, ""); - - if (cpu_state != new_state) { - cpu_state = new_state; - // スケジューラに通知 - syncer->RequestCPUMode(new_state); - } -} + // level は 0 か 1。 + intr_asserted = level; -// アクセス中の論理アドレスを取得 -uint32 -MPU88xx0Device::GetLaddr() const -{ - m88200 *m = m88200::GetBusMaster(); - assert(m); - return m->GetLaddr(); -} + if (intr_asserted && IsIntrEnable()) { + OuterException(EXCPRI_INTERRUPT); -// アクセス中の物理アドレスを取得 -uint32 -MPU88xx0Device::GetPaddr() const -{ - m88200 *m = m88200::GetBusMaster(); - assert(m); - return m->GetPaddr(); + if (cpu_state == CPU_STATE_STOP) { + // 割り込みを受け付けたら STOP 解除。 + ChangeState(CPU_STATE_NORMAL); + } + } else { + excep_pending &= ~EXCPRI_INTERRUPT; + // INTERRUPT を下げたことで全員いなくなれば OUTER を下げる。 + if ((excep_pending & EXCPRI_OUTER_MASK) == 0) { + excep_pending &= ~EXCPRI_OUTER; + } + } } -// Interrupt void -MPU88xx0Device::Interrupt(int level) +MPU88xx0Device::SetPSR() { - // level は 0 か 1。 - intr_pending = level; - - if (intr_pending && IsIntrEnable() && (cpu_state == CPU_STATE_STOP)) { - // 割り込みを受け付けたら STOP 解除。 - ChangeState(CPU_STATE_NORMAL); + if (intr_asserted && IsIntrEnable()) { + OuterException(EXCPRI_INTERRUPT); + } else { + excep_pending &= ~EXCPRI_INTERRUPT; + // INTERRUPT を下げたことで全員いなくなれば OUTER を下げる。 + if ((excep_pending & EXCPRI_OUTER_MASK) == 0) { + excep_pending &= ~EXCPRI_OUTER; + } } + + // CMMU に S/U 信号を出す + cmmu[0]->SetSuper(IsSuper()); + cmmu[1]->SetSuper(IsSuper()); } // DOS call エミュレーションのコールバックを指定 @@ -278,7 +294,7 @@ MPU88xx0Device::SetFLineCallback(bool (* // モニター更新 void -MPU88xx0Device::MonitorUpdate(Monitor *, TextScreen& screen) +MPU88xx0Device::MonitorScreen(Monitor *, TextScreen& screen) { m88100reg tmp; int x; @@ -289,82 +305,77 @@ MPU88xx0Device::MonitorUpdate(Monitor *, // ローカルにコピー tmp = reg; - // - for (int i = 0; i < countof(reg.r); i++) { - screen.Print((i / 8) * 14, i % 8, "r%-2d:%08x", i, tmp.r[i]); + // 汎用レジスタ + for (uint i = 0; i < countof(reg.r); i++) { + screen.Print((i / 8) * 14, i % 8, "r%-2u:%08x", i, tmp.r[i]); } - // 制御レジスタ + // 制御レジスタ (上段右) + x = 57; + y = 0; + for (int i = 0; i < 4; i++) { + int rn = 17 + i; + screen.Print(x, y++, "sr%u(cr%u):%08x", i, rn, tmp.cr[rn]); + } + screen.Print(x, y++, "ssbr(cr3):%08x", tmp.ssbr); + for (int i = 0; i < 3; i++) { + screen.Print(x, y++, "%s(cr%u):%08x:%c%c", + m88100reg::sipname[i], 4 + i, + (tmp.cr[4 + i] & M88100::SIP_MASK), + (tmp.cr[4 + i] & M88100::SIP_V) ? 'V' : '-', + (tmp.cr[4 + i] & M88100::SIP_E) ? 'E' : '-'); + } + screen.Print(x, y++, "vbr (cr7):%08x", tmp.vbr); + + // 制御レジスタ(中段上; *IP) x = 0; y = 9; - screen.Print(x, y++, "pid (cr0):%08x(Arch=$%02x Ver=$%02x MC=%s)", + screen.Print(x, y++, "xip:%08x (op:%08x:%c)", + tmp.xip, (uint32)tmp.opX, OpIsBusErr(tmp.opX) ? 'B' : '-'); + screen.Print(x, y++, "nip:%08x (op:%08x:%c)", + tmp.nip, (uint32)tmp.opF, OpIsBusErr(tmp.opF) ? 'B' : '-'); + screen.Print(x, y++, "fip:%08x", tmp.fip); + + // 制御レジスタ 中段上; pid,*psr) + x = 30; + y = 9; + screen.Print(x, y++, "pid(cr0):%08x(Arch=$%02x Ver=$%02x MC=%s)", tmp.pid, (tmp.pid >> 8) & 0xff, (tmp.pid >> 1) & 0x7f, (tmp.pid & 1) ? "Master" : "Checker"); - screen.Print(x, y, "psr (cr1):%08x(", tmp.psr); + screen.Print(x, y, "psr(cr1):%08x(", tmp.psr); + x--; screen.Puts(x + 19, y, FA(tmp.psr, PSR_SUPER), "S"); - screen.Puts(x + 21, y, - ((tmp.psr & M88100::PSR_BO_LE) ? "BO=LE" : "BO=BE")); - screen.Puts(x + 27, y, FA(tmp.psr, PSR_SER), "SER"); - screen.Puts(x + 31, y, FA(tmp.psr, PSR_C), "Cy"); - screen.Puts(x + 34, y, FA(tmp.psr, PSR_SFD1), "SFD1"); - screen.Puts(x + 39, y, FA(tmp.psr, PSR_MXM), "MXM"); - screen.Puts(x + 43, y, FA(tmp.psr, PSR_IND), "IND"); - screen.Puts(x + 47, y, FA(tmp.psr, PSR_SFRZ), "SFRZ"); - screen.Puts(x + 51, y, ")"); + screen.Puts(x + 21, y, ((tmp.psr & M88100::PSR_BO_LE) ? "LE" : "BE")); + screen.Puts(x + 24, y, FA(tmp.psr, PSR_SER), "SER"); + screen.Puts(x + 28, y, FA(tmp.psr, PSR_C), "Cy"); + screen.Puts(x + 31, y, FA(tmp.psr, PSR_SFD1), "SFD1"); + screen.Puts(x + 36, y, FA(tmp.psr, PSR_MXM), "MXM"); + screen.Puts(x + 40, y, FA(tmp.psr, PSR_IND), "IND"); + screen.Puts(x + 44, y, FA(tmp.psr, PSR_SFRZ), "SFRZ"); + screen.Puts(x + 48, y, ")"); y++; screen.Print(x, y, "epsr(cr2):%08x(", tmp.epsr); screen.Puts(x + 19, y, FA(tmp.epsr, PSR_SUPER), "S"); - screen.Puts(x + 21, y, - ((tmp.epsr& M88100::PSR_BO_LE) ? "BO=LE" : "BO=BE")); - screen.Puts(x + 27, y, FA(tmp.epsr, PSR_SER), "SER"); - screen.Puts(x + 31, y, FA(tmp.epsr, PSR_C), "Cy"); - screen.Puts(x + 34, y, FA(tmp.epsr, PSR_SFD1), "SFD1"); - screen.Puts(x + 39, y, FA(tmp.epsr, PSR_MXM), "MXM"); - screen.Puts(x + 43, y, FA(tmp.epsr, PSR_IND), "IND"); - screen.Puts(x + 47, y, FA(tmp.epsr, PSR_SFRZ), "SFRZ"); - screen.Puts(x + 51, y, ")"); + screen.Puts(x + 21, y, ((tmp.epsr& M88100::PSR_BO_LE) ? "LE" : "BE")); + screen.Puts(x + 24, y, FA(tmp.epsr, PSR_SER), "SER"); + screen.Puts(x + 28, y, FA(tmp.epsr, PSR_C), "Cy"); + screen.Puts(x + 31, y, FA(tmp.epsr, PSR_SFD1), "SFD1"); + screen.Puts(x + 36, y, FA(tmp.epsr, PSR_MXM), "MXM"); + screen.Puts(x + 40, y, FA(tmp.epsr, PSR_IND), "IND"); + screen.Puts(x + 44, y, FA(tmp.epsr, PSR_SFRZ), "SFRZ"); + screen.Puts(x + 48, y, ")"); - // 制御レジスタ(左中; *IP) - x = 0; + // MMU レジスタ(中段下) y = 12; - screen.Print(x, y + 0, "xip:%08x opX:%08x(%c)", - tmp.xip, (uint32)tmp.opX, - OpIsBusErr(tmp.opX) ? 'B' : '-'); - screen.Print(x, y + 1, "nip:%08x opF:%08x(%c)", - tmp.nip, (uint32)tmp.opF, - OpIsBusErr(tmp.opF) ? 'B' : '-'); - screen.Print(x, y + 2, "fip:%08x", tmp.fip); + for (uint i = 0; i <= 2; i++) { + uint dt = 8 + i * 3; + uint dd = 9 + i * 3; + uint da = 10 + i * 3; - // 制御レジスタ (S*IP) - x = 32; - for (int i = 0; i < 3; i++) { - screen.Print(x, y + i, "%s(cr%d):%08x:%c%c", - m88100reg::sipname[i], 4 + i, - (tmp.cr[4 + i] & M88100::SIP_MASK), - (tmp.cr[4 + i] & M88100::SIP_V) ? 'V' : '-', - (tmp.cr[4 + i] & M88100::SIP_E) ? 'E' : '-'); - } - - // 制御レジスタ(右中) - x = 55; - y = 9; - for (int i = 0; i < 4; i++) { - int rn = 17 + i; - screen.Print(x, y++, "sr%d(cr%d):%08x", i, rn, tmp.cr[rn]); - } - screen.Print(x, y++, "ssbr(cr3):%08x", tmp.ssbr); - screen.Print(x, y++, "vbr (cr7):%08x", tmp.vbr); - - // MMU レジスタ(次段) - y = 15; - for (int i = 0; i <= 2; i++) { - int dt = 8 + i * 3; - int dd = 9 + i * 3; - int da = 10 + i * 3; - - screen.Print(0, y, "dmt%d(cr%-2d):%04x", + // DMT は "cr8 " があるので左揃え + screen.Print(0, y, "dmt%u(cr%-2u):%04x", i, dt, (tmp.cr[dt] & 0xffff)); screen.Puts(15, y, "(b,s,d,l,rx, s,en ,w,v)"); screen.Puts(16, y, (tmp.cr[dt] & M88100::DM_BO) ? "B" : "-"); @@ -372,7 +383,7 @@ MPU88xx0Device::MonitorUpdate(Monitor *, screen.Puts(20, y, (tmp.cr[dt] & M88100::DM_DOUB1) ? "D" : "-"); screen.Puts(22, y, (tmp.cr[dt] & M88100::DM_LOCK) ? "L" : "-"); // カンマが自然に見えるようにここだけカンマも含めて前詰めで出力 - screen.Print(25, y, "%d,", + screen.Print(25, y, "%u,", (tmp.cr[dt] & M88100::DM_DREG_MASK) >> 7); screen.Puts(28, y, (tmp.cr[dt] & M88100::DM_SIGNED) ? "S" : "-"); uint32 en = (tmp.cr[dt] & M88100::DM_EN_MASK) >> 2; @@ -380,8 +391,9 @@ MPU88xx0Device::MonitorUpdate(Monitor *, screen.Puts(35, y, (tmp.cr[dt] & M88100::DM_WRITE) ? "W" : "-"); screen.Puts(37, y, (tmp.cr[dt] & M88100::DM_VALID) ? "V" : "-"); - screen.Print(40, y, "dmd%d(cr%-2d):%08x", i, dd, tmp.cr[dd]); - screen.Print(60, y, "dma%d(cr%2d):%08x", i, da, tmp.cr[da]); + // DMD は "cr9 " があるので左揃え + screen.Print(40, y, "dmd%u(cr%-2u):%08x", i, dd, tmp.cr[dd]); + screen.Print(60, y, "dma%u(cr%2u):%08x", i, da, tmp.cr[da]); y++; } y++; @@ -400,23 +412,49 @@ MPU88xx0Device::MonitorUpdate(Monitor *, screen.Puts(x + 41, y, ")"); y++; + char tsiz[4] = { 's', 'd', '2', '3' }; screen.Print(0, y++, - "fppt(fcr5): %08x(OpCode=%%%c%c%c%c%c T1=%d T2=%d TD=%d Dest=r%d)", + "fppt(fcr5): %08x(OpCode=%%%c%c%c%c%c T1=%c T2=%c TD=%c Dest=r%u)", tmp.fppt, ((tmp.fppt >> 15) & 1) + '0', ((tmp.fppt >> 14) & 1) + '0', ((tmp.fppt >> 13) & 1) + '0', ((tmp.fppt >> 12) & 1) + '0', ((tmp.fppt >> 11) & 1) + '0', - ((tmp.fppt >> 9) & 3), - ((tmp.fppt >> 7) & 3), - ((tmp.fppt >> 5) & 3), + tsiz[(tmp.fppt >> 9) & 3], + tsiz[(tmp.fppt >> 7) & 3], + tsiz[(tmp.fppt >> 5) & 3], (tmp.fppt & M88100::FPPT_DEST)); - screen.Print(0, y++, "fphs1(fcr1)/fpls1(fcr2): %08x'%08x", - tmp.fphs1, tmp.fpls1); - screen.Print(0, y++, "fphs2(fcr3)/fpls2(fcr4): %08x'%08x", - tmp.fphs2, tmp.fpls2); + for (uint i = 0; i < 2; i++) { + uint32 hs; + uint32 ls; + bool isfloat; + if (i == 0) { + hs = tmp.fphs1; + ls = tmp.fpls1; + isfloat = (tmp.fppt & 0x600) == 0; + } else { + hs = tmp.fphs2; + ls = tmp.fpls2; + isfloat = (tmp.fppt & 0x180) == 0; + } + uint n = i * 2; + screen.Print(0, y, "fphs%u(fcr%u)/fpls%u(fcr%u): %08x'%08x =", + (i + 1), (n + 1), (i + 1), (n + 2), hs, ls); + int32 e = ((int32)(hs << 1)) >> 21; + screen.Print(45, y, "%c0.%05x'", + ((hs & 0x80000000) ? '-' : '+'), + (hs & 0x000f'ffff)); + if (isfloat) { + screen.Print(45 + 9, y, "%1x", (ls >> 28) & 0xf); + screen.Print(45 + 10, y, TA::Disable, "%07x", (ls & 0x0fff'ffff)); + screen.Print(45 + 18, y, "e%+d", e); + } else { + screen.Print(45 + 9, y, "%08x e%+d", ls, e); + } + y++; + } screen.Print(0, y, "fprh(fcr6) /fprl(fcr7): %08x'%08x(", tmp.fprh, tmp.fprl); @@ -426,7 +464,7 @@ MPU88xx0Device::MonitorUpdate(Monitor *, y++; x = 21; - screen.Print(0, y, "fpit(fcr8): %08x(OpCode=%%%c%c%c%c%c TD=%d", + screen.Print(0, y, "fpit(fcr8): %08x(OpCode=%%%c%c%c%c%c TD=%u", tmp.fpit, ((tmp.fpit >> 15) & 1) + '0', ((tmp.fpit >> 14) & 1) + '0', @@ -439,7 +477,7 @@ MPU88xx0Device::MonitorUpdate(Monitor *, screen.Puts(x + 29, y, FA(tmp.fpit, FPIT_EFUNF), "EUNF"); screen.Puts(x + 34, y, FA(tmp.fpit, FPIT_EFOVF), "EOVF"); screen.Puts(x + 39, y, FA(tmp.fpit, FPIT_EFINX), "EINX"); - screen.Print(x + 44, y, "Dest=r%d)", tmp.fpit & M88100::FPIT_DEST); + screen.Print(x + 44, y, "Dest=r%u)", tmp.fpit & M88100::FPIT_DEST); y++; uint32 sign = (tmp.fprh & M88100::FPRH_SIGN);