using System; using VMdemo.Core; namespace VMdemo.Simulation { public enum TranslationStep { GenerateVA = 0, SplitVA = 1, LookupTLB = 2, LookupPageTable = 3, HandlePageFault = 4, ComposePA = 5, Finalize = 6 } public readonly struct AccessExecutionResult { public AccessExecutionResult( int round, ulong virtualAddress, AddressParts addressParts, ulong pfn, ulong physicalAddress, bool tlbHit, bool pageTableHit, bool pageFault, EvictionInfo eviction) { Round = round; VirtualAddress = virtualAddress; AddressParts = addressParts; Pfn = pfn; PhysicalAddress = physicalAddress; TlbHit = tlbHit; PageTableHit = pageTableHit; PageFault = pageFault; Eviction = eviction; } public int Round { get; } public ulong VirtualAddress { get; } public AddressParts AddressParts { get; } public ulong Pfn { get; } public ulong PhysicalAddress { get; } public bool TlbHit { get; } public bool PageTableHit { get; } public bool PageFault { get; } public EvictionInfo Eviction { get; } } public class TranslatorEngine { private readonly SimulationConfig _config; private readonly ConfigValidator.DerivedConfig _derivedConfig; private readonly int? _seed; private AddressGenerator _addressGenerator; private TlbCache _tlbCache; private TwoLevelPageTable _pageTable; private PhysicalMemoryManager _physicalMemoryManager; private bool _hasPendingForcedVirtualAddress; private ulong _pendingForcedVirtualAddress; private EvictionInfo _lastEviction; public TranslatorEngine(SimulationConfig config, int? seed = null) { if (!ConfigValidator.TryValidateAndBuildDerived(config, out var derived, out var errorMessage)) { throw new ArgumentException(errorMessage, nameof(config)); } _config = config; _derivedConfig = derived; _seed = seed; State = new SimulationState(); Stats = new StatsCollector(); AddressTranslatorUtils.GetPageTableBitLayout(derived.VpnBits, out var l1Bits, out var l2Bits); L1Bits = l1Bits; L2Bits = l2Bits; _addressGenerator = CreateAddressGenerator(); _tlbCache = new TlbCache(_config.tlbEntries); _pageTable = new TwoLevelPageTable(L1Bits, L2Bits); _physicalMemoryManager = new PhysicalMemoryManager(_derivedConfig.FrameCount); Reset(); } public SimulationState State { get; } public TranslationStep CurrentStep => State.CurrentStep; public int MachineBits => _config.machineBits; public int VaBits => _config.vaBits; public int PageSizeKB => _config.pageSizeKB; public int PhysicalMemoryMB => _config.physicalMemoryMB; public int OffsetBits => _derivedConfig.OffsetBits; public int L1Bits { get; } public int L2Bits { get; } public ulong MaxVirtualAddress => _addressGenerator.MaxVirtualAddress; public TlbCache TlbCache => _tlbCache; public TwoLevelPageTable PageTable => _pageTable; public PhysicalMemoryManager PhysicalMemoryManager => _physicalMemoryManager; public StatsCollector Stats { get; } public EvictionInfo LastEviction => _lastEviction; public void Reset() { State.Reset(); _lastEviction = EvictionInfo.None; _hasPendingForcedVirtualAddress = false; _pendingForcedVirtualAddress = 0UL; Stats.Reset(); _addressGenerator = CreateAddressGenerator(); _tlbCache = new TlbCache(_config.tlbEntries); _pageTable = new TwoLevelPageTable(L1Bits, L2Bits); _physicalMemoryManager = new PhysicalMemoryManager(_derivedConfig.FrameCount); } public void SetNextVirtualAddress(ulong virtualAddress) { EnsureVirtualAddressInRange(virtualAddress); _pendingForcedVirtualAddress = virtualAddress; _hasPendingForcedVirtualAddress = true; } public bool StepOnce() { switch (State.CurrentStep) { case TranslationStep.GenerateVA: ExecuteGenerateVa(); return false; case TranslationStep.SplitVA: ExecuteSplitVa(); return false; case TranslationStep.LookupTLB: ExecuteLookupTlb(); return false; case TranslationStep.LookupPageTable: ExecuteLookupPageTable(); return false; case TranslationStep.HandlePageFault: ExecuteHandlePageFault(); return false; case TranslationStep.ComposePA: ExecuteComposePa(); return false; case TranslationStep.Finalize: ExecuteFinalize(); return true; default: throw new InvalidOperationException($"未知翻译步骤:{State.CurrentStep}"); } } public AccessExecutionResult RunOneAccess(ulong? forcedVirtualAddress = null) { if (State.CurrentStep != TranslationStep.GenerateVA) { throw new InvalidOperationException("RunOneAccess 只能在 GenerateVA 起始步骤调用。"); } if (forcedVirtualAddress.HasValue) { SetNextVirtualAddress(forcedVirtualAddress.Value); } while (!StepOnce()) { } return new AccessExecutionResult( State.CurrentRound, State.CurrentVirtualAddress, State.CurrentAddressParts, State.CurrentPfn, State.CurrentPhysicalAddress, State.IsTlbHit, State.IsPageTableHit, State.IsPageFault, _lastEviction); } private void ExecuteGenerateVa() { State.IsTlbHit = false; State.IsPageTableHit = false; State.IsPageFault = false; State.CurrentCost = 0; State.CurrentAddressParts = AddressParts.Empty; State.CurrentPhysicalAddress = 0UL; State.CurrentPfn = 0UL; State.HasCurrentPfn = false; State.LastDecisionReason = "已生成本轮虚拟地址,准备进行地址拆分。"; _lastEviction = EvictionInfo.None; if (_hasPendingForcedVirtualAddress) { State.CurrentVirtualAddress = _pendingForcedVirtualAddress; _hasPendingForcedVirtualAddress = false; _pendingForcedVirtualAddress = 0UL; } else { State.CurrentVirtualAddress = _addressGenerator.NextVirtualAddress(); } State.CurrentStep = TranslationStep.SplitVA; } private void ExecuteSplitVa() { State.CurrentAddressParts = AddressTranslatorUtils.SplitVirtualAddress( State.CurrentVirtualAddress, _config.vaBits, _derivedConfig.OffsetBits); State.LastDecisionReason = "已拆分 VA 为 VPN/Offset,并从 VPN 拆分出 L1/L2 索引。"; State.CurrentStep = TranslationStep.LookupTLB; } private void ExecuteLookupTlb() { if (_tlbCache.TryLookup(State.CurrentAddressParts.Vpn, out var pfn)) { State.IsTlbHit = true; State.CurrentPfn = pfn; State.HasCurrentPfn = true; State.LastDecisionReason = $"TLB 命中:VPN={State.CurrentAddressParts.Vpn} 命中 PFN={pfn},跳过页表,直接合成物理地址。"; State.CurrentStep = TranslationStep.ComposePA; return; } State.LastDecisionReason = $"TLB 未命中:VPN={State.CurrentAddressParts.Vpn} 未找到映射,转入页表查询。"; State.CurrentStep = TranslationStep.LookupPageTable; } private void ExecuteLookupPageTable() { var probe = _pageTable.Probe(State.CurrentAddressParts.L1Index, State.CurrentAddressParts.L2Index); if (probe.Status == PageTableProbeStatus.PresentEntry) { State.IsPageTableHit = true; State.CurrentPfn = probe.Entry.Pfn; State.HasCurrentPfn = true; _tlbCache.InsertOrUpdate(State.CurrentAddressParts.Vpn, probe.Entry.Pfn); State.LastDecisionReason = $"页表命中:L1={State.CurrentAddressParts.L1Index}, L2={State.CurrentAddressParts.L2Index}, PFN={probe.Entry.Pfn},并写回 TLB。"; State.CurrentStep = TranslationStep.ComposePA; return; } State.LastDecisionReason = probe.Status switch { PageTableProbeStatus.MissingL1Table => $"页表未命中:L1={State.CurrentAddressParts.L1Index} 对应二级页表不存在,触发缺页处理。", PageTableProbeStatus.MissingL2Entry => $"页表未命中:L2={State.CurrentAddressParts.L2Index} 页表项不存在,触发缺页处理。", PageTableProbeStatus.NotPresentEntry => $"页表项无效:L2={State.CurrentAddressParts.L2Index} present=false,触发缺页处理。", _ => "页表未命中,触发缺页处理。" }; State.CurrentStep = TranslationStep.HandlePageFault; } private void ExecuteHandlePageFault() { var result = MemoryAccessResolver.Resolve( State.CurrentAddressParts.Vpn, State.CurrentAddressParts.L1Index, State.CurrentAddressParts.L2Index, _pageTable, _physicalMemoryManager, _tlbCache); State.IsPageTableHit = result.PageTableHit; State.IsPageFault = result.PageFault; State.CurrentPfn = result.Pfn; State.HasCurrentPfn = true; _lastEviction = result.Eviction; State.LastDecisionReason = result.Eviction.HasEvicted ? $"缺页处理完成:装入 PFN={result.Pfn},并按 FIFO 淘汰 VPN={result.Eviction.EvictedVpn}。" : $"缺页处理完成:装入 PFN={result.Pfn},当前仍有空闲物理帧。"; State.CurrentStep = TranslationStep.ComposePA; } private void ExecuteComposePa() { if (!State.HasCurrentPfn) { throw new InvalidOperationException("ComposePA 阶段缺少 PFN,无法合成物理地址。"); } State.CurrentPhysicalAddress = (State.CurrentPfn << _derivedConfig.OffsetBits) | State.CurrentAddressParts.Offset; State.LastDecisionReason = $"物理地址合成:PA = (PFN << offsetBits) | offset = ({State.CurrentPfn} << {_derivedConfig.OffsetBits}) | {State.CurrentAddressParts.Offset}。"; State.CurrentStep = TranslationStep.Finalize; } private void ExecuteFinalize() { State.CurrentCost = Stats.CalculateCost( State.IsTlbHit, State.IsPageTableHit, State.IsPageFault, _config.pageFaultPenalty); Stats.RecordAccess( State.IsTlbHit, State.IsPageTableHit, State.IsPageFault, State.CurrentCost); State.LastDecisionReason = State.IsPageFault ? $"本轮完成:TLB 未命中 + 页表未命中,发生缺页,开销={State.CurrentCost}。" : State.IsTlbHit ? $"本轮完成:TLB 命中,开销={State.CurrentCost}。" : $"本轮完成:TLB 未命中 + 页表命中,开销={State.CurrentCost}。"; State.CurrentRound += 1; State.CurrentStep = TranslationStep.GenerateVA; } private void EnsureVirtualAddressInRange(ulong virtualAddress) { if (virtualAddress > _addressGenerator.MaxVirtualAddress) { throw new ArgumentOutOfRangeException(nameof(virtualAddress), "virtualAddress 超出 vaBits 可表示范围。"); } } private AddressGenerator CreateAddressGenerator() { return new AddressGenerator( _config.vaBits, _seed, _config.addressGenerationMode, _config.arrayLengthBytes, _config.arrayElementBytes, _config.arrayBaseAddress); } } }