FPGA開発日記

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

自作CPUのベクトルLSUパイプラインのまとめ(1. LSUパイプラインの概要)

ベクトルLSUのパイプラインは、大まかに以下のステージによって実行される。

  • ex0: 命令キューからの命令発行。命令詳細デコード。アドレス計算のためのレジスタアクセス。
  • ex1: ベクトル演算モードによるアドレス生成。TLBへのアクセスによる物理アドレスへの変換。同時にデータキャッシュへのアクセス。
  • ex2: キャッシュヒットの場合はデータの整列。ミスの場合はリプレイキューへの格納。
  • ex3: キャッシュヒットの場合はデータのベクトルレジスタ書き込みと命令実行終了。

かなりギリギリにステージを詰め込んでいる。

  • ベクトルメモリアクセスのアドレス生成

まず、ベクトル演算モードによるアドレス生成は、Unit Stride、Strided、Indexedに応じてアドレスを計算している。 現在はUnit Strideのみにしか対応していないが、Unit Strideであったとしてもキャッシュの境界を跨ぐ場合は2つのリクエストに分割してアクセスする必要があるので、キャッシュラインを跨がない場合は0サイクル、跨ぐ場合は1サイクルが使用される。

  • リプレイの対応

ベクトル命令は複数のメモリアクセス要素が時分割で実行される。どこかの要素においてキャッシュミスなどが発生すると、当然リプレイなどの処理が必要になるが、後続のアクセス要素の処理はどうするか。 今回は実装の簡単化のため、ある要素Nのハザードが発生しリプレイキューに格納されると、それ以降の同一命令の全ての要素もハザードが発生したものとし、同様にリプレイキューに入る。 つまり、命令は必ず古いアクセス要素の順に処理が完了し、最後の要素のアクセスが完了するすればそれが命令全体の実行終了を意味する。

これが、アクセス要素が順不同での処理完了を許した場合、どの要素が処理を終えたのか、全部の要素で処理が終えたのかどうかを示すテーブルが必要になり管理が煩雑になるので、このような処理にしている。

本来ならば、リプレイキューに入ったアクセス要素N以降のN+1...要素は、リプレイキューに入れずとも必ず再実行されるため、その場で消去してしまっても問題ないはずなのだが、現在はリプレイキューにそれらの要素の再生成の機能を持たせていないため、とりあえずすべての要素を格納するようにしている。これはもったいないので、いずれ改善する。

リプレイ・キューには、以下の情報を渡している。

  • valid : アクセスValid
  • cmt_id / grp_id : 命令ID
  • inst : 命令の機械語自体。パイプライン中の詳細デコードに使用する。
  • vlvtype : VL/VTYPEの譲歩う
  • cat / subcat : 命令のカテゴリ
  • hazard_typ : どのハザードで命令がリプレイキューに格納されたか。
  • rd_regs : レジスタ情報
  • wr_reg / wr_old_reg : 書き込みレジスタ情報
  • wr_origin_rnid : 命令の最も先頭のRNID
  • hazard_index : ハザードの発生したインデックス。
  • vec_step_index / vec_lmul_index : 現在のベクトル・アクセス要素の位置
  • paddr : アクセス物理アドレス。これは無くても良いかも。
  • haz_1st_req : 命令中で最初に発生したハザード。これ以降は付随して格納されるアクセス要素。
  • req_splitted : 命令がアドレス生成時に分割されたかを示す。
  • reg_offset : 命令が分割された際に、レジスタ書き込みのオフセット位置を記録する。