--- nono/vm/mpu680x0.cpp 2026/04/29 17:05:17 1.1.1.15 +++ nono/vm/mpu680x0.cpp 2026/04/29 17:05:24 1.1.1.16 @@ -12,12 +12,12 @@ #include "config.h" #include "debugger.h" #include "interrupt.h" +#include "m68030cache.h" #include "mainapp.h" #include "scheduler.h" #include "syncer.h" #include "uimessage.h" #include "vectortable.h" -#include "vm.h" #include static Syncer *gSyncer; @@ -33,6 +33,8 @@ MPU680x0Device::MPU680x0Device() SetCRP(0x00000001, 0); // FPU fpu_init(); + // キャッシュ + icache.reset(new m68030Cache()); // 割り込みイベントコールバック設定 intr_event.func = ToEventCallback(&MPU680x0Device::InterruptCallback); @@ -40,18 +42,23 @@ MPU680x0Device::MPU680x0Device() // レジスタモニター reg_monitor.func = ToMonitorCallback(&MPU680x0Device::MonitorUpdateReg); - reg_monitor.SetSize(79, 16); + reg_monitor.SetSize(78, 19); reg_monitor.Regist(ID_MONITOR_MPUREG); // ATC モニター atc_monitor.func = ToMonitorCallback(&MPU680x0Device::MonitorUpdateATC); #if !defined(ATC_SINGLE) - atc_monitor.SetSize(131, m68030ATCTable::LINES + 3); + atc_monitor.SetSize(135, m68030ATCTable::LINES + 4); #else - atc_monitor.SetSize(31, 24); + atc_monitor.SetSize(32, 24); #endif atc_monitor.Regist(ID_MONITOR_MPUATC); + // キャッシュモニター + cache_monitor.func = ToMonitorCallback(&MPU680x0Device::MonitorUpdateCache); + cache_monitor.SetSize(48, 20); + cache_monitor.Regist(ID_MONITOR_MPUCACHE); + SetTrace(false); } @@ -60,6 +67,14 @@ MPU680x0Device::~MPU680x0Device() { } +void +MPU680x0Device::SetLogLevel(int loglevel_) +{ + inherited::SetLogLevel(loglevel_); + + atc.SetLogLevel(loglevel_); +} + // 初期化 bool MPU680x0Device::Init() @@ -197,9 +212,7 @@ MPU680x0Device::ExecFull(Event& ev) intr_pending = false; // 前の命令実行後となるここで割り込みを起動 - int cycle = ExceptionInterrupt(); - - ev.time = cycle * clock_nsec; + ev.time = ExceptionInterrupt(); scheduler->StartEvent(ev); } else { if (cpu_state == CPU_STATE_NORMAL) { @@ -273,14 +286,14 @@ MPU680x0Device::InterruptCallback(Event& // 信号線が 2 クロック期間安定していること云々は省略 - // ホールトなら何もしない + // 割り込みを起こすかどうかに関わらずここで更新。 + intr_level = level; + + // ホールトならここまで。 if (cpu_state == CPU_STATE_HALT) { return; } - // 割り込みを起こすかどうかに関わらずここで更新 - intr_level = level; - // 割り込み例外を起動するのは // o レベルがマスクより高い // o マスクに関係なく、レベルが下位から 7 に変化した場合 @@ -347,7 +360,8 @@ MPU680x0Device::SetFLineCallback(bool (* void MPU680x0Device::ops_reset() { - gVM->ResetByMPU(); + auto mainbus = GetMainbusDevice(); + mainbus->ResetByMPU(); } // ホールト状態 @@ -363,70 +377,6 @@ MPU680x0Device::Halt() UIMessage::Post(UIMessage::HALT); } -// MPU からのアクセスをエミュレート -uint64 -MPU680x0Device::Read8(uint32 addr) -{ - try { - return read_8(addr); - } catch (...) { - return (uint64)-1; - } -} - -uint64 -MPU680x0Device::Read16(uint32 addr) -{ - try { - return read_16(addr); - } catch (...) { - return (uint64)-1; - } -} - -uint64 -MPU680x0Device::Read32(uint32 addr) -{ - try { - return read_32(addr); - } catch (...) { - return (uint64)-1; - } -} - -uint64 -MPU680x0Device::Write8(uint32 addr, uint32 data) -{ - try { - write_8(addr, data); - return 0; - } catch (...) { - return (uint64)-1; - } -} - -uint64 -MPU680x0Device::Write16(uint32 addr, uint32 data) -{ - try { - write_16(addr, data); - return 0; - } catch (...) { - return (uint64)-1; - } -} - -uint64 -MPU680x0Device::Write32(uint32 addr, uint32 data) -{ - try { - write_32(addr, data); - return 0; - } catch (...) { - return (uint64)-1; - } -} - // モニター更新 (レジスタウィンドウ) void MPU680x0Device::MonitorUpdateReg(Monitor *, TextScreen& screen) @@ -465,76 +415,96 @@ MPU680x0Device::MonitorUpdateReg(Monitor (tmp.ccr.IsV()) ? 'V' : '-', (tmp.ccr.IsC()) ? 'C' : '-'); - // VBR - screen.Print(x, 1, "VBR:%08x", tmp.vbr); - // *SP uint ms = (tmp.s ? 2 : 0) | (tmp.m ? 1 : 0); // T1 T0 S M if (ms == 3) { // Supervisor (Master) mode (A7=MSP, USP/ISP) - screen.Print(x, 2, TA::Disable, "USP:%08x", tmp.usp); - screen.Print(x, 3, TA::Disable, "ISP:%08x", tmp.isp); + screen.Print(x, 1, TA::Disable, "USP:%08x", tmp.usp); + screen.Print(x, 2, TA::Disable, "ISP:%08x", tmp.isp); } else if (ms == 2) { // Supervisor (Interrupt) mode (A7=ISP, USP/MSP) - screen.Print(x, 2, TA::Disable, "USP:%08x", tmp.usp); - screen.Print(x, 3, TA::Disable, "MSP:%08x", tmp.msp); + screen.Print(x, 1, TA::Disable, "USP:%08x", tmp.usp); + screen.Print(x, 2, TA::Disable, "MSP:%08x", tmp.msp); } else { // User mode (A7=USP, ISP/MSP) - screen.Print(x, 2, TA::Disable, "ISP:%08x", tmp.isp); - screen.Print(x, 3, TA::Disable, "MSP:%08x", tmp.msp); + screen.Print(x, 1, TA::Disable, "ISP:%08x", tmp.isp); + screen.Print(x, 2, TA::Disable, "MSP:%08x", tmp.msp); } // 6列目 - // PC: 01234567 - // SFC:1 DFC:1 - // CACR:01234567 - // CAAR:01234567 + // PC: 01234567 + // SFC:1 DFC:1 + // VBR:01234567 x = 66; - screen.Print(x, 0, "PC: %08x", tmp_ppc); - screen.Print(x, 1, "SFC:%d DFC:%d", tmp.sfc, tmp.dfc); - screen.Print(x, 2, "CACR:%08x", tmp.cacr); - screen.Print(x, 3, "CAAR:%08x", tmp.caar); + screen.Print(x, 0, "PC: %08x", tmp_ppc); + screen.Print(x, 1, "SFC:%d DFC:%d", tmp.GetSFC(), tmp.GetDFC()); + screen.Print(x, 2, "VBR:%08x", tmp.vbr); - // XXX どこに置くのがいいか switch (tmp_state) { case CPU_STATE_NORMAL: - screen.Puts(25, 4, "State: Running"); + screen.Puts(50, 3, "State: Running"); break; case CPU_STATE_STOP: - screen.Puts(25, 4, "State: STOP instruction"); + screen.Puts(50, 3, "State: STOP instruction"); break; case CPU_STATE_HALT: - screen.Puts(25, 4, TA::On, "State: Double Bus Fault"); + screen.Puts(50, 3, TA::On, "State: Double Bus Fault"); break; default: - screen.Print(25, 4, TA::On, "corrupted cpu_state=%d", tmp_state); + screen.Print(50, 3, TA::On, "corrupted cpu_state=%d", tmp_state); break; } + // Cache + y = 4; + screen.Puts(0, y++, ""); + screen.Print(0, y, "CACR:%08x(", tmp.cacr); + screen.Puts(14, y, TA::OnOff(tmp.cacr & M68K::CACR_WA), "WA"); + screen.Puts(17, y, TA::OnOff(tmp.cacr & M68K::CACR_DBE), "DBE"); + screen.Puts(21, y, TA::OnOff(tmp.cacr & M68K::CACR_FD), "FD"); + screen.Puts(24, y, TA::OnOff(tmp.cacr & M68K::CACR_ED), "ED"); + screen.Puts(27, y, TA::OnOff(tmp.cacr & M68K::CACR_IBE), "IBE"); + screen.Puts(31, y, TA::OnOff(tmp.cacr & M68K::CACR_FI), "FI"); + screen.Puts(34, y, TA::OnOff(tmp.cacr & M68K::CACR_EI), "EI"); + screen.Putc(36, y, ')'); + screen.Print(50, y, "CAAR:%08x", tmp.caar); + y++; + // MMU x = 0; - y = 4; screen.Puts(x, y++, ""); screen.Print(x, y, "SRP:%08x_%08x", tmp.srp.h, tmp.srp.l); screen.Print(x, y + 1, "CRP:%08x_%08x", tmp.crp.h, tmp.crp.l); - x += 23; + x += 25; for (int i = 0; i < 2; i++) { uint32 tt = tmp.tt[i]; - screen.Print(x, y + i, "TT%d:%08x(%c%c%c)", + screen.Print(x, y + i, + "TT%d:%08x(%c%c%c Addr=$%02x Mask=$%02x FC=%d FCMask=%d)", i, tt, (tt & m68030TT::E) ? 'E' : '-', (tt & m68030TT::CI) ? 'C' : '-', - (tt & m68030TT::RWM) ? '-' : ((tt & m68030TT::RW) ? 'R' : 'W')); - } - x += 19; - screen.Print(x, y, "TC:%08x(%c%c%c)", + (tt & m68030TT::RWM) ? '-' : ((tt & m68030TT::RW) ? 'R' : 'W'), + (tt >> 24), + (tt >> 16) & 0xff, + (tt >> 4) & 0x07, + (tt ) & 0x07); + } + y += 2; + screen.Print(0, y, + "TC:%08x(%c%c%c IS=$%x TIA-D=%x:%x:%x:%x PS=$%x)", tmp.tc, (tmp.tc & m68030TC::TC_E) ? 'E' : '-', (tmp.tc & m68030TC::TC_SRE) ? 'S' : '-', - (tmp.tc & m68030TC::TC_FCL) ? 'F' : '-'); - y++; - screen.Print(x, y, "MMUSR: %04x(", tmp.mmusr); - x += 12; + (tmp.tc & m68030TC::TC_FCL) ? 'F' : '-', + (tmp.tc >> 16) & 0xf, + (tmp.tc >> 12) & 0xf, + (tmp.tc >> 8) & 0xf, + (tmp.tc >> 4) & 0xf, + (tmp.tc ) & 0xf, + (tmp.tc >> 20) & 0xf); + x = 49; + screen.Print(x, y, "MMUSR:%04x(", tmp.mmusr); + x += 11; screen.Putc(x++, y, TA::OnOff(tmp.mmusr & m68030MMUSR::B) | 'B'); screen.Putc(x++, y, TA::OnOff(tmp.mmusr & m68030MMUSR::L) | 'L'); screen.Putc(x++, y, TA::OnOff(tmp.mmusr & m68030MMUSR::S) | 'S'); @@ -546,10 +516,10 @@ MPU680x0Device::MonitorUpdateReg(Monitor x += 3; screen.Putc(x++, y, TA::OnOff(tmp.mmusr & m68030MMUSR::T) | 'T'); screen.Print(x, y, "---N=%d)", tmp.mmusr & m68030MMUSR::N); + y++; // FPU x = 0; - y = 7; screen.Puts(x, y++, ""); for (int i = 0; i < 8; i++) { screen.Print(x, y + i, "FP%d:%04x_%08x_%08x (%-20s)", @@ -638,7 +608,7 @@ MPU680x0Device::MonitorUpdateATC(Monitor } for (int t = 0; t < countof(fclist); t++) { - int x = t * 32 + 4; + int x = t * 33 + 4; int fc = fclist[t].fc; const char *name = fclist[t].name; double r; @@ -646,7 +616,7 @@ MPU680x0Device::MonitorUpdateATC(Monitor table = &atc.tables[fc]; screen.Print(x, 0, "FC=%d %s", fc, name); - screen.Puts(x, 1, "LAddr PAddr Flag Hit% Age"); + screen.Puts(x, 1, "LAddr PAddr Flag Hit% Age"); // 先に統計用の母数を計算 uint64 total = 0; for (i = 0; i < countof(table->hit); i++) { @@ -666,10 +636,11 @@ MPU680x0Device::MonitorUpdateATC(Monitor attr = TA::Normal; } - screen.Print(x, i + 2, attr, "%08x %08x %c%c%c", + screen.Print(x, i + 2, attr, "%08x %08x %c%c%c%c", a.GetLAddr(), a.GetPAddr(), a.IsBusError() ? 'B' : '-', + a.IsCInhibit() ? 'C' : '-', a.IsWProtect() ? 'P' : '-', a.IsModified() ? 'M' : '-'); } @@ -680,11 +651,11 @@ MPU680x0Device::MonitorUpdateATC(Monitor screen.Print(x + 5, i + 2, "%4.1f%%", r); } // 配列のヒット率とミス率 - screen.Puts(x + 17, i + 2, "miss"); + screen.Puts(x + 18, i + 2, "miss"); for (i = 0; i < countof(table->hit); i++) { r = (double)(table->hit[i] * 100) / total; if (!std::isnan(r)) { - screen.Print(x + 22, i + 2, "%4.1f%%", r); + screen.Print(x + 23, i + 2, "%4.1f%%", r); } } // カウンタ @@ -692,10 +663,14 @@ MPU680x0Device::MonitorUpdateATC(Monitor for (i = 0; i < countof(table->line); i++) { m68030ATCLine& a = table->line[i]; if (!a.IsInvalid()) { - screen.Print(x + 27, i + 2, "%4d", table->head->age - a.age); + screen.Print(x + 28, i + 2, "%4d", table->head->age - a.age); } } } + + screen.Print(0, 25, + "Note: Real 68030's ATC is 22 entries, FC-mixed. " + "This FC-separated one is by nono."); #else m68030ATCLine *a; int i; @@ -713,15 +688,53 @@ MPU680x0Device::MonitorUpdateATC(Monitor case 2: dp = 'P'; break; default: dp = '?'; break; } - screen.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%c", a->fc, (a->fc & 4) ? 'S' : 'U', dp, a->GetLAddr(), a->GetPAddr(), a->IsBusError() ? 'B' : '-', + a->IsCInhibit() ? 'C' : '-', a->IsWProtect() ? 'W' : '-', a->IsModified() ? 'M' : '-'); } } #endif } + +// モニタ更新 (キャッシュ) +void +MPU680x0Device::MonitorUpdateCache(Monitor *, TextScreen& screen) +{ + int y; + screen.Clear(); + + // + // 01234567890123456789012345678901234567890123456789 + // Tag Address Data + // S.012345'00: 00000000 00000000 -------- 00000000 + + screen.Print(0, 0, ""); + screen.Print(0, 1, "Tag Address Data"); + + y = 2; + for (int idx = 0; idx < icache->line.size(); idx++) { + auto& l = icache->line[idx]; + screen.Print(0, y, "%c.%06x'%x0:", + (l.IsSuper() ? 'S' : 'U'), + (l.TagAddr() >> 8), + idx); + + for (int i = 0; i < 4; i++) { + if (l.valid[i]) { + screen.Print(13 + 9 * i, y, "%08x", l.data[i]); + } else { + screen.Print(13 + 9 * i, y, TA::Disable, "--------"); + } + } + y++; + } + + y++; + screen.Print(0, y, " Not Implemented"); +}