Archived
Step 5 - 翻译引擎(单步状态机)
This commit is contained in:
@@ -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:
|
||||
Reference in New Issue
Block a user