--- nono/vm/mpu680x0.cpp 2026/04/29 17:04:50 1.1.1.7 +++ nono/vm/mpu680x0.cpp 2026/04/29 17:05:03 1.1.1.11 @@ -8,34 +8,36 @@ #include "mpu680x0.h" #include "config.h" +#include "m68030bus.h" #include "m68030excep.h" #include "mainapp.h" +#include "uimessage.h" #include "vm.h" #include -std::unique_ptr gMPUATC; - // コンストラクタ -// -// reset_vector にはリセットベクタの番地を指定する。 -// 本来の MPU の動作は、リセット例外時にメモリの $0, $4 番地 (もっと言えば -// FC がプログラム空間の) から SP, PC を読み込むのだが、そのためにメモリ空間 -// を切り替える処理はリセット時にしか必要ないわりに結構手間である。そしてこの -// m68k 恒例のブートストラップ動作はソフトウェア的には一切観測する手段がない。 -// であれば、リセット例外時にこのアドレスから SP, PC の値を直接読み込んだと -// しても動作にはまったく違いは出ない。そしてバス・メモリ空間の実装も簡略化 -// できる。すごい楽。 -MPU680x0Device::MPU680x0Device(uint32 reset_vector) +MPU680x0Device::MPU680x0Device() + : inherited("MPU(68030)") { - monitor_size = nnSize(79, 16); - - cpu = m68030_init(reset_vector); + cpu = m68030_init(); // イベントコールバック設定 + event.SetName("MPU"); event.func = (DeviceCallback_t)&MPU680x0Device::Callback; - // モニタ用の別オブジェクト - gMPUATC.reset(new MPUATC(cpu)); + // レジスタモニター + reg_monitor.func = (MonitorCallback_t)&MPU680x0Device::MonitorUpdateReg; + reg_monitor.SetSize(79, 16); + reg_monitor.Regist(ID_MONITOR_MPUREG); + + // ATC モニター + atc_monitor.func = (MonitorCallback_t)&MPU680x0Device::MonitorUpdateATC; +#if !defined(ATC_SINGLE) + atc_monitor.SetSize(131, m68030ATCTable::LINES + 3); +#else + atc_monitor.SetSize(31, 24); +#endif + atc_monitor.Regist(ID_MONITOR_MPUATC); } // デストラクタ @@ -69,24 +71,34 @@ MPU680x0Device::Init() } } + cpu->halt_callback = &MPU680x0Device::HaltCallback; + cpu->halt_arg = NULL; + + return true; +} + +bool +MPU680x0Device::PowerOn() +{ + m68030_power_on(cpu); return true; } +void +MPU680x0Device::ResetHard() +{ + // リセット例外 + m68030_request_reset_exception(cpu); +} + // イベントコールバック // ev.code は -// 0x80000000: リセット例外 // 0x0 〜 0x7: 新しい割り込みレベルを通知 (0-7) void MPU680x0Device::Callback(Event& ev) { - if (__predict_false((int32)ev.code < 0)) { - // リセット例外 - m68030_request_reset_exception(cpu); - } else { - // コードが 0-7 なら新しい割り込みレベルの通知 - int level = ev.code; - m68030_interrupt(cpu, level); - } + int level = ev.code; + m68030_interrupt(cpu, level); } // MPU を vtime [nsec] 分実行する。 @@ -145,24 +157,87 @@ MPU680x0Device::SetFLineCallback(bool (* cpu->fline_arg = arg; } -// ダブルバスフォールトのコールバックを指定。 -void -MPU680x0Device::SetHaltCallback(void (*callback)(void *), void *arg) +// MPU ホールト時の MPU からのコールバック関数 +/*static*/ void +MPU680x0Device::HaltCallback(void *arg) { - cpu->halt_callback = callback; - cpu->halt_arg = arg; + UIMessage::Post(UIMessage::HALT); +} + +// MPU からのアクセスをエミュレート +uint64 +MPU680x0Device::Read8(uint32 addr) +{ + try { + return m68030_read_8(cpu, addr); + } catch (...) { + return (uint64)-1; + } +} + +uint64 +MPU680x0Device::Read16(uint32 addr) +{ + try { + return m68030_read_16(cpu, addr); + } catch (...) { + return (uint64)-1; + } +} + +uint64 +MPU680x0Device::Read32(uint32 addr) +{ + try { + return m68030_read_32(cpu, addr); + } catch (...) { + return (uint64)-1; + } +} + +uint64 +MPU680x0Device::Write8(uint32 addr, uint32 data) +{ + try { + m68030_write_8(cpu, addr, data); + return 0; + } catch (...) { + return (uint64)-1; + } +} + +uint64 +MPU680x0Device::Write16(uint32 addr, uint32 data) +{ + try { + m68030_write_16(cpu, addr, data); + return 0; + } catch (...) { + return (uint64)-1; + } +} + +uint64 +MPU680x0Device::Write32(uint32 addr, uint32 data) +{ + try { + m68030_write_32(cpu, addr, data); + return 0; + } catch (...) { + return (uint64)-1; + } } // モニター更新 (レジスタウィンドウ) void -MPU680x0Device::MonitorUpdate(TextScreen& monitor) +MPU680x0Device::MonitorUpdateReg(Monitor *, TextScreen& screen) { m68kreg reg; uint32 ppc; int x; int y; - monitor.Clear(); + screen.Clear(); // ローカルにコピー // ただし PPC だけ reg 構造体ではなく cpu クラス側にある @@ -171,7 +246,7 @@ MPU680x0Device::MonitorUpdate(TextScreen // データレジスタ、アドレスレジスタ for (int i = 0; i < 4; i++) { - monitor.Print(0, i, "D%d:%08x D%d:%08x A%d:%08x A%d:%08x", + screen.Print(0, i, "D%d:%08x D%d:%08x A%d:%08x A%d:%08x", i + 0, reg.da[i], i + 4, reg.da[i + 4], i + 0, reg.da[i + 8], @@ -181,7 +256,7 @@ MPU680x0Device::MonitorUpdate(TextScreen // 5列目 x = 50; // SR - monitor.Print(x, 0, "SR:%04x(%c%c%c%c%c)", + screen.Print(x, 0, "SR:%04x(%c%c%c%c%c)", (reg.sr_h() | reg.ccr.Get()), (reg.ccr.IsX()) ? 'X' : '-', (reg.ccr.IsN()) ? 'N' : '-', @@ -190,22 +265,22 @@ MPU680x0Device::MonitorUpdate(TextScreen (reg.ccr.IsC()) ? 'C' : '-'); // VBR - monitor.Print(x, 1, "VBR:%08x", reg.vbr); + screen.Print(x, 1, "VBR:%08x", reg.vbr); // *SP uint ms = (reg.s ? 2 : 0) | (reg.m ? 1 : 0); // T1 T0 S M if (ms == 3) { // Supervisor (Master) mode (A7=MSP, USP/ISP) - monitor.Print(x, 2, TA::Disable, "USP:%08x", reg.usp); - monitor.Print(x, 3, TA::Disable, "ISP:%08x", reg.isp); + screen.Print(x, 2, TA::Disable, "USP:%08x", reg.usp); + screen.Print(x, 3, TA::Disable, "ISP:%08x", reg.isp); } else if (ms == 2) { // Supervisor (Interrupt) mode (A7=ISP, USP/MSP) - monitor.Print(x, 2, TA::Disable, "USP:%08x", reg.usp); - monitor.Print(x, 3, TA::Disable, "MSP:%08x", reg.msp); + screen.Print(x, 2, TA::Disable, "USP:%08x", reg.usp); + screen.Print(x, 3, TA::Disable, "MSP:%08x", reg.msp); } else { // User mode (A7=USP, ISP/MSP) - monitor.Print(x, 2, TA::Disable, "ISP:%08x", reg.isp); - monitor.Print(x, 3, TA::Disable, "MSP:%08x", reg.msp); + screen.Print(x, 2, TA::Disable, "ISP:%08x", reg.isp); + screen.Print(x, 3, TA::Disable, "MSP:%08x", reg.msp); } // 6列目 @@ -214,42 +289,42 @@ MPU680x0Device::MonitorUpdate(TextScreen // CACR:01234567 // CAAR:01234567 x = 66; - monitor.Print(x, 0, "PC: %08x", ppc); - monitor.Print(x, 1, "SFC:%d DFC:%d", reg.sfc, reg.dfc); - monitor.Print(x, 2, "CACR:%08x", reg.cacr); - monitor.Print(x, 3, "CAAR:%08x", reg.caar); + screen.Print(x, 0, "PC: %08x", ppc); + screen.Print(x, 1, "SFC:%d DFC:%d", reg.sfc, reg.dfc); + screen.Print(x, 2, "CACR:%08x", reg.cacr); + screen.Print(x, 3, "CAAR:%08x", reg.caar); // XXX どこに置くのがいいか if (reg.state == 0) { - monitor.Puts(25, 4, "State: Running"); + screen.Puts(25, 4, "State: Running"); } else if (reg.state == CPU_REQ_STOP) { - monitor.Puts(25, 4, "State: STOP instruction"); + screen.Puts(25, 4, "State: STOP instruction"); } else if (reg.state == CPU_REQ_HALT) { - monitor.Puts(25, 4, TA::On, "State: Double Bus Fault"); + screen.Puts(25, 4, TA::On, "State: Double Bus Fault"); } // MMU x = 0; y = 4; - monitor.Puts(x, y++, ""); - monitor.Print(x, y, "SRP:%08x_%08x", reg.srp.h, reg.srp.l); - monitor.Print(x, y + 1, "CRP:%08x_%08x", reg.crp.h, reg.crp.l); + screen.Puts(x, y++, ""); + screen.Print(x, y, "SRP:%08x_%08x", reg.srp.h, reg.srp.l); + screen.Print(x, y + 1, "CRP:%08x_%08x", reg.crp.h, reg.crp.l); x += 23; for (int i = 0; i < 2; i++) { uint32 tt = reg.tt[i]; - monitor.Print(x, y + i, "TT%d:%08x(%c%c%c)", + screen.Print(x, y + i, "TT%d:%08x(%c%c%c)", i, tt, (tt & m68030TT::E) ? 'E' : '-', (tt & m68030TT::CI) ? 'C' : '-', (tt & m68030TT::RWM) ? '-' : ((tt & m68030TT::RW) ? 'R' : 'W')); } x += 19; - monitor.Print(x, y, "TC:%08x(%c%c%c)", + screen.Print(x, y, "TC:%08x(%c%c%c)", reg.tc, (reg.tc & m68030TC::TC_E) ? 'E' : '-', (reg.tc & m68030TC::TC_SRE) ? 'S' : '-', (reg.tc & m68030TC::TC_FCL) ? 'F' : '-'); - monitor.Print(x, y + 1, "MMUSR: %04x(%c%c%c%c%c%c%c N=%d)", + screen.Print(x, y + 1, "MMUSR: %04x(%c%c%c%c%c%c%c N=%d)", reg.mmusr, (reg.mmusr & m68030MMUSR::B) ? 'B' : '-', (reg.mmusr & m68030MMUSR::L) ? 'L' : '-', @@ -263,9 +338,9 @@ MPU680x0Device::MonitorUpdate(TextScreen // FPU x = 0; y = 7; - monitor.Puts(x, y++, ""); + screen.Puts(x, y++, ""); for (int i = 0; i < 8; i++) { - monitor.Print(x, y + i, "FP%d:%04x_%08x_%08x (%-20s)", + screen.Print(x, y + i, "FP%d:%04x_%08x_%08x (%-20s)", i, reg.fpframe.fpf_regs[i * 3 + 0] >> 16, reg.fpframe.fpf_regs[i * 3 + 1], @@ -289,72 +364,53 @@ MPU680x0Device::MonitorUpdate(TextScreen "Plus", }; uint32 fpcr = reg.fpframe.fpf_fpcr; - monitor.Print(x, y++, "FPCR:%04x", fpcr); - monitor.Print(x + 2, y++, "%s %s %s %s %s %s %s %s", - (fpcr & 0x8000) ? "BS" : "--", - (fpcr & 0x4000) ? "SN" : "--", - (fpcr & 0x2000) ? "OP" : "--", - (fpcr & 0x1000) ? "OV" : "--", - (fpcr & 0x0800) ? "UF" : "--", - (fpcr & 0x0400) ? "DZ" : "--", - (fpcr & 0x0200) ? "I2" : "--", - (fpcr & 0x0100) ? "I1" : "--"); - monitor.Print(x + 2, y++, "RP=%s RM=%s", + screen.Print(x, y++, "FPCR:%04x", fpcr); + screen.Puts(x + 2, y, TA::OnOff(fpcr & 0x8000), "BS"); + screen.Puts(x + 5, y, TA::OnOff(fpcr & 0x4000), "SN"); + screen.Puts(x + 8, y, TA::OnOff(fpcr & 0x2000), "OP"); + screen.Puts(x + 11, y, TA::OnOff(fpcr & 0x1000), "OV"); + screen.Puts(x + 14, y, TA::OnOff(fpcr & 0x0800), "UF"); + screen.Puts(x + 17, y, TA::OnOff(fpcr & 0x0400), "DZ"); + screen.Puts(x + 20, y, TA::OnOff(fpcr & 0x0200), "I2"); + screen.Puts(x + 23, y, TA::OnOff(fpcr & 0x0100), "I1"); + y++; + screen.Print(x + 2, y++, "RP=%s RM=%s", rpstr[(fpcr >> 6) & 3], rmstr[(fpcr >> 4) & 3]); // FPSR uint32 fpsr = reg.fpframe.fpf_fpsr; uint32 cc = fpsr >> 24; - monitor.Print(x, y++, "FPSR:%08x", fpsr); - monitor.Print(x + 2, y++, "%c %c %s %s Q=$%02x", - (cc & 0x08) ? 'N' : '-', - (cc & 0x04) ? 'Z' : '-', - (cc & 0x02) ? "Inf" : "---", - (cc & 0x01) ? "NAN" : "---", - (fpsr >> 16) & 0xff); - monitor.Print(x + 2, y++, "%s %s %s %s %s %s %s %s", - (fpsr & 0x8000) ? "BS" : "--", - (fpsr & 0x4000) ? "SN" : "--", - (fpsr & 0x2000) ? "OP" : "--", - (fpsr & 0x1000) ? "OV" : "--", - (fpsr & 0x0800) ? "UF" : "--", - (fpsr & 0x0400) ? "DZ" : "--", - (fpsr & 0x0200) ? "I2" : "--", - (fpsr & 0x0100) ? "I1" : "--"); - monitor.Print(x + 2, y++, "%s %s %s %s %s", - (fpsr & 0x80) ? "IOP" : "---", - (fpsr & 0x40) ? "OVFL" : "----", - (fpsr & 0x20) ? "UNFL" : "----", - (fpsr & 0x10) ? "DZ" : "--", - (fpsr & 0x08) ? "INEX" : "----"); + screen.Print(x, y++, "FPSR:%08x", fpsr); + screen.Puts(x + 2, y, TA::OnOff(cc & 0x08), "N"); + screen.Puts(x + 4, y, TA::OnOff(cc & 0x04), "Z"); + screen.Puts(x + 6, y, TA::OnOff(cc & 0x02), "Inf"); + screen.Puts(x + 10, y, TA::OnOff(cc & 0x01), "NAN"); + screen.Print(x + 14, y, "Q=$%02x", (fpsr >> 16) & 0xff); + y++; + screen.Puts(x + 2, y, TA::OnOff(fpsr & 0x8000), "BS"); + screen.Puts(x + 5, y, TA::OnOff(fpsr & 0x4000), "SN"); + screen.Puts(x + 8, y, TA::OnOff(fpsr & 0x2000), "OP"); + screen.Puts(x + 11, y, TA::OnOff(fpsr & 0x1000), "OV"); + screen.Puts(x + 14, y, TA::OnOff(fpsr & 0x0800), "UF"); + screen.Puts(x + 17, y, TA::OnOff(fpsr & 0x0400), "DZ"); + screen.Puts(x + 20, y, TA::OnOff(fpsr & 0x0200), "I2"); + screen.Puts(x + 23, y, TA::OnOff(fpsr & 0x0100), "I1"); + y++; + screen.Puts(x + 2, y, TA::OnOff(fpsr & 0x80), "IOP"); + screen.Puts(x + 6, y, TA::OnOff(fpsr & 0x80), "OVFL"); + screen.Puts(x + 11, y, TA::OnOff(fpsr & 0x80), "UNFL"); + screen.Puts(x + 16, y, TA::OnOff(fpsr & 0x80), "DZ"); + screen.Puts(x + 19, y, TA::OnOff(fpsr & 0x80), "INEX"); + y++; // FPIAR - monitor.Print(x, y++, "FPIAR:%08x", reg.fpframe.fpf_fpiar); -} - -// CPU 側からのコールバック。RESET 命令ハンドラ -void -m68030_reset_inst(m68kcpu *cpu) -{ - gVM->ResetByMPU(); -} - -// -// ATC モニタ -// -MPUATC::MPUATC(m68kcpu *cpu_) -{ - cpu = cpu_; -#if !defined(ATC_SINGLE) - monitor_size = nnSize(131, m68030ATCTable::LINES + 3); -#else - monitor_size = nnSize(31, 24); -#endif + screen.Print(x, y++, "FPIAR:%08x", reg.fpframe.fpf_fpiar); } +// モニター更新 (ATC) void -MPUATC::MonitorUpdate(TextScreen& monitor) +MPU680x0Device::MonitorUpdateATC(Monitor *, TextScreen& screen) { m68030ATCTable *table; #if !defined(ATC_SINGLE) @@ -368,11 +424,11 @@ MPUATC::MonitorUpdate(TextScreen& monito { 6, "Super/Program" }, }; - monitor.Clear(); + screen.Clear(); // 行数は左端にだけ for (int i = 0; i < m68030ATCTable::LINES; i++) { - monitor.Print(0, i + 2, "%02d:", i); + screen.Print(0, i + 2, "%02d:", i); } for (int t = 0; t < countof(fclist); t++) { @@ -383,8 +439,8 @@ MPUATC::MonitorUpdate(TextScreen& monito int i; table = &cpu->atc.tables[fc]; - monitor.Print(x, 0, "FC=%d %s", fc, name); - monitor.Puts(x, 1, "LAddr PAddr Flag Hit% Age"); + screen.Print(x, 0, "FC=%d %s", fc, name); + screen.Puts(x, 1, "LAddr PAddr Flag Hit% Age"); // 先に統計用の母数を計算 uint64 total = 0; for (i = 0; i < countof(table->hit); i++) { @@ -404,7 +460,7 @@ MPUATC::MonitorUpdate(TextScreen& monito attr = TA::Normal; } - monitor.Print(x, i + 2, attr, "%08x %08x %c%c%c", + screen.Print(x, i + 2, attr, "%08x %08x %c%c%c", a.GetLAddr(), a.GetPAddr(), a.IsBusError() ? 'B' : '-', @@ -412,17 +468,17 @@ MPUATC::MonitorUpdate(TextScreen& monito a.IsModified() ? 'M' : '-'); } // ヘッドのヒット率 - monitor.Puts(x + 0, i + 2, "head"); + screen.Puts(x + 0, i + 2, "head"); r = (double)table->hit_head * 100 / total; if (!isnan(r)) { - monitor.Print(x + 5, i + 2, "%4.1f%%", r); + screen.Print(x + 5, i + 2, "%4.1f%%", r); } // 配列のヒット率とミス率 - monitor.Puts(x + 17, i + 2, "miss"); + screen.Puts(x + 17, i + 2, "miss"); for (i = 0; i < countof(table->hit); i++) { r = (double)(table->hit[i] * 100) / total; if (!isnan(r)) { - monitor.Print(x + 22, i + 2, "%4.1f%%", r); + screen.Print(x + 22, i + 2, "%4.1f%%", r); } } // カウンタ @@ -430,7 +486,7 @@ MPUATC::MonitorUpdate(TextScreen& monito for (i = 0; i < countof(table->line); i++) { m68030ATCLine& a = table->line[i]; if (!a.IsInvalid()) { - monitor.Print(x + 27, i + 2, "%4d", table->head->age - a.age); + screen.Print(x + 27, i + 2, "%4d", table->head->age - a.age); } } } @@ -439,11 +495,11 @@ MPUATC::MonitorUpdate(TextScreen& monito int i; table = &cpu->atc.tables[0]; - monitor.Clear(); + screen.Clear(); - monitor.Puts(0, 0, "No. FC LAddr PAddr Flag"); + screen.Puts(0, 0, "No. FC LAddr PAddr Flag"); for (a = table->head, i = 0; a; a = a->next, i++) { - monitor.Print(0, i + 1, "%02d:", i); + screen.Print(0, i + 1, "%02d:", i); if (!a->IsInvalid()) { char dp; switch (a->fc & 3) { @@ -451,7 +507,7 @@ MPUATC::MonitorUpdate(TextScreen& monito case 2: dp = 'P'; break; default: dp = '?'; break; } - monitor.Print(4, i + 1, "%d(%c%c):%08x %08x %c%c%c", + screen.Print(4, i + 1, "%d(%c%c):%08x %08x %c%c%c", a->fc, (a->fc & 4) ? 'S' : 'U', dp, @@ -463,3 +519,10 @@ MPUATC::MonitorUpdate(TextScreen& monito } #endif } + +// CPU 側からのコールバック。RESET 命令ハンドラ +void +m68030_reset_inst(m68kcpu *cpu) +{ + gVM->ResetByMPU(); +}