ベクトルLSUのパイプラインは、大まかに以下のステージによって実行される。
- ex0: 命令キューからの命令発行。命令詳細デコード。アドレス計算のためのレジスタアクセス。
- ex1: ベクトル演算モードによるアドレス生成。TLBへのアクセスによる物理アドレスへの変換。同時にデータキャッシュへのアクセス。
- ex2: キャッシュヒットの場合はデータの整列。ミスの場合はリプレイキューへの格納。
- ex3: キャッシュヒットの場合はデータのベクトルレジスタ書き込みと命令実行終了。
かなりギリギリにステージを詰め込んでいる。
- ベクトルメモリアクセスのアドレス生成
まず、ベクトル演算モードによるアドレス生成は、Unit Stride、Strided、Indexedに応じてアドレスを計算している。 現在はUnit Strideのみにしか対応していないが、Unit Strideであったとしてもキャッシュの境界を跨ぐ場合は2つのリクエストに分割してアクセスする必要があるので、キャッシュラインを跨がない場合は0サイクル、跨ぐ場合は1サイクルが使用される。
- リプレイの対応
ベクトル命令は複数のメモリアクセス要素が時分割で実行される。どこかの要素においてキャッシュミスなどが発生すると、当然リプレイなどの処理が必要になるが、後続のアクセス要素の処理はどうするか。 今回は実装の簡単化のため、ある要素Nのハザードが発生しリプレイキューに格納されると、それ以降の同一命令の全ての要素もハザードが発生したものとし、同様にリプレイキューに入る。 つまり、命令は必ず古いアクセス要素の順に処理が完了し、最後の要素のアクセスが完了するすればそれが命令全体の実行終了を意味する。
これが、アクセス要素が順不同での処理完了を許した場合、どの要素が処理を終えたのか、全部の要素で処理が終えたのかどうかを示すテーブルが必要になり管理が煩雑になるので、このような処理にしている。
本来ならば、リプレイキューに入ったアクセス要素N以降のN+1...要素は、リプレイキューに入れずとも必ず再実行されるため、その場で消去してしまっても問題ないはずなのだが、現在はリプレイキューにそれらの要素の再生成の機能を持たせていないため、とりあえずすべての要素を格納するようにしている。これはもったいないので、いずれ改善する。
リプレイ・キューには、以下の情報を渡している。
valid
: アクセスValidcmt_id / grp_id
: 命令IDinst
: 命令の機械語自体。パイプライン中の詳細デコードに使用する。vlvtype
: VL/VTYPEの譲歩うcat / subcat
: 命令のカテゴリhazard_typ
: どのハザードで命令がリプレイキューに格納されたか。rd_regs
: レジスタ情報wr_reg / wr_old_reg
: 書き込みレジスタ情報wr_origin_rnid
: 命令の最も先頭のRNIDhazard_index
: ハザードの発生したインデックス。vec_step_index / vec_lmul_index
: 現在のベクトル・アクセス要素の位置paddr
: アクセス物理アドレス。これは無くても良いかも。haz_1st_req
: 命令中で最初に発生したハザード。これ以降は付随して格納されるアクセス要素。req_splitted
: 命令がアドレス生成時に分割されたかを示す。reg_offset
: 命令が分割された際に、レジスタ書き込みのオフセット位置を記録する。