FPGA開発日記

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

SystemVerilogでのqueue arrayにおけるsortの勉強 (と、性能評価用のレイテンシ測定機能実装)

性能評価用に各命令のレイテンシを測りたいのだけれども、最終的な出力ではレイテンシが大きい順番に命令をソートして出力したい。 DPIを使用すれば上手く行きそうだがDPIを使うこと自体が面倒くさい。なんかSystemVerilogで良い機能無いかなーと探していたら、queueにはsortの機能があるらしい。

www.chipverify.com

sort自体はまあ考えられなくもないが、with演算子を使ってソーティングの対象となる要素を選択できるらしい。すごい。

これはSystemVerilogのstructにも使えるのだろうか?ちょっとやってみる。Verilatorでは動くかな?

typedef struct packed {
logic [31: 0]        lifetime;
logic [CMT_ID_W-1:0] cmt_id;
logic [DISP_SIZE-1:0] grp_id;
logic [riscv_pkg::VADDR_W-1:0] pc_addr;
logic [31: 0]                  inst;
logic [31: 0]                  cmt_time;
} lifetime_t;

lifetime_t life_array[$];

always_ff @ (negedge i_clk, negedge i_reset_n) begin
  if (i_reset_n) begin
    if (o_commit.commit) begin
      for(int d_idx = 0; d_idx < msrh_conf_pkg::DISP_SIZE; d_idx++) begin
        if (o_commit.grp_id[d_idx] & !o_commit.all_dead) begin
          lifetime_t new_life;
          new_life.lifetime = w_entries[w_out_cmt_entry_id].lifetime[d_idx];
          new_life.cmt_id   = o_commit.cmt_id;
          new_life.grp_id   = 1 << d_idx;
          new_life.pc_addr  = w_entries[w_out_cmt_entry_id].inst[d_idx].pc_addr;
          new_life.inst     = w_entries[w_out_cmt_entry_id].inst[d_idx].inst;
          new_life.cmt_time = $time;

          life_array.push_back(new_life);
        end // if (o_commit.grp_id[d_idx] & !o_commit.all_dead)
      end // for (int d_idx = 0; d_idx < msrh_conf_pkg::DISP_SIZE; d++)

      life_array.rsort(item) with (item.lifetime);
      // while (life_array.size() > 100) begin
      //   life_array.pop_back();
      // end
    end // if (o_commit.commit)
  end // else: !if(!i_reset_n)
end // always_ff @ (negedge i_clk, negedge i_reset_n)

コンパイルエラーが起きた。手元にVCSが無いので分からないが、文法的には合っているはず?

%Error: ../src/../src/msrh_rob.sv:495:41: Can't find definition of variable: 'lifetime'
                                        : ... Suggested alternative: 'lifetime_t'
  495 |       life_array.rsort(item) with (item.lifetime);
      |                                         ^~~~~~~~
%Error: Exiting due to 1 error(s)

ついでに言うとコメントアウトしているpop_back()もダメだった。結構いろいろ制約があるなあ。 という訳で、lifetime変数をキーにしてソーティングして欲しいので、lifetime変数を一番上にしてwith無しでソートしたらできるかな?と思ってやってみたら出来た。

最終的に以下のような出力が得られる。ストア命令のレイテンシが非常に長い。

        53,     768414, (32, 8), PC=00800021a8, sd      ra, 24(sp)
        53,     743786, (32, 8), PC=00800021a8, sd      ra, 24(sp)
        53,     719158, (32, 8), PC=00800021a8, sd      ra, 24(sp)
        53,     694526, (32, 8), PC=00800021a8, sd      ra, 24(sp)
        53,     669898, (32, 8), PC=00800021a8, sd      ra, 24(sp)
        53,     645266, (32, 8), PC=00800021a8, sd      ra, 24(sp)
        53,     620638, (32, 8), PC=00800021a8, sd      ra, 24(sp)
        53,     596010, (32, 8), PC=00800021a8, sd      ra, 24(sp)
        53,     571382, (32, 8), PC=00800021a8, sd      ra, 24(sp)
        53,     546754, (32, 8), PC=00800021a8, sd      ra, 24(sp)
        53,     522114, (32, 8), PC=00800021a8, sd      ra, 24(sp)
        53,     497486, (32, 8), PC=00800021a8, sd      ra, 24(sp)
        53,     472854, (32, 8), PC=00800021a8, sd      ra, 24(sp)
        53,     448226, (32, 8), PC=00800021a8, sd      ra, 24(sp)
        53,     423594, (32, 8), PC=00800021a8, sd      ra, 24(sp)
        53,     398966, (32, 8), PC=00800021a8, sd      ra, 24(sp)
        53,     374338, (32, 8), PC=00800021a8, sd      ra, 24(sp)
        53,     349710, (32, 8), PC=00800021a8, sd      ra, 24(sp)
        53,     325082, (32, 8), PC=00800021a8, sd      ra, 24(sp)
        53,     300450, (32, 8), PC=00800021a8, sd      ra, 24(sp)
        53,     275822, (32, 8), PC=00800021a8, sd      ra, 24(sp)
        53,     251190, (32, 8), PC=00800021a8, sd      ra, 24(sp)
        53,     226562, (32, 8), PC=00800021a8, sd      ra, 24(sp)
        53,     201934, (32, 8), PC=00800021a8, sd      ra, 24(sp)

命令を追いかけていくと、これはオペランドとなるspのロードが遅い。なぜロードが遅いかというとそのロードに依存しているストア命令の影響で前へ進めない...といったいろんなハザード条件にぶつかっていた。

f:id:msyksphinz:20211109001133p:plain

STQ内のストア命令で、パイプライン中のロード命令よりも古いものが存在しておりかつ物理アドレスが決定していない場合には、そのストア命令からのフォワードが発生する可能性があるため、ロード命令は前に進むことが出来ない。これはどうやって解決しようかな...