性能評価用に各命令のレイテンシを測りたいのだけれども、最終的な出力ではレイテンシが大きい順番に命令をソートして出力したい。
DPIを使用すれば上手く行きそうだがDPIを使うこと自体が面倒くさい。なんかSystemVerilogで良い機能無いかなーと探していたら、queue
にはsortの機能があるらしい。
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
のロードが遅い。なぜロードが遅いかというとそのロードに依存しているストア命令の影響で前へ進めない...といったいろんなハザード条件にぶつかっていた。
STQ内のストア命令で、パイプライン中のロード命令よりも古いものが存在しておりかつ物理アドレスが決定していない場合には、そのストア命令からのフォワードが発生する可能性があるため、ロード命令は前に進むことが出来ない。これはどうやって解決しようかな...