using System.Collections.Generic; using System.Text; using VMdemo.Simulation; namespace VMdemo.UI { public static class SimulationUIFormatter { private const string ColorVpn = "#4FC3F7"; private const string ColorL1 = "#FFB74D"; private const string ColorL2 = "#81C784"; private const string ColorOffset = "#B0BEC5"; public static string FormatStateSummary( SimulationState state, int machineBits, int vaBits, int pageSizeKB, int physicalMemoryMB, int tlbEntries) { var va = FormatAddressHex(state.CurrentVirtualAddress, vaBits); var pa = FormatAddressHex(state.CurrentPhysicalAddress, vaBits); var stepText = TranslationStepDisplay.ToChinese(state.CurrentStep); return $"系统规格:{machineBits}位机\n" + $"虚拟地址有效位:{vaBits}位\n" + $"页大小:{pageSizeKB}KB\n" + $"物理内存:{physicalMemoryMB}MB\n" + $"TLB:{tlbEntries}条全相联\n"; } public static string FormatStats(StatsCollector stats) { return $"总访问={stats.TotalAccess}\n" + $"TLB命中率={stats.TlbHitRate:P2}\n" + $"页表命中率={stats.PageTableHitRate:P2}\n" + $"缺页次数={stats.PageFault}\n" + $"平均开销={stats.AvgCost:F2}"; } public static string FormatTlbTable( IReadOnlyList entries, int vpnBits, int pfnBits) { if (entries == null || entries.Count == 0) { return "TLB:空"; } var sb = new StringBuilder(); sb.AppendLine("TLB(最近使用 -> 最久未用)"); for (var i = 0; i < entries.Count; i++) { var entry = entries[i]; sb.Append("#").Append(i + 1) .Append("VPN=").Append(FormatBitWidthHex(entry.Vpn, vpnBits)) .Append(" -> PFN=").Append(FormatBitWidthHex(entry.Pfn, pfnBits)) .AppendLine(); } return sb.ToString().TrimEnd(); } public static string FormatCurrentPageTableEntry( SimulationState state, TwoLevelPageTable pageTable, EvictionInfo eviction) { if (state == null || pageTable == null) { return "页表:N/A"; } var sb = new StringBuilder(); sb.Append("当前页表项:"); if (pageTable.TryGetEntry(state.CurrentAddressParts.L1Index, state.CurrentAddressParts.L2Index, out var entry)) { sb.Append("存在=").Append(entry.Present) .Append(" 物理帧号PFN=").Append(FormatHex(entry.Pfn)) .Append(" 脏位=").Append(entry.Dirty); } else { sb.Append("(缺失)"); } sb.AppendLine(); if (eviction.HasEvicted) { sb.Append("最近淘汰:虚拟页号VPN=").Append(FormatHex(eviction.EvictedVpn)) .Append(" 物理帧号PFN=").Append(FormatHex(eviction.EvictedPfn)); } else { sb.Append("最近淘汰:无"); } return sb.ToString(); } public static string FormatFifoQueue(IReadOnlyList fifoOrder) { if (fifoOrder == null || fifoOrder.Count == 0) { return "FIFO:空"; } var sb = new StringBuilder("FIFO(最早进入 -> 最新进入):"); for (var i = 0; i < fifoOrder.Count; i++) { if (i > 0) { sb.Append(" -> "); } sb.Append(FormatHex(fifoOrder[i])); } return sb.ToString(); } public static string FormatAddressHex(ulong value, int vaBits) { return FormatBitWidthHex(value, vaBits); } private static string FormatHex(ulong value) { return $"0x{value:X}"; } public static string FormatBitWidthHex(ulong value, int bits) { var digits = bits switch { 8 => 2, 16 => 4, 24 => 6, 32 => 8, 48 => 12, 64 => 16, _ => bits > 0 ? (bits + 3) / 4 : 1 }; return $"0x{value.ToString($"X{digits}")}"; } public static int ComputeBitsForCount(ulong count) { if (count <= 1UL) { return 1; } var maxValue = count - 1UL; var bits = 0; while (maxValue > 0UL) { bits++; maxValue >>= 1; } return bits; } public static string FormatAddressSplitTrace( SimulationState state, int vaBits, int offsetBits, int l1Bits, int l2Bits) { if (state == null) { return "地址拆分可视化:N/A"; } var vpnBits = vaBits - offsetBits; var vaHex = FormatAddressHex(state.CurrentVirtualAddress, vaBits); var vaBin = FormatBinary(state.CurrentVirtualAddress, vaBits); var vaBinColored = FormatVaBinaryWithFieldColors(state.CurrentVirtualAddress, vaBits, l1Bits, l2Bits, offsetBits); var vpnBin = FormatBinary(state.CurrentAddressParts.Vpn, vpnBits); var l1Bin = FormatBinary(state.CurrentAddressParts.L1Index, l1Bits); var l2Bin = FormatBinary(state.CurrentAddressParts.L2Index, l2Bits); var offBin = FormatBinary(state.CurrentAddressParts.Offset, offsetBits); var sb = new StringBuilder(); sb.AppendLine("地址拆分可视化"); sb.AppendLine($"{vaHex})"); sb.AppendLine($"{vaBinColored}"); sb.AppendLine( $"{WrapColor("VPN", ColorVpn)} = {WrapColor("L1+L2", ColorVpn)}," + $"{WrapColor("L1", ColorL1)},{WrapColor("L2", ColorL2)},{WrapColor("Offset", ColorOffset)}"); sb.AppendLine($"VPN({vpnBits}) = L1({l1Bits}) + L2({l2Bits}) | Offset({offsetBits})"); sb.AppendLine($"VPN:{FormatBitWidthHex(state.CurrentAddressParts.Vpn, vpnBits)} ({WrapColor(vpnBin, ColorVpn)})"); sb.AppendLine($"L1 索引:{FormatBitWidthHex(state.CurrentAddressParts.L1Index, l1Bits)} ({WrapColor(l1Bin, ColorL1)})"); sb.AppendLine($"L2 索引:{FormatBitWidthHex(state.CurrentAddressParts.L2Index, l2Bits)} ({WrapColor(l2Bin, ColorL2)})"); sb.Append($"Offset:{FormatBitWidthHex(state.CurrentAddressParts.Offset, offsetBits)} ({WrapColor(offBin, ColorOffset)})"); return sb.ToString(); } public static string FormatPageTableWalkTrace(SimulationState state, TwoLevelPageTable pageTable) { if (state == null || pageTable == null) { return "页表访问路径:N/A"; } var probe = pageTable.Probe(state.CurrentAddressParts.L1Index, state.CurrentAddressParts.L2Index); var sb = new StringBuilder(); sb.AppendLine("多级页表查询可视化"); sb.AppendLine( $"1) 先按 VPN 拆分:L1={state.CurrentAddressParts.L1Index}, L2={state.CurrentAddressParts.L2Index}"); switch (probe.Status) { case PageTableProbeStatus.MissingL1Table: sb.Append("2) L1 未命中:对应二级页表不存在。"); break; case PageTableProbeStatus.MissingL2Entry: sb.Append("2) L1 命中,L2 未命中:页表项不存在。"); break; case PageTableProbeStatus.NotPresentEntry: sb.Append($"2) L1/L2 命中,但 present=false(PFN={FormatHex(probe.Entry.Pfn)})。"); break; case PageTableProbeStatus.PresentEntry: sb.Append($"2) L1/L2 命中,present=true,得到 PFN={FormatHex(probe.Entry.Pfn)}。"); break; } return sb.ToString(); } private static string FormatBinary(ulong value, int bits) { if (bits <= 0) { return "0"; } var sb = new StringBuilder(bits + (bits / 4)); for (var i = bits - 1; i >= 0; i--) { var bit = (value >> i) & 1UL; sb.Append(bit == 1UL ? '1' : '0'); if (i > 0 && i % 4 == 0) { sb.Append('_'); } } return sb.ToString(); } private static string FormatVaBinaryWithFieldColors( ulong value, int vaBits, int l1Bits, int l2Bits, int offsetBits) { if (vaBits <= 0) { return "0"; } var sb = new StringBuilder(vaBits * 10); string currentColor = null; for (var i = vaBits - 1; i >= 0; i--) { var bitColor = ResolveBitColor(i, l1Bits, l2Bits, offsetBits); if (currentColor != bitColor) { if (currentColor != null) { sb.Append(""); } sb.Append(""); currentColor = bitColor; } var bit = (value >> i) & 1UL; sb.Append(bit == 1UL ? '1' : '0'); if (i > 0 && i % 4 == 0) { sb.Append('_'); } } if (currentColor != null) { sb.Append(""); } return sb.ToString(); } private static string ResolveBitColor(int bitIndex, int l1Bits, int l2Bits, int offsetBits) { var l1Start = offsetBits + l2Bits; if (bitIndex >= l1Start) { return ColorL1; } if (bitIndex >= offsetBits) { return ColorL2; } return ColorOffset; } private static string WrapColor(string text, string colorHex) { return $"{text}"; } } }