Step 5 - 翻译引擎(单步状态机)

This commit is contained in:
2026-04-14 08:58:08 +08:00
parent 38aa8e9bf4
commit 61e0034800
7 changed files with 531 additions and 12 deletions
@@ -7,8 +7,12 @@ namespace VMdemo.Simulation
public class SimulationState
{
public int CurrentRound { get; set; }
public TranslationStep CurrentStep { get; set; }
public ulong CurrentVirtualAddress { get; set; }
public AddressParts CurrentAddressParts { get; set; }
public ulong CurrentPhysicalAddress { get; set; }
public ulong CurrentPfn { get; set; }
public bool HasCurrentPfn { get; set; }
public bool IsPageFault { get; set; }
public bool IsTlbHit { get; set; }
public bool IsPageTableHit { get; set; }
@@ -17,8 +21,12 @@ namespace VMdemo.Simulation
public void Reset()
{
CurrentRound = 0;
CurrentStep = TranslationStep.GenerateVA;
CurrentVirtualAddress = 0UL;
CurrentAddressParts = AddressParts.Empty;
CurrentPhysicalAddress = 0UL;
CurrentPfn = 0UL;
HasCurrentPfn = false;
IsPageFault = false;
IsTlbHit = false;
IsPageTableHit = false;
@@ -0,0 +1,293 @@
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();
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 EvictionInfo LastEviction => _lastEviction;
public void Reset()
{
State.Reset();
_lastEviction = EvictionInfo.None;
_hasPendingForcedVirtualAddress = false;
_pendingForcedVirtualAddress = 0UL;
_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.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 可表示范围。");
}
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 573321a5f8ef63248bc3d9baa95c450d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: