自作CPUはアウト・オブ・オーダ命令発行できるような構成にしているのだが、そのうちどれくらいが実際にアウト・オブ・オーダ発行できているのかをちゃんと計測できていない。
いい機会なので、命令スケジューラに統計情報を処理する機能を追加して、全体命令のうちどれくらいがアウト・オブ・オーダ発行されているのかを計測してみることにする。
必要なことは: 1. 全体のスケジューラのうち最も古い命令を把握する 2. 各スケジューラで発行された命令が、最も古い命令よりも若いかを判定し、該当すれば、それをアウト・オブ・オーダ発行ととらえる
まず、1. が結構面倒くさくて、分散スケジューラの方式をとっており、しかも各スケジューラの数は可変にしているのでちゃんと全部把握するためのSystemVerilogのコードを書くのが面倒くさい。
とりあえず、すべてのスケジューラからエントリ情報を取得して、そのうちのもっとも古いものを抜き出すようにかなり無理やりな実装にしている。
// --------------------------- // ALU Issue Unit Information // --------------------------- for (genvar alu_idx = 0; alu_idx < mycpu_conf_pkg::ALU_INST_NUM; alu_idx++) begin : alu_issue_loop /* verilator lint_off UNOPTFLAT */ mycpu_pkg::cmt_id_t w_alu_oldest_cmt_id[mycpu_conf_pkg::RV_ALU_ENTRY_SIZE]; mycpu_pkg::grp_id_t w_alu_oldest_grp_id[mycpu_conf_pkg::RV_ALU_ENTRY_SIZE]; for (genvar entry_idx = 0; entry_idx < mycpu_conf_pkg::RV_ALU_ENTRY_SIZE; entry_idx++) begin logic w_id0_is_older_than_id1; assign w_id0_is_older_than_id1 = mycpu_pkg::id0_is_older_than_id1 (entry_idx == 'h0 ? 'h0 : w_alu_oldest_cmt_id[entry_idx-1], entry_idx == 'h0 ? 'h0 : w_alu_oldest_grp_id[entry_idx-1], u_mycpu_subsystem_wrapper.u_mycpu_subsystem.u_tile.alu_loop[alu_idx].u_alu.u_mycpu_issue_unit.w_entry[entry_idx].cmt_id, u_mycpu_subsystem_wrapper.u_mycpu_subsystem.u_tile.alu_loop[alu_idx].u_alu.u_mycpu_issue_unit.w_entry[entry_idx].grp_id); assign {w_alu_oldest_cmt_id[entry_idx], w_alu_oldest_grp_id[entry_idx]} = u_mycpu_subsystem_wrapper.u_mycpu_subsystem.u_tile.alu_loop[alu_idx].u_alu.u_mycpu_issue_unit.w_entry[entry_idx].valid & w_id0_is_older_than_id1 ? {u_mycpu_subsystem_wrapper.u_mycpu_subsystem.u_tile.alu_loop[alu_idx].u_alu.u_mycpu_issue_unit.w_entry[entry_idx].cmt_id, u_mycpu_subsystem_wrapper.u_mycpu_subsystem.u_tile.alu_loop[alu_idx].u_alu.u_mycpu_issue_unit.w_entry[entry_idx].grp_id} : entry_idx == 'h0 ? 'h0 : {w_alu_oldest_cmt_id[entry_idx-1], w_alu_oldest_grp_id[entry_idx-1]}; end // for (genvar entry_idx = 0; entry_idx < u_mycpu_subsystem_wrapper.u_mycpu_subsystem.u_tile.alu_loop[alu_idx].u_alu.u_mycpu_issue_unit.ENTRY_SIZE; entry_idx++) always_ff @ (negedge w_clk, negedge w_mycpu_reset_n) begin issue_entries[ALU_ISSUE_BASE + alu_idx] <= {w_alu_oldest_cmt_id[mycpu_conf_pkg::RV_ALU_ENTRY_SIZE-1], w_alu_oldest_grp_id[mycpu_conf_pkg::RV_ALU_ENTRY_SIZE-1]}; end end // block: alu_issue_loop
さらに全体で最も古い命令を取り出す。この時SystemVerilogはmin()的なものが素直に使えるものがないので、結構苦労する。
scariv_pkg::cmt_id_t w_issue_oldest_cmt_id; scariv_pkg::grp_id_t w_issue_oldest_grp_id; int w_issue_oldest_id; always_comb begin w_issue_oldest_cmt_id = '0; w_issue_oldest_grp_id = '0; w_issue_oldest_id = 'h0; for (int i = 0; i < scariv_conf_pkg::ALU_INST_NUM + scariv_conf_pkg::LSU_INST_NUM + 1 + 1 + scariv_conf_pkg::FPU_INST_NUM; i++) begin if ((issue_entries[i] != 'h0) & (({w_issue_oldest_cmt_id, w_issue_oldest_grp_id} == 'h0) | ({w_issue_oldest_cmt_id, w_issue_oldest_grp_id}) > issue_entries[i])) begin {w_issue_oldest_cmt_id, w_issue_oldest_grp_id} = issue_entries[i]; w_issue_oldest_id = issue_entries[i]; end end end
次に2. だ。各ユニットについて、アウト・オブ・オーダ発行をカウントしていく。
// ---------------------- // Counting Up OoO issue // ---------------------- logic [ 9: 0] r_issue_num[ISSUE_UNIT_NUM-1: 0]; logic [ 9: 0] r_ooo_issue_num[ISSUE_UNIT_NUM-1: 0]; logic [ 9: 0] r_count; logic w_count_reset; always_ff @ (posedge w_clk, negedge w_scariv_reset_n) begin if (!w_scariv_reset_n) begin r_count <= 'h0; end else begin if (r_count == 1000-1) begin r_count <= 'h0; end else begin r_count <= r_count + 'h1; end end end assign w_count_reset = r_count == 1000-1; for (genvar alu_idx = 0; alu_idx < scariv_conf_pkg::ALU_INST_NUM; alu_idx++) begin : alu_issue_count_loop always_ff @ (negedge w_clk, negedge w_scariv_reset_n) begin if (!w_scariv_reset_n | w_count_reset) begin r_issue_num [ALU_ISSUE_BASE + alu_idx] <= 'h0; r_ooo_issue_num[ALU_ISSUE_BASE + alu_idx] <= 'h0; end else begin if (u_scariv_subsystem_wrapper.u_scariv_subsystem.u_tile.alu_loop[alu_idx].u_alu.w_rv0_issue.valid) begin r_issue_num [ALU_ISSUE_BASE + alu_idx] <= r_issue_num[ALU_ISSUE_BASE + alu_idx] + 'h1; if (scariv_pkg::id0_is_older_than_id1 (w_issue_oldest_cmt_id, w_issue_oldest_grp_id, u_scariv_subsystem_wrapper.u_scariv_subsystem.u_tile.alu_loop[alu_idx].u_alu.w_rv0_issue.cmt_id, u_scariv_subsystem_wrapper.u_scariv_subsystem.u_tile.alu_loop[alu_idx].u_alu.w_rv0_issue.grp_id)) begin r_ooo_issue_num[ALU_ISSUE_BASE + alu_idx] <= r_ooo_issue_num[ALU_ISSUE_BASE + alu_idx] + 'h1; end end end // else: !if(!w_scariv_reset_n | w_count_reset) end // always_ff @ (negedge w_clk, negedge w_scariv_reset_n) end
とりあえずこれでできたかな。ログを吐き出すようにしている。
alu[0] 91 / 212, alu[1] 48 / 120, lsu[0] 90 / 224, lsu[1] 41 / 82, bru 65 / 132, csu 0 / 999, fpu[0] 0 / 0, fpu[1] 0 / 0, alu[0] 96 / 264, alu[1] 39 / 136, lsu[0] 140 / 358, lsu[1] 37 / 71, bru 93 / 254, csu 0 / 999, fpu[0] 0 / 0, fpu[1] 0 / 0, alu[0] 120 / 295, alu[1] 41 / 153, lsu[0] 186 / 383, lsu[1] 44 / 90, bru 96 / 282, csu 0 / 999, fpu[0] 0 / 0, fpu[1] 0 / 0, alu[0] 87 / 245, alu[1] 100 / 165, lsu[0] 131 / 316, lsu[1] 41 / 113, bru 64 / 183, csu 0 / 999, fpu[0] 0 / 0, fpu[1] 0 / 0, alu[0] 101 / 266, alu[1] 53 / 163, lsu[0] 140 / 338, lsu[1] 16 / 44, bru 77 / 266, csu 0 / 999, fpu[0] 0 / 0, fpu[1] 0 / 0, alu[0] 131 / 299, alu[1] 96 / 194, lsu[0] 139 / 383, lsu[1] 40 / 87, bru 119 / 289, csu 0 / 999, fpu[0] 0 / 0, fpu[1] 0 / 0, alu[0] 194 / 437, alu[1] 145 / 295, lsu[0] 229 / 593, lsu[1] 75 / 117, bru 164 / 431, csu 0 / 999, fpu[0] 0 / 0, fpu[1] 0 / 0, alu[0] 189 / 473, alu[1] 162 / 322, lsu[0] 232 / 669, lsu[1] 41 / 138, bru 171 / 461, csu 0 / 999, fpu[0] 0 / 0, fpu[1] 0 / 0, alu[0] 184 / 469, alu[1] 153 / 315, lsu[0] 247 / 660, lsu[1] 51 / 138, bru 161 / 455, csu 0 / 999, fpu[0] 0 / 0, fpu[1] 0 / 0, alu[0] 210 / 457, alu[1] 160 / 318, lsu[0] 253 / 652, lsu[1] 96 / 134, bru 158 / 460, csu 0 / 999, fpu[0] 0 / 0, fpu[1] 0 / 0, alu[0] 218 / 472, alu[1] 151 / 325, lsu[0] 229 / 658, lsu[1] 91 / 121, bru 162 / 476, csu 0 / 999, fpu[0] 0 / 0, fpu[1] 0 / 0, alu[0] 201 / 472, alu[1] 159 / 320, lsu[0] 247 / 668, lsu[1] 59 / 139, bru 177 / 479, csu 0 / 999, fpu[0] 0 / 0, fpu[1] 0 / 0, alu[0] 185 / 472, alu[1] 150 / 315, lsu[0] 243 / 648, lsu[1] 49 / 140, bru 168 / 448, csu 0 / 999, fpu[0] 0 / 0, fpu[1] 0 / 0, alu[0] 211 / 471, alu[1] 146 / 321, lsu[0] 236 / 666, lsu[1] 89 / 132, bru 155 / 469, csu 0 / 999, fpu[0] 0 / 0, fpu[1] 0 / 0, alu[0] 216 / 465, alu[1] 148 / 322, lsu[0] 233 / 669, lsu[1] 97 / 140, bru 163 / 469, csu 0 / 999, fpu[0] 0 / 0, fpu[1] 0 / 0, alu[0] 201 / 471, alu[1] 164 / 319, lsu[0] 263 / 644, lsu[1] 54 / 124, bru 181 / 473, csu 0 / 999, fpu[0] 0 / 0, fpu[1] 0 / 0, alu[0] 182 / 480, alu[1] 163 / 329, lsu[0] 241 / 680, lsu[1] 52 / 138, bru 161 / 478, csu 0 / 999, fpu[0] 0 / 0, fpu[1] 0 / 0, alu[0] 217 / 475, alu[1] 150 / 319, lsu[0] 226 / 656, lsu[1] 96 / 141, bru 162 / 452, csu 0 / 999, fpu[0] 0 / 0, fpu[1] 0 / 0, alu[0] 210 / 471, alu[1] 145 / 321, lsu[0] 231 / 673, lsu[1] 98 / 136, bru 168 / 470, csu 0 / 999, fpu[0] 0 / 0, fpu[1] 0 / 0, alu[0] 203 / 474, alu[1] 169 / 326, lsu[0] 236 / 678, lsu[1] 46 / 132, bru 177 / 477, csu 0 / 999, fpu[0] 0 / 0, fpu[1] 0 / 0,
なんか結構な割合でアウト・オブ・オーダ発行できている気がするな。ただもうちょっと精査が必要かな。