CVA6はオープンソースのRISC-V CPUコアで、Chipyardにも組み込まれているインオーダパイプラインのCPUだ。
CPUの部分はソースコードを読むことができるが、複雑なLSUやキャッシュ周りはちゃんとVerilogの実装を読もうとすると時間がかかってしまう。ちょうど @ogawa_tter さんが CVA6 のデータキャッシュ構造を解説したドキュメントをTwitterで共有されていたので、読んでいくことした。
どうもこれはMeltdown/Spectre関連の話から始まったいくつかの研究の一環として公開されたドキュメントらしい。ざっくりと読んでみたがあまり詳細なパイプラインの動作について触れているわけではないっぽい。しかし有用であることは変わりないので読んでいく。
https://arxiv.org/ftp/arxiv/papers/2202/2202.03749.pdf
CVA6のキャッシュサブシステムは以下のようになっているようだ。
- Data cache memory : キャッシュ本体。データRAMとタグRAMから構成される。
- Miss Unit : キャッシュミスを起こしたラインをメインメモリから読み込むための機能を有する
- Write Buffer : ストア命令による書き込みを制御するための機能を有する
まず、CVA6のデータSRAMの構成自体は以下のようになっている。
- 256本のキャッシュラインから構成されている。
- 各ラインは8-wayセットアソシエイティブである。
- 各ラインは16バイトである。
- つまり、 のサイズがデフォルトとなっている。
アドレスに応じたラインの配置方法は以下のようになる。ちなみにキャッシュアクセスに使われるのは仮想アドレス化物理アドレス化は明言されていない。
- 16バイトのキャッシュラインなので、アドレスの下位4ビット
Addr[3: 0]
は無視される。この部分はオフセットとなる。 - 256エントリのキャッシュラインなので、オフセットからの上位8ビット
Addr[11: 4]
がエントリ選択に使われる。- バンクは定義されていないのか?
- 12ビットよりも上位はタグとして使用される。
このキャッシュには4つのモードが用意されている。
- ライトスルー (write through) : ストア命令によるデータ書き込み時、データをキャッシュとメインメモリに同時に書き込む。
ライトバック (write back) : ストア命令によるデータ書き込み時、データをキャッシュにのみ書き込む。書き込んだキャッシュラインは "dirty" とマークが付けられる。
ライトアロケート (write allocate) : キャッシュにデータを書き込んだのちにメインメモリに書き込む。
- 非ライトアロケート (No-write allocate) : データをメインメモリに書き込むのみで、キャッシュには書き込まない。キャッシュはリードミス時にのみ書き込まれる。
デフォルトのコンフィグレーションでは、ライトスルーかつ非ライトアロケートになっている。
dirtyなキャッシュラインの掃き出しは、キャッシュミスかつ当該エントリがすべて埋まっている場合に発生し、どのキャッシュエントリをEvictするかはLFSR (Linear-Feedback Shift Register) により実行される。 キャッシュブロックの掃き出しは、Miss Unit上で行われる。
データSRAMの構成は以下のようになっている。あれ、バンクが定義されているな? この説明を読むと、オフセット4ビットによるエントリ16バイト (=128ビット)でははく、さらに内部で2つに分割されて64ビットのエントリ×2バンクで構成されているらしい。