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 = new AddressGenerator(_config.vaBits, _seed); _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 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 = new AddressGenerator(_config.vaBits, _seed); _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; _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.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.CurrentStep = TranslationStep.ComposePA; return; } State.CurrentStep = TranslationStep.LookupPageTable; } private void ExecuteLookupPageTable() { if (_pageTable.TryGetPresentPfn( State.CurrentAddressParts.L1Index, State.CurrentAddressParts.L2Index, out var pfn)) { State.IsPageTableHit = true; State.CurrentPfn = pfn; State.HasCurrentPfn = true; _tlbCache.InsertOrUpdate(State.CurrentAddressParts.Vpn, pfn); State.CurrentStep = TranslationStep.ComposePA; return; } 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.CurrentStep = TranslationStep.ComposePA; } private void ExecuteComposePa() { if (!State.HasCurrentPfn) { throw new InvalidOperationException("ComposePA 阶段缺少 PFN,无法合成物理地址。"); } State.CurrentPhysicalAddress = (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.CurrentRound += 1; State.CurrentStep = TranslationStep.GenerateVA; } private void EnsureVirtualAddressInRange(ulong virtualAddress) { if (_config.vaBits < 64 && virtualAddress > _addressGenerator.MaxVirtualAddress) { throw new ArgumentOutOfRangeException(nameof(virtualAddress), "virtualAddress 超出 vaBits 可表示范围。"); } } } }