From 48239128c368abeddf1dfd1912854b6f6284dfce Mon Sep 17 00:00:00 2001
From: Alban Gruin <alban.gruin@irit.fr>
Date: Wed, 9 Feb 2022 16:07:24 +0100
Subject: [PATCH] scoreboard: size and timing improvements

Signed-off-by: Alban Gruin <alban.gruin@irit.fr>
---
 src/scoreboard.sv | 184 +++++++++++++++++-----------------------------
 1 file changed, 66 insertions(+), 118 deletions(-)

diff --git a/src/scoreboard.sv b/src/scoreboard.sv
index 92254af9..a53aacbb 100644
--- a/src/scoreboard.sv
+++ b/src/scoreboard.sv
@@ -239,70 +239,45 @@ module scoreboard #(
   // RD clobber process
   // -------------------
   // rd_clobber output: output currently clobbered destination registers
-  logic [2**ariane_pkg::REG_ADDR_SIZE-1:0][NR_ENTRIES:0]              gpr_clobber_vld;
-  logic [2**ariane_pkg::REG_ADDR_SIZE-1:0][NR_ENTRIES:0]              fpr_clobber_vld;
-  ariane_pkg::fu_t [NR_ENTRIES:0]                                     clobber_fu;
-
-  always_comb begin : clobber_assign
-    gpr_clobber_vld  = '0;
-    fpr_clobber_vld  = '0;
-
-    // default (highest entry hast lowest prio in arbiter tree below)
-    clobber_fu[NR_ENTRIES] = ariane_pkg::NONE;
-    for (int unsigned i = 0; i < 2**ariane_pkg::REG_ADDR_SIZE; i++) begin
-      gpr_clobber_vld[i][NR_ENTRIES] = 1'b1;
-      fpr_clobber_vld[i][NR_ENTRIES] = 1'b1;
-    end
-
-    // check for all valid entries and set the clobber accordingly
-    for (int unsigned i = 0; i < NR_ENTRIES; i++) begin
-      gpr_clobber_vld[mem_q[i].sbe.rd][i] = ~mem_q[i].pending & mem_q[i].issued & ~mem_q[i].is_rd_fpr_flag;
-      fpr_clobber_vld[mem_q[i].sbe.rd][i] = ~mem_q[i].pending & mem_q[i].issued & mem_q[i].is_rd_fpr_flag;
-      clobber_fu[i]                       = mem_q[i].sbe.fu;
+  logic [2**ariane_pkg::REG_ADDR_SIZE-1:0][NR_ENTRIES-1:0]              gpr_clobber_vld;
+  logic [2**ariane_pkg::REG_ADDR_SIZE-1:0][NR_ENTRIES-1:0]              fpr_clobber_vld;
+  ariane_pkg::fu_t [NR_ENTRIES-1:0]                                     clobber_fu;
+
+  for (genvar i = 0; i < 2**ariane_pkg::REG_ADDR_SIZE; i++) begin
+    for (genvar j = 0; j < NR_ENTRIES; j++) begin
+      assign gpr_clobber_vld[i][j] = mem_q[j].sbe.rd == i & ~mem_q[j].pending & mem_q[j].issued & ~mem_q[j].is_rd_fpr_flag & i != 0;
+      assign fpr_clobber_vld[i][j] = mem_q[j].sbe.rd == i & ~mem_q[j].pending & mem_q[j].issued & mem_q[j].is_rd_fpr_flag;
     end
+  end
 
-    // GPR[0] is always free
-    gpr_clobber_vld[0] = '0;
+  for (genvar k = 0; k < NR_ENTRIES; k++) begin
+    assign clobber_fu[k] = mem_q[k].sbe.fu;
   end
 
