BOOMと自作CPUの合成結果を比較して、ボトルネックになっている部分を調査したい。まずは面積から。
まず気になったのは、LDQとSTQのサイズが異常にでかい。LDQに比べてSTQの大きさが異常に大きいのも気になるので、余計なFFが入っている可能性を調査する。
とりあえずSTQの不要なエントリを削除しても意味がなかった。そういう最適化は最初からやられているらしい。
次に、Verilogファイルを生成して具体的にどんなFFが使われているのかを見てみる。
write_verilog -cell scariv_stq_entry stq_entry.sv
(* STRUCTURAL_NETLIST = "yes" *) module scariv_stq_entry (\r_entry_reg[is_rmw]_0 , \w_stq_entries[0][except_valid] , \w_stq_entries[0][inst][rd_regs][1][ready] , \r_entry_reg[inst][rd_regs][0][predict_ready]_0 , \r_entry_reg[inst][rd_regs][0][ready]_0 , \r_entry_reg[inst][rd_regs][1][typ]_0 , \r_entry_reg[inst][rd_regs][0][typ]_0 , \w_stq_entries[0][is_amo] , \w_stq_entries[0][vaddr] , \r_entry_reg[vaddr][6]_0 , \r_entry_reg[vaddr][7]_0 , \r_entry_reg[vaddr][8]_0 , \r_entry_reg[vaddr][9]_0 , ...
たぶんFDxxというセルがFlip Flopに相当しているものと思う。
grep FD stq_entry.sv | wc -l 826
とりあえずセル名をリストアップする。
$ grep -A2 FD stq_entry.sv | grep -v FD | grep -v INIT | grep -v -- -- ... \stq_snoop_if\.resp_s1_data_reg[85] \stq_snoop_if\.resp_s1_data_reg[86] \stq_snoop_if\.resp_s1_data_reg[87] \stq_snoop_if\.resp_s1_data_reg[88] \stq_snoop_if\.resp_s1_data_reg[89] \stq_snoop_if\.resp_s1_data_reg[8] \stq_snoop_if\.resp_s1_data_reg[90] \stq_snoop_if\.resp_s1_data_reg[91] \stq_snoop_if\.resp_s1_data_reg[92] \stq_snoop_if\.resp_s1_data_reg[93] \stq_snoop_if\.resp_s1_data_reg[94] \stq_snoop_if\.resp_s1_data_reg[95] \stq_snoop_if\.resp_s1_data_reg[96] \stq_snoop_if\.resp_s1_data_reg[97] \stq_snoop_if\.resp_s1_data_reg[98] \stq_snoop_if\.resp_s1_data_reg[99] \stq_snoop_if\.resp_s1_data_reg[9]
さらに解析する。どの種類のレジスタがどれだけ定義されているかが示される。
$ grep -A2 FD stq_entry.sv | grep -v FD | grep -v INIT | grep -v -- -- | sed 's/[0-9]//g' | sort | uniq -c 4 \FSM_sequential_r_entry_reg[state][] 3 \FSM_sequential_r_entry[state][]_i___ 1 (.I(\FSM_sequential_r_entry[state][]_i____n_ ), 1 i____i_ 1 (.I(Q[]), 1 (.I(\r_entry_reg[cmt_id][]_ ), 1 (.I(\r_entry_reg[state] ), 2 (.I(\r_entry_reg[vaddr][]_rep_ ), 1 (.I(\r_entry_reg[vaddr][]_rep___n_ ), 1 (.I(\stq_snoop_if\.resp_s_data[]_i__n_ ), 1 (.I(\w_stq_entries[][size] []), 2 (.I(\w_stq_entries[][vaddr] []), 5 \r_entry_reg[another_flush_cmt_id][] 5 \r_entry_reg[another_flush_grp_id][] 1 \r_entry_reg[another_flush_valid] 16 \r_entry_reg[br_mask][] 6 \r_entry_reg[cmt_id][] 4 \r_entry_reg[except_type][] 1 \r_entry_reg[except_valid] 5 \r_entry_reg[grp_id][] 1 \r_entry_reg[inst][oldest_valid] 1 \r_entry_reg[inst][rd_regs][][predict_ready] 2 \r_entry_reg[inst][rd_regs][][ready] 16 \r_entry_reg[inst][rd_regs][][rnid][] 2 \r_entry_reg[inst][rd_regs][][typ] 1 \r_entry_reg[inst][rd_regs][][valid] 1 \r_entry_reg[is_amo] 1 \r_entry_reg[is_committed] 1 \r_entry_reg[is_lr] 1 \r_entry_reg[is_rmw] 1 \r_entry_reg[is_rs_get] 1 \r_entry_reg[is_sc] 1 \r_entry_reg[is_uc] 1 \r_entry_reg[is_valid] 8 \r_entry_reg[missu_haz_index_oh][] 1 \r_entry_reg[oldest_ready] 27 \r_entry_reg[paddr][] 1 \r_entry_reg[paddr_valid] 5 \r_entry_reg[rmwop][] 64 \r_entry_reg[rs_data][] 1 \r_entry_reg[sc_success] 3 \r_entry_reg[size][] 39 \r_entry_reg[vaddr][] 5 \r_entry_reg[vaddr][]_rep 7 \r_entry_reg[vaddr][]_rep__ 6 \stq_snoop_if\.resp_s_be[]_i___ 64 \stq_snoop_if\.resp_s_be_reg[] 1 \stq_snoop_if\.resp_s_data[]_i___ 512 \stq_snoop_if\.resp_s_data_reg[]
なるほど、Snoopインタフェースが冗長かな?調べてみるとSTQの中にレスポンスのための大きなFFが入っていた。これは除去できる。
結果、FFの数はかなり減らしたが、LUTは相変わらず大きいな!