FPGA開発日記

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

AXIのバスリクエスト中に取消をしたい場合にどうすれば良いのか

例えばの話、CPUでフェッチリクエストを出したとして、その間にフラッシュ信号を受信してしまい、それまでのフェッチを無かったことにしたい。 そんなときはどうすれば良いのか。基本的にAXIにリードリクエストを出してしまうとそれを止めることは出来ない(と思う)ので、アドレスチャネルに対してリクエストを出してしまったものを中止にすることは出来ない。 つまり全てのリクエストを出したアドレスに対してリードレスポンスは帰ってくるはずなので、これをどのようにして中止させるかが問題になる。

単純なメモリならば、アドレスチャネルで既に出したリクエストのテーブルに無効化ビットを立て、そのIDに対してリードレスポンスが帰ってきてもそれを破棄する、ということになる。 これが一般的な解決法だと思うが、もうちょっと具体的にブレークダウンしてみる。

例えばCPUのフェッチリクエストに対して、フェッチした命令を一時的に溜めるための命令バッファのようなものを考える。 命令バッファはリング上に構成されており、フェッチしてきたものを順番にIDステージに渡していく。

f:id:msyksphinz:20160808015254p:plain

次に命令バッファ0番には命令とデータが入っているが、命令バッファ1番はまだリクエストしたデータが帰ってきていない状態で、フラッシュ信号が入ったとする。 そうすると、前の命令もフラッシュされるが、次の命令が到着するのをとりあえず待ち、ID=11のデータがフェッチされるまで待つ。そのデータが帰ってくるのを確認してから、次のフェッチを出す。

f:id:msyksphinz:20160808015522p:plain

こうすると行儀が良いように見えるが、もし大量にフェッチリクエストを発行している場合、本当に欲しいフラッシュ後の命令フェッチの発行が遅れる。 少しでも本当に欲しいフェッチの発行を早くしたければ、フラッシュ後に新しいアドレスの命令フェッチリクエストを出してしまう (レスポンスは相変らず遅いだろうが)。

f:id:msyksphinz:20160808020345p:plain

ポインタの制御だが、まずアドレスチャネルとデータチャネルの先頭を制御するためにhead_idx, tail_idxのポインタをチェイスさせる。 さらに、どこまで発行したかを示すためにissue_idxを用意しておく。

f:id:msyksphinz:20160808020652p:plain

ここでフラッシュが発生した場合、まず既にデータを取得していたラインについてはデータを破棄する。 また、まだリクエストが到着していないラインについては、cancelledフラグを立て、この命令が来ても次のステージに転送しないようにする。

f:id:msyksphinz:20160808021144p:plain

このようにすれば、フラッシュ通知が発生した後にフェッチリクエストで余分なデータが帰ってきても、それを誤って後続のステージに渡すことはない。 ただし相変らずフラッシュ後の命令フェッチは遅い。これはどうにかならないものか。