122 lines
3.2 KiB
C#
122 lines
3.2 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
|
|
namespace VMdemo.Simulation
|
|
{
|
|
public class TlbCache
|
|
{
|
|
private readonly Dictionary<ulong, LinkedListNode<TlbEntry>> _index;
|
|
private readonly LinkedList<TlbEntry> _lruList;
|
|
|
|
public TlbCache(int capacity)
|
|
{
|
|
if (capacity <= 0)
|
|
{
|
|
throw new ArgumentOutOfRangeException(nameof(capacity), "TLB 容量必须是正整数。");
|
|
}
|
|
|
|
Capacity = capacity;
|
|
_index = new Dictionary<ulong, LinkedListNode<TlbEntry>>(capacity);
|
|
_lruList = new LinkedList<TlbEntry>();
|
|
}
|
|
|
|
public int Capacity { get; }
|
|
public int Count => _index.Count;
|
|
public int HitCount { get; private set; }
|
|
public int MissCount { get; private set; }
|
|
|
|
public bool Lookup(ulong vpn, out ulong pfn)
|
|
{
|
|
return TryLookup(vpn, out pfn);
|
|
}
|
|
|
|
public bool TryLookup(ulong vpn, out ulong pfn)
|
|
{
|
|
if (_index.TryGetValue(vpn, out var node) && node.Value.IsValid)
|
|
{
|
|
MoveToMostRecent(node);
|
|
pfn = node.Value.Pfn;
|
|
HitCount++;
|
|
return true;
|
|
}
|
|
|
|
pfn = 0UL;
|
|
MissCount++;
|
|
return false;
|
|
}
|
|
|
|
public void InsertOrUpdate(ulong vpn, ulong pfn)
|
|
{
|
|
if (_index.TryGetValue(vpn, out var existingNode))
|
|
{
|
|
existingNode.Value = existingNode.Value.WithPfn(pfn);
|
|
MoveToMostRecent(existingNode);
|
|
return;
|
|
}
|
|
|
|
var newNode = new LinkedListNode<TlbEntry>(new TlbEntry(vpn, pfn));
|
|
_lruList.AddFirst(newNode);
|
|
_index[vpn] = newNode;
|
|
|
|
if (_index.Count > Capacity)
|
|
{
|
|
EvictLeastRecent();
|
|
}
|
|
}
|
|
|
|
public bool Remove(ulong vpn)
|
|
{
|
|
if (!_index.TryGetValue(vpn, out var node))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
_lruList.Remove(node);
|
|
_index.Remove(vpn);
|
|
return true;
|
|
}
|
|
|
|
public void Clear()
|
|
{
|
|
_lruList.Clear();
|
|
_index.Clear();
|
|
HitCount = 0;
|
|
MissCount = 0;
|
|
}
|
|
|
|
public IReadOnlyList<TlbEntry> GetEntriesMostRecentFirst()
|
|
{
|
|
var snapshot = new List<TlbEntry>(_index.Count);
|
|
for (var node = _lruList.First; node != null; node = node.Next)
|
|
{
|
|
snapshot.Add(node.Value);
|
|
}
|
|
|
|
return snapshot;
|
|
}
|
|
|
|
private void MoveToMostRecent(LinkedListNode<TlbEntry> node)
|
|
{
|
|
if (node.List != _lruList || _lruList.First == node)
|
|
{
|
|
return;
|
|
}
|
|
|
|
_lruList.Remove(node);
|
|
_lruList.AddFirst(node);
|
|
}
|
|
|
|
private void EvictLeastRecent()
|
|
{
|
|
var leastRecentNode = _lruList.Last;
|
|
if (leastRecentNode == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
_lruList.RemoveLast();
|
|
_index.Remove(leastRecentNode.Value.Vpn);
|
|
}
|
|
}
|
|
}
|