-  for (genvar k = 0; k < 2**ariane_pkg::REG_ADDR_SIZE; k++) begin : gen_sel_clobbers
-    // get fu that is going to clobber this register (there should be only one)
-    rr_arb_tree #(
-      .NumIn(NR_ENTRIES+1),
-      .DataType(ariane_pkg::fu_t),
-      .ExtPrio(1'b1),
-      .AxiVldRdy(1'b1)
-    ) i_sel_gpr_clobbers (
-      .clk_i   ( clk_i               ),
-      .rst_ni  ( rst_ni              ),
-      .flush_i ( 1'b0                ),
-      .rr_i    ( '0                  ),
-      .req_i   ( gpr_clobber_vld[k]  ),
-      .gnt_o   (                     ),
-      .data_i  ( clobber_fu          ),
-      .gnt_i   ( 1'b1                ),
-      .req_o   (                     ),
-      .data_o  ( rd_clobber_gpr_o[k] ),
-      .idx_o   (                     )
+  for (genvar k = 0; k < 2**ariane_pkg::REG_ADDR_SIZE; k++) begin
+    logic [$clog2(NR_ENTRIES)-1:0] gpr_clobber_idx, fpr_clobber_idx;
+    logic gpr_no_clobber, fpr_no_clobber;
+
+    lzc #(
+      .WIDTH ( NR_ENTRIES ),
+      .MODE  ( 0          )
+    ) lzc_gpr_clobbers (
+      .in_i    ( gpr_clobber_vld[k] ),
+      .cnt_o   ( gpr_clobber_idx    ),
+      .empty_o ( gpr_no_clobber     )
     );
-    rr_arb_tree #(
-      .NumIn(NR_ENTRIES+1),
-      .DataType(ariane_pkg::fu_t),
-      .ExtPrio(1'b1),
-      .AxiVldRdy(1'b1)
-    ) i_sel_fpr_clobbers (
-      .clk_i   ( clk_i               ),
-      .rst_ni  ( rst_ni              ),
-      .flush_i ( 1'b0                ),
-      .rr_i    ( '0                  ),
-      .req_i   ( fpr_clobber_vld[k]  ),
-      .gnt_o   (                     ),
-      .data_i  ( clobber_fu          ),
-      .gnt_i   ( 1'b1                ),
-      .req_o   (                     ),
-      .data_o  ( rd_clobber_fpr_o[k] ),
-      .idx_o   (                     )
+
+    lzc #(
+      .WIDTH ( NR_ENTRIES ),
+      .MODE  ( 0          )
+    ) lzc_fpr_clobbers (
+      .in_i    ( fpr_clobber_vld[k] ),
+      .cnt_o   ( fpr_clobber_idx    ),
+      .empty_o ( fpr_no_clobber     )
     );
+
+    assign rd_clobber_gpr_o[k] = (gpr_no_clobber) ? ariane_pkg::NONE : clobber_fu[gpr_clobber_idx];
+    assign rd_clobber_fpr_o[k] = (fpr_no_clobber) ? ariane_pkg::NONE : clobber_fu[fpr_clobber_idx];
   end
 
   // ----------------------------------
@@ -310,6 +285,7 @@ module scoreboard #(
   // ----------------------------------
   // read operand interface: same logic as register file
   logic [NR_ENTRIES+NR_WB_PORTS-1:0] rs1_fwd_req, rs2_fwd_req, rs3_fwd_req;
+  logic [$clog2(NR_WB_PORTS+NR_ENTRIES)-1:0] rs1_fwd_idx, rs2_fwd_idx, rs3_fwd_idx;
   logic [NR_ENTRIES+NR_WB_PORTS-1:0][riscv::XLEN-1:0] rs_data;
   logic rs1_valid, rs2_valid;
 
@@ -327,72 +303,44 @@ module scoreboard #(
     assign rs_data[k+NR_WB_PORTS]     = mem_q[k].sbe.result;
   end
 
-  // check whether we are accessing GPR[0], rs3 is only used with the FPR!
-  assign rs1_valid_o = rs1_valid & ((|rs1_i) | ariane_pkg::is_rs1_fpr(issue_instr_o.op));
-  assign rs2_valid_o = rs2_valid & ((|rs2_i) | ariane_pkg::is_rs2_fpr(issue_instr_o.op));
-
-  // use fixed prio here
-  // this implicitly gives higher prio to WB ports
-  rr_arb_tree #(
-    .NumIn(NR_ENTRIES+NR_WB_PORTS),
-    .DataWidth(riscv::XLEN),
-    .ExtPrio(1'b1),
-    .AxiVldRdy(1'b1)
-  ) i_sel_rs1 (
-    .clk_i   ( clk_i       ),
-    .rst_ni  ( rst_ni      ),
-    .flush_i ( 1'b0        ),
-    .rr_i    ( '0          ),
-    .req_i   ( rs1_fwd_req ),
-    .gnt_o   (             ),
-    .data_i  ( rs_data     ),
-    .gnt_i   ( 1'b1        ),
-    .req_o   ( rs1_valid   ),
-    .data_o  ( rs1_o       ),
-    .idx_o   (             )
+  lzc #(
+    .WIDTH ( NR_WB_PORTS+NR_ENTRIES ),
+    .MODE  ( 0                      )
+  ) i_lzc_rs1_wb (
+    .in_i    ( rs1_fwd_req ),
+    .cnt_o   ( rs1_fwd_idx ),
+    .empty_o (             )
   );
 
-  rr_arb_tree #(
-    .NumIn(NR_ENTRIES+NR_WB_PORTS),
-    .DataWidth(riscv::XLEN),
-    .ExtPrio(1'b1),
-    .AxiVldRdy(1'b1)
-  ) i_sel_rs2 (
-    .clk_i   ( clk_i       ),
-    .rst_ni  ( rst_ni      ),
-    .flush_i ( 1'b0        ),
-    .rr_i    ( '0          ),
-    .req_i   ( rs2_fwd_req ),
-    .gnt_o   (             ),
-    .data_i  ( rs_data     ),
-    .gnt_i   ( 1'b1        ),
-    .req_o   ( rs2_valid   ),
-    .data_o  ( rs2_o       ),
-    .idx_o   (             )
+  lzc #(
+    .WIDTH ( NR_WB_PORTS+NR_ENTRIES ),
+    .MODE  ( 0                      )
+  ) i_lzc_rs2_wb (
+    .in_i    ( rs2_fwd_req ),
+    .cnt_o   ( rs2_fwd_idx ),
+    .empty_o (             )
   );
 
-  riscv::xlen_t           rs3;
-
-  rr_arb_tree #(
-    .NumIn(NR_ENTRIES+NR_WB_PORTS),
-    .DataWidth(riscv::XLEN),
-    .ExtPrio(1'b1),
-    .AxiVldRdy(1'b1)
-  ) i_sel_rs3 (
-    .clk_i   ( clk_i       ),
-    .rst_ni  ( rst_ni      ),
-    .flush_i ( 1'b0        ),
-    .rr_i    ( '0          ),
-    .req_i   ( rs3_fwd_req ),
-    .gnt_o   (             ),
-    .data_i  ( rs_data     ),
-    .gnt_i   ( 1'b1        ),
-    .req_o   ( rs3_valid_o ),
-    .data_o  ( rs3         ),
-    .idx_o   (             )
+  lzc #(
+    .WIDTH ( NR_WB_PORTS+NR_ENTRIES ),
+    .MODE  ( 0                      )
+  ) i_lzc_rs3_wb (
+    .in_i    ( rs3_fwd_req ),
+    .cnt_o   ( rs3_fwd_idx ),
+    .empty_o (             )
   );
 
-  assign rs3_o = rs3[ariane_pkg::FLEN-1:0];
+  assign rs1_valid = |rs1_fwd_req;
+  assign rs2_valid = |rs2_fwd_req;
+  assign rs3_valid_o = |rs3_fwd_req;
+
+  assign rs1_o = (rs1_valid) ? rs_data[rs1_fwd_idx] : '0;
+  assign rs2_o = (rs2_valid) ? rs_data[rs2_fwd_idx] : '0;
+  assign rs3_o = (rs3_valid_o) ? rs_data[rs3_fwd_idx] : '0;
+
+  // check whether we are accessing GPR[0], rs3 is only used with the FPR!
+  assign rs1_valid_o = rs1_valid & ((|rs1_i) | ariane_pkg::is_rs1_fpr(issue_instr_o.op));
+  assign rs2_valid_o = rs2_valid & ((|rs2_i) | ariane_pkg::is_rs2_fpr(issue_instr_o.op));
 
   // sequential process
   always_ff @(posedge clk_i or negedge rst_ni) begin : regs
-- 
GitLab