FPGA開発日記

カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages , English Version https://fpgadevdiary.hatenadiary.com/

Champsim の Hashed Perceptronの実装を読む (2. テーブルの初期化方法)

github.com

この辺の実装がどのようになっているのかを勉強したい。ChatGPTにお願いしながら、読み進めていくことにする。

msyksphinz.hatenablog.com


ghist_words:折り畳みシフトレジスタ(folded_shift_register)

using history_type = folded_shift_register<TABLE_INDEX_BITS>;
std::array<history_type, NTABLES> ghist_words = []()
{
    decltype(ghist_words) retval;
    std::transform(std::cbegin(history_lengths), std::cend(history_lengths), std::begin(retval), [](const auto len)
                   { return history_type{len}; });
    return retval;
}();

一般に「折り畳みシフトレジスタ(folded shift register)」は、長いグローバル履歴ビット列を、指定されたビット数(ここでは12ビット)に"折り畳む"という仕組みを持っている。 たとえば「232ビット分の履歴」をそのまま4096要素のインデックスに使用するのは大きすぎるため、履歴中のビットをシフト&XORなどで畳み込みながら12ビット分に縮めておき、value()を呼ぶとその折り畳まれた「12ビット分のビットベクタ」を返す、という動作をする。 TABLE_INDEX_BITSが12であるため、各history_typeインスタンスは「12ビットに折り畳んで保持できる履歴レジスタ」を表す。

ghist_wordsの初期化

std::array<history_type, NTABLES> ghist_wordsは、16個のhistory_typeを格納する。 右辺のラムダ([]() { … }())を使って、次のように初期化する:

  1. decltype(ghist_words) retval;でまず同じ型の空の配列を用意する。
  2. std::transform(std::cbegin(history_lengths), std::cend(history_lengths), std::begin(retval), [](const auto len) { return history_type{len}; });
  3. history_lengthsには16個の「履歴長」が並んでいる。
  4. このtransformで、要素len(例えば3, 4, 6, …, 232)を取り出し、history_type{len}という形でコンストラクタを呼び出して生成したものをretval[i]に順次格納する。
  5. つまり、ghist_words[i]history_type(history_lengths[i])で初期化される。
    • 例: ghist_words[0] = history_type{bits{0}} → バイアス用であるため履歴長0、
    • ghist_words[1] = history_type{bits{3}} → レジスタ長3ビット、
    • ghist_words[15] = history_type{bits{232}} → 232ビットを折り畳むレジスタ、という具合である。
  6. 最後にretvalを返してghist_wordsに代入する。

結果として、テーブルごとに異なる長さの「折り畳まれた履歴レジスタ」が16個用意される。 これを使用して、実際の分岐が起きるたびにグローバル履歴を更新し、value()を呼ぶとそれぞれの折り畳み済みビット列(12ビット分)を取り出せる仕組みとなっている。