This repository has been archived on 2026-04-18. You can view files and clone it, but cannot push or open issues or pull requests.
Virtual-Memory-Demo/Assets/Scripts/Simulation/TranslatorEngine.cs

294 lines
9.9 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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 可表示范围。");
}
}
}
}