以前、たまたまSimplescalarを使用していました。実際、Simplescalarはすでに真のLRUアルゴリズムを実装しています。
次のコメントは、関数update_way_listを明確に説明しています。
/* insert BLK into the order way chain in SET at location WHERE */
static void
update_way_list(struct cache_set_t *set, /* set contained way chain */
struct cache_blk_t *blk, /* block to insert */
enum list_loc_t where) /* insert location */
引用したコードは、キャッシュにアクセスしたときの「キャッシュミス」の場合のものです。
switch (cp->policy) {
case LRU:
case FIFO:
repl = cp->sets[set].way_tail;
update_way_list(&cp->sets[set], repl, Head);
break;
}
ここでは、セットの最後の方法が犠牲者として選択され、セットのヘッドに移動されます。その後、置き換えられたブロックデータが書き戻され、被害者は新しいデータブロックに置き換えられます。
LRUとFIFOを区別する最も重要な部分は、「キャッシュヒット」の場合に由来します。
/* if LRU replacement and this is not the first element of list, reorder */
if (blk->way_prev && cp->policy == LRU)
{
/* move this block to head of the way (MRU) list */
update_way_list(&cp->sets[set], blk, Head);
}
したがって、セット内の方法は、年齢の降順に従います。セットの先頭はMRU(最も最近使用された)ブロックであり、末尾はLRUです。
これはまさに真のLRUアルゴリズムです。キャッシュヒットが発生すると、ヒットブロックは他の順序を維持しながらMRUウェイにプロモートされます。キャッシュミスがある場合、LRUブロックが犠牲者として選択され、新しいブロックがMRU方式で配置されます。以前の「キャッシュヒット」コードを削除すると、アクセス履歴は記録されず、セット内のウェイはアクセス順序に従っているため、FIFOの動作が提供されます。行を削除すると
update_way_list(&cp->sets[set], repl, Head);
前の「キャッシュミス」コードでは、新しいブロックがLRU方式で配置されるため、LIP(LRU挿入ポリシー)動作が提供されます。