Archived
finish(maybe...)
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using VMdemo.Core;
|
||||
|
||||
namespace VMdemo.Simulation
|
||||
{
|
||||
@@ -6,28 +7,74 @@ namespace VMdemo.Simulation
|
||||
{
|
||||
public const int DefaultSeed = 12345;
|
||||
|
||||
private readonly int _vaBits;
|
||||
private readonly ulong _vaMask;
|
||||
private readonly Random _random;
|
||||
private readonly byte[] _buffer = new byte[8];
|
||||
private readonly AddressGenerationMode _mode;
|
||||
private readonly ulong _arrayBaseAddress;
|
||||
private readonly ulong _arrayElementBytes;
|
||||
private readonly ulong _arrayElementCount;
|
||||
private ulong _nextArrayIndex;
|
||||
|
||||
public AddressGenerator(int vaBits, int? seed = null)
|
||||
public AddressGenerator(
|
||||
int vaBits,
|
||||
int? seed = null,
|
||||
AddressGenerationMode mode = AddressGenerationMode.RandomUniform,
|
||||
int arrayLengthBytes = 256,
|
||||
int arrayElementBytes = 4,
|
||||
int arrayBaseAddress = 0)
|
||||
{
|
||||
if (vaBits != 32 && vaBits != 48 && vaBits != 64)
|
||||
if (vaBits != 8 && vaBits != 16 && vaBits != 24)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(vaBits), "vaBits 仅支持 32、48、64。");
|
||||
throw new ArgumentOutOfRangeException(nameof(vaBits), "vaBits 仅支持 8、16、24。");
|
||||
}
|
||||
|
||||
_vaBits = vaBits;
|
||||
_vaMask = vaBits == 64 ? ulong.MaxValue : (1UL << vaBits) - 1UL;
|
||||
_vaMask = (1UL << vaBits) - 1UL;
|
||||
_random = new Random(seed ?? DefaultSeed);
|
||||
_mode = mode;
|
||||
|
||||
if (arrayLengthBytes <= 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(arrayLengthBytes), "arrayLengthBytes 必须是正整数。");
|
||||
}
|
||||
|
||||
if (arrayElementBytes <= 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(arrayElementBytes), "arrayElementBytes 必须是正整数。");
|
||||
}
|
||||
|
||||
if (arrayBaseAddress < 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(arrayBaseAddress), "arrayBaseAddress 不能为负数。");
|
||||
}
|
||||
|
||||
if (mode == AddressGenerationMode.SequentialArrayLoop && arrayLengthBytes < arrayElementBytes)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(
|
||||
nameof(arrayLengthBytes),
|
||||
"SequentialArrayLoop 模式下 arrayLengthBytes 必须 >= arrayElementBytes。");
|
||||
}
|
||||
|
||||
_arrayBaseAddress = (ulong)arrayBaseAddress;
|
||||
_arrayElementBytes = (ulong)arrayElementBytes;
|
||||
_arrayElementCount = Math.Max(1UL, (ulong)arrayLengthBytes / _arrayElementBytes);
|
||||
|
||||
var maxGenerated = _arrayBaseAddress + (_arrayElementCount - 1UL) * _arrayElementBytes;
|
||||
if (maxGenerated > _vaMask)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(
|
||||
nameof(arrayLengthBytes),
|
||||
$"数组访问地址超出 vaBits 范围。maxGenerated={maxGenerated}, maxVA={_vaMask}");
|
||||
}
|
||||
}
|
||||
|
||||
public ulong MaxVirtualAddress => _vaMask;
|
||||
|
||||
public ulong NextVirtualAddress()
|
||||
{
|
||||
return NextRawUlong() & _vaMask;
|
||||
return _mode == AddressGenerationMode.SequentialArrayLoop
|
||||
? NextArrayLoopAddress()
|
||||
: (NextRawUlong() & _vaMask);
|
||||
}
|
||||
|
||||
private ulong NextRawUlong()
|
||||
@@ -35,5 +82,12 @@ namespace VMdemo.Simulation
|
||||
_random.NextBytes(_buffer);
|
||||
return BitConverter.ToUInt64(_buffer, 0);
|
||||
}
|
||||
|
||||
private ulong NextArrayLoopAddress()
|
||||
{
|
||||
var address = _arrayBaseAddress + _nextArrayIndex * _arrayElementBytes;
|
||||
_nextArrayIndex = (_nextArrayIndex + 1UL) % _arrayElementCount;
|
||||
return address;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ namespace VMdemo.Simulation
|
||||
public bool IsTlbHit { get; set; }
|
||||
public bool IsPageTableHit { get; set; }
|
||||
public int CurrentCost { get; set; }
|
||||
public string LastDecisionReason { get; set; }
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
@@ -31,6 +32,7 @@ namespace VMdemo.Simulation
|
||||
IsTlbHit = false;
|
||||
IsPageTableHit = false;
|
||||
CurrentCost = 0;
|
||||
LastDecisionReason = string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ namespace VMdemo.Simulation
|
||||
L1Bits = l1Bits;
|
||||
L2Bits = l2Bits;
|
||||
|
||||
_addressGenerator = new AddressGenerator(_config.vaBits, _seed);
|
||||
_addressGenerator = CreateAddressGenerator();
|
||||
_tlbCache = new TlbCache(_config.tlbEntries);
|
||||
_pageTable = new TwoLevelPageTable(L1Bits, L2Bits);
|
||||
_physicalMemoryManager = new PhysicalMemoryManager(_derivedConfig.FrameCount);
|
||||
@@ -91,6 +91,10 @@ namespace VMdemo.Simulation
|
||||
|
||||
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; }
|
||||
@@ -109,7 +113,7 @@ namespace VMdemo.Simulation
|
||||
_pendingForcedVirtualAddress = 0UL;
|
||||
Stats.Reset();
|
||||
|
||||
_addressGenerator = new AddressGenerator(_config.vaBits, _seed);
|
||||
_addressGenerator = CreateAddressGenerator();
|
||||
_tlbCache = new TlbCache(_config.tlbEntries);
|
||||
_pageTable = new TwoLevelPageTable(L1Bits, L2Bits);
|
||||
_physicalMemoryManager = new PhysicalMemoryManager(_derivedConfig.FrameCount);
|
||||
@@ -190,6 +194,7 @@ namespace VMdemo.Simulation
|
||||
State.CurrentPhysicalAddress = 0UL;
|
||||
State.CurrentPfn = 0UL;
|
||||
State.HasCurrentPfn = false;
|
||||
State.LastDecisionReason = "已生成本轮虚拟地址,准备进行地址拆分。";
|
||||
_lastEviction = EvictionInfo.None;
|
||||
|
||||
if (_hasPendingForcedVirtualAddress)
|
||||
@@ -212,6 +217,7 @@ namespace VMdemo.Simulation
|
||||
State.CurrentVirtualAddress,
|
||||
_config.vaBits,
|
||||
_derivedConfig.OffsetBits);
|
||||
State.LastDecisionReason = "已拆分 VA 为 VPN/Offset,并从 VPN 拆分出 L1/L2 索引。";
|
||||
|
||||
State.CurrentStep = TranslationStep.LookupTLB;
|
||||
}
|
||||
@@ -223,28 +229,42 @@ namespace VMdemo.Simulation
|
||||
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()
|
||||
{
|
||||
if (_pageTable.TryGetPresentPfn(
|
||||
State.CurrentAddressParts.L1Index,
|
||||
State.CurrentAddressParts.L2Index,
|
||||
out var pfn))
|
||||
var probe = _pageTable.Probe(State.CurrentAddressParts.L1Index, State.CurrentAddressParts.L2Index);
|
||||
if (probe.Status == PageTableProbeStatus.PresentEntry)
|
||||
{
|
||||
State.IsPageTableHit = true;
|
||||
State.CurrentPfn = pfn;
|
||||
State.CurrentPfn = probe.Entry.Pfn;
|
||||
State.HasCurrentPfn = true;
|
||||
_tlbCache.InsertOrUpdate(State.CurrentAddressParts.Vpn, pfn);
|
||||
_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;
|
||||
}
|
||||
|
||||
@@ -263,6 +283,9 @@ namespace VMdemo.Simulation
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -275,6 +298,8 @@ namespace VMdemo.Simulation
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -291,6 +316,11 @@ namespace VMdemo.Simulation
|
||||
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;
|
||||
@@ -298,10 +328,21 @@ namespace VMdemo.Simulation
|
||||
|
||||
private void EnsureVirtualAddressInRange(ulong virtualAddress)
|
||||
{
|
||||
if (_config.vaBits < 64 && virtualAddress > _addressGenerator.MaxVirtualAddress)
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,28 @@ using System.Collections.Generic;
|
||||
|
||||
namespace VMdemo.Simulation
|
||||
{
|
||||
public enum PageTableProbeStatus
|
||||
{
|
||||
MissingL1Table = 0,
|
||||
MissingL2Entry = 1,
|
||||
NotPresentEntry = 2,
|
||||
PresentEntry = 3
|
||||
}
|
||||
|
||||
public readonly struct PageTableProbeResult
|
||||
{
|
||||
public PageTableProbeResult(PageTableProbeStatus status, bool hasEntry, PageTableEntry entry)
|
||||
{
|
||||
Status = status;
|
||||
HasEntry = hasEntry;
|
||||
Entry = entry;
|
||||
}
|
||||
|
||||
public PageTableProbeStatus Status { get; }
|
||||
public bool HasEntry { get; }
|
||||
public PageTableEntry Entry { get; }
|
||||
}
|
||||
|
||||
public class TwoLevelPageTable
|
||||
{
|
||||
private readonly Dictionary<ulong, Dictionary<ulong, PageTableEntry>> _table;
|
||||
@@ -73,6 +95,40 @@ namespace VMdemo.Simulation
|
||||
return false;
|
||||
}
|
||||
|
||||
public PageTableProbeResult Probe(ulong l1Index, ulong l2Index)
|
||||
{
|
||||
ValidateIndices(l1Index, l2Index);
|
||||
|
||||
if (!_table.TryGetValue(l1Index, out var l2Table))
|
||||
{
|
||||
return new PageTableProbeResult(
|
||||
PageTableProbeStatus.MissingL1Table,
|
||||
hasEntry: false,
|
||||
entry: PageTableEntry.NotPresent);
|
||||
}
|
||||
|
||||
if (!l2Table.TryGetValue(l2Index, out var entry))
|
||||
{
|
||||
return new PageTableProbeResult(
|
||||
PageTableProbeStatus.MissingL2Entry,
|
||||
hasEntry: false,
|
||||
entry: PageTableEntry.NotPresent);
|
||||
}
|
||||
|
||||
if (!entry.Present)
|
||||
{
|
||||
return new PageTableProbeResult(
|
||||
PageTableProbeStatus.NotPresentEntry,
|
||||
hasEntry: true,
|
||||
entry: entry);
|
||||
}
|
||||
|
||||
return new PageTableProbeResult(
|
||||
PageTableProbeStatus.PresentEntry,
|
||||
hasEntry: true,
|
||||
entry: entry);
|
||||
}
|
||||
|
||||
public void SetPresent(ulong l1Index, ulong l2Index, ulong pfn, bool dirty = false)
|
||||
{
|
||||
ValidateIndices(l1Index, l2Index);
|
||||
|
||||
Reference in New Issue
Block a user