この話の続き。RISC-V対応のCPUの実装にあたり、足回りのAXIをどのように実装するか。
今のところ1次キャッシュは備えていないので(いずれは追加しないといけないが)、足回りのAXIは、
- 命令アドレスリクエスト用チャネル (IF_MAR)
- 命令データリクエスト&リプライ(IF_MR)
のチャネルが非同期に動作することを考える。
このとき、命令フラッシュが発生した場合投機的にフェッチしているリクエストをどのように扱うかだが、基本的には、フェッチリクエストを出してしまったものはしようが無いので、このリクエストを全て回収して、本当に欲しいフラッシュ後のリクエストまでのFIFOは全て破棄、そして欲しいリクエストが来ると、そのデータをIDステージに送るという方法にした。
この場合、3種類のFIFO(というよりもリングバッファ)を用意した。
- MARリクエストバッファ (16entry, 4bit幅)
- MRリクエストバッファ (16entry, 1bit幅)
- キャンセルバッファ (16entry, 1bit幅)
MARリクエストバッファを4ビット保持しているのは、128bit(4word)のうち、ワードアラインを記憶しておくためだ。例えば、フェッチアドレスの先頭が0x128であれば、最後の4bitが8であるため、フェッチ自体は0x120をリクエスト、ただし有効なデータは0x008アラインからスタートさせなければならない。そのためのアライン情報を保持している。
- フェッチ開始アドレス
3 | 2 | 1 | 0 |
---|---|---|---|
0xc | 0x8 | 0x4 | 0x0 |
MRリクエストバッファは、その名の通りデータリプライが来た場合に、データを保持していることを記憶する。そしてフェッチラインがそのエントリまで到達すると、データをIDステージに渡すとともに、バッファの内容をクリアする。
キャンセルバッファは、命令フラッシュが来た場合に、リクエストが既に出ているが、リプライが帰ってきていないエントリに対して、このエントリを無効化することを意味する。 つまり、フラッシュ信号がアサートされた場合に、
- MARリクエストバッファのエントリが0では無い(つまり既にリクエストがAXIに対して送出されている)
- MRリクエストバッファのエントリが1では無い(つまりまだAXIからのデータリプライが返されていない)
このとき、キャンセルバッファの当該エントリを有効化する必要がある。
これと同時に、リクエストリングバッファのために、3つのエントリポインタを定義する。
- リクエスト先頭ポインタ (AXIリクエストを送出した最も先頭のポインタを記憶する)
- リクエスト最後尾ポインタ (AXIリクエストの中でデータが返ってきている最新のポインタを記憶する)
- 命令発行先頭ポインタ (リクエストバッファの中でデータをIDステージに渡していない最も古いデータのポインタを記憶する)