From 4f3ef52ec94a9ff3b9dcf325d8455881faccbd4e Mon Sep 17 00:00:00 2001
From: Alban Gruin <alban.gruin@irit.fr>
Date: Fri, 6 May 2022 13:11:30 +0200
Subject: [PATCH] issue stage: critical path improvements

Signed-off-by: Alban Gruin <alban.gruin@irit.fr>
---
 include/ariane_pkg.sv      |   4 +
 src/decoder.sv             |   9 ++
 src/issue_read_operands.sv | 210 +++++++++++++++----------------------
 src/issue_stage.sv         |   9 --
 src/scoreboard.sv          |  31 +++---
 5 files changed, 114 insertions(+), 149 deletions(-)

diff --git a/include/ariane_pkg.sv b/include/ariane_pkg.sv
index 290219e3..9c35b0b6 100644
--- a/include/ariane_pkg.sv
+++ b/include/ariane_pkg.sv
@@ -603,6 +603,10 @@ package ariane_pkg;
         logic                     valid;         // is the result valid
         logic                     use_imm;       // should we use the immediate as operand b?
         logic                     use_zimm;      // use zimm as operand a
+        logic                     use_rs1_fpr;
+        logic                     use_rs2_fpr;
+        logic                     use_imm_fpr;
+        logic                     use_rd_fpr;
         logic                     use_pc;        // set if we need to use the PC as operand a, PC from exception
         exception_t               ex;            // exception has occurred
         branchpredict_sbe_t       bp;            // branch predict scoreboard data structure
diff --git a/src/decoder.sv b/src/decoder.sv
index e0c551e7..4ea5de72 100644
--- a/src/decoder.sv
+++ b/src/decoder.sv
@@ -80,6 +80,10 @@ module decoder import ariane_pkg::*; (
         instruction_o.trans_id      = '0;
         instruction_o.is_compressed = is_compressed_i;
         instruction_o.use_zimm      = 1'b0;
+        instruction_o.use_rs1_fpr   = 1'b0;
+        instruction_o.use_rs2_fpr   = 1'b0;
+        instruction_o.use_imm_fpr   = 1'b0;
+        instruction_o.use_rd_fpr    = 1'b0;
         instruction_o.bp            = branch_predict_i;
         ecall                       = 1'b0;
         ebreak                      = 1'b0;
@@ -1005,6 +1009,11 @@ module decoder import ariane_pkg::*; (
 
                 default: illegal_instr = 1'b1;
             endcase
+
+            instruction_o.use_rs1_fpr = is_rs1_fpr(instruction_o.op);
+            instruction_o.use_rs2_fpr = is_rs2_fpr(instruction_o.op);
+            instruction_o.use_imm_fpr = is_imm_fpr(instruction_o.op);
+            instruction_o.use_rd_fpr = is_rd_fpr(instruction_o.op);
         end
     end
 
diff --git a/src/issue_read_operands.sv b/src/issue_read_operands.sv
index 1bdd15a8..7e6a2b27 100644
--- a/src/issue_read_operands.sv
+++ b/src/issue_read_operands.sv
@@ -26,13 +26,10 @@ module issue_read_operands import ariane_pkg::*; #(
     input  logic                                   issue_instr_valid_i,
     output logic                                   issue_ack_o,
     // lookup rd in scoreboard
-    output logic [REG_ADDR_SIZE-1:0]               rs1_o,
     input  riscv::xlen_t                           rs1_i,
     input  logic                                   rs1_valid_i,
-    output logic [REG_ADDR_SIZE-1:0]               rs2_o,
     input  riscv::xlen_t                           rs2_i,
     input  logic                                   rs2_valid_i,
-    output logic [REG_ADDR_SIZE-1:0]               rs3_o,
     input  logic [FLEN-1:0]                        rs3_i,
     input  logic                                   rs3_valid_i,
     // get clobber input
@@ -149,93 +146,36 @@ module issue_read_operands import ariane_pkg::*; #(
     // ---------------
     // check that all operands are available, otherwise stall
     // forward corresponding register
-    always_comb begin : operands_available
-        stall = 1'b0;
-        // operand forwarding signals
-        forward_rs1 = 1'b0;
-        forward_rs2 = 1'b0;
-        forward_rs3 = 1'b0; // FPR only
-        // poll the scoreboard for those values
-        rs1_o = issue_instr_i.rs1;
-        rs2_o = issue_instr_i.rs2;
-        rs3_o = issue_instr_i.result[REG_ADDR_SIZE-1:0]; // rs3 is encoded in imm field
-
-        // 0. check that we are not using the zimm type in RS1
-        //    as this is an immediate we do not have to wait on anything here
-        // 1. check if the source registers are clobbered --> check appropriate clobber list (gpr/fpr)
-        // 2. poll the scoreboard
-        if (!issue_instr_i.use_zimm && (is_rs1_fpr(issue_instr_i.op) ? rd_clobber_fpr_i[issue_instr_i.rs1] != NONE
-                                                                     : rd_clobber_gpr_i[issue_instr_i.rs1] != NONE)) begin
-            // check if the clobbering instruction is not a CSR instruction, CSR instructions can only
-            // be fetched through the register file since they can't be forwarded
-            // if the operand is available, forward it. CSRs don't write to/from FPR
-            if (rs1_valid_i && (is_rs1_fpr(issue_instr_i.op) ? 1'b1 : ((rd_clobber_gpr_i[issue_instr_i.rs1] != CSR) || (issue_instr_i.op == SFENCE_VMA)))) begin
-                forward_rs1 = 1'b1;
-            end else begin // the operand is not available -> stall
-                stall = 1'b1;
-            end
-        end
+    logic is_instr_csr_or_fence_rs1, is_instr_csr_or_fence_rs2;
+    assign is_instr_csr_or_fence_rs1 = rs1_valid_i && (issue_instr_i.use_rs1_fpr || rd_clobber_gpr_i[issue_instr_i.rs1] != CSR || issue_instr_i.op == SFENCE_VMA);
+    assign is_instr_csr_or_fence_rs2 = rs2_valid_i && (issue_instr_i.use_rs2_fpr || rd_clobber_gpr_i[issue_instr_i.rs2] != CSR || issue_instr_i.op == SFENCE_VMA);
 
-        if (is_rs2_fpr(issue_instr_i.op) ? rd_clobber_fpr_i[issue_instr_i.rs2] != NONE
-                                         : rd_clobber_gpr_i[issue_instr_i.rs2] != NONE) begin
-            // if the operand is available, forward it. CSRs don't write to/from FPR
-            if (rs2_valid_i && (is_rs2_fpr(issue_instr_i.op) ? 1'b1 : ( (rd_clobber_gpr_i[issue_instr_i.rs2] != CSR) || (issue_instr_i.op == SFENCE_VMA))))  begin
-                forward_rs2 = 1'b1;
-            end else begin // the operand is not available -> stall
-                stall = 1'b1;
-            end
-        end
+    logic should_forward_rs1, should_forward_rs2, should_forward_rs3;
+    assign should_forward_rs1 = !issue_instr_i.use_zimm && ((issue_instr_i.use_rs1_fpr && rd_clobber_fpr_i[issue_instr_i.rs1]) || rd_clobber_gpr_i[issue_instr_i.rs1] != NONE);
+    assign should_forward_rs2 = (issue_instr_i.use_rs2_fpr && rd_clobber_fpr_i[issue_instr_i.rs2]) || rd_clobber_gpr_i[issue_instr_i.rs2] != NONE;
+    assign should_forward_rs3 = issue_instr_i.use_imm_fpr && rd_clobber_fpr_i[issue_instr_i.result[REG_ADDR_SIZE-1:0]] != NONE;
 
-        if (is_imm_fpr(issue_instr_i.op) && rd_clobber_fpr_i[issue_instr_i.result[REG_ADDR_SIZE-1:0]] != NONE) begin
-            // if the operand is available, forward it. CSRs don't write to/from FPR so no need to check
-            if (rs3_valid_i) begin
-                forward_rs3 = 1'b1;
-            end else begin // the operand is not available -> stall
-                stall = 1'b1;
-            end
-        end
-    end
+    assign stall = (should_forward_rs1 && !is_instr_csr_or_fence_rs1) ||
+                   (should_forward_rs2 && !is_instr_csr_or_fence_rs2) ||
+                   (should_forward_rs3 && !rs3_valid_i);
 
-    // Forwarding/Output MUX
-    always_comb begin : forwarding_operand_select
-        // default is regfiles (gpr or fpr)
-        operand_a_n = operand_a_regfile;
-        operand_b_n = operand_b_regfile;
-        // immediates are the third operands in the store case
-        // for FP operations, the imm field can also be the third operand from the regfile
-        imm_n      = is_imm_fpr(issue_instr_i.op) ? {{riscv::XLEN-FLEN{1'b0}}, operand_c_regfile} : issue_instr_i.result;
-        trans_id_n = issue_instr_i.trans_id;
-        fu_n       = issue_instr_i.fu;
-        operator_n = issue_instr_i.op;
-        // or should we forward
-        if (forward_rs1) begin
-            operand_a_n  = rs1_i;
-        end
-
-        if (forward_rs2) begin
-            operand_b_n  = rs2_i;
-        end
-
-        if (forward_rs3) begin
-            imm_n  = {{riscv::XLEN-FLEN{1'b0}}, rs3_i};
-        end
-
-        // use the PC as operand a
-        if (issue_instr_i.use_pc) begin
-            operand_a_n = {{riscv::XLEN-riscv::VLEN{issue_instr_i.pc[riscv::VLEN-1]}}, issue_instr_i.pc};
-        end
+    assign forward_rs1 = should_forward_rs1 && is_instr_csr_or_fence_rs1;
+    assign forward_rs2 = should_forward_rs2 && is_instr_csr_or_fence_rs2;
+    assign forward_rs3 = should_forward_rs3 && rs3_valid_i;
 
-        // use the zimm as operand a
-        if (issue_instr_i.use_zimm) begin
-            // zero extend operand a
-            operand_a_n = {{riscv::XLEN-5{1'b0}}, issue_instr_i.rs1[4:0]};
-        end
-        // or is it an immediate (including PC), this is not the case for a store and control flow instructions
-        // also make sure operand B is not already used as an FP operand
-        if (issue_instr_i.use_imm && (issue_instr_i.fu != STORE) && (issue_instr_i.fu != CTRL_FLOW) && !is_rs2_fpr(issue_instr_i.op)) begin
-            operand_b_n = issue_instr_i.result;
-        end
-    end
+    // Forwarding/Output MUX
+    assign operand_a_n = (issue_instr_i.use_zimm) ? {{riscv::XLEN-5{1'b0}}, issue_instr_i.rs1[4:0]} :
+                         (issue_instr_i.use_pc) ? {{riscv::XLEN-riscv::VLEN{issue_instr_i.pc[riscv::VLEN-1]}}, issue_instr_i.pc} :
+                         (forward_rs1) ? rs1_i : operand_a_regfile;
+    assign operand_b_n = (issue_instr_i.use_imm && !(issue_instr_i.fu inside {STORE, CTRL_FLOW}) && !issue_instr_i.use_rs2_fpr) ? issue_instr_i.result :
+                         (forward_rs2) ? rs2_i : operand_b_regfile;
+
+    assign imm_n = (forward_rs3) ? {{riscv::XLEN-FLEN{1'b0}}, rs3_i} :
+                   issue_instr_i.use_imm_fpr ? {{riscv::XLEN-FLEN{1'b0}}, operand_c_regfile} :
+                   issue_instr_i.result;
+    assign trans_id_n = issue_instr_i.trans_id;
+    assign fu_n = issue_instr_i.fu;
+    assign operator_n = issue_instr_i.op;
 
     // FU select, assert the correct valid out signal (in the next cycle)
     // This needs to be like this to make verilator happy. I know its ugly.
@@ -299,47 +239,65 @@ module issue_read_operands import ariane_pkg::*; #(
       end
     end
 
+    logic [NR_COMMIT_PORTS-1:0] waw_check;
+    logic                       rd_clobbered;
+
+    assign rd_clobbered = (issue_instr_i.use_rd_fpr && rd_clobber_fpr_i[issue_instr_i.rd] == NONE) ||
+                          rd_clobber_gpr_i[issue_instr_i.rd] == NONE;
+
+    for (genvar i = 0; i < NR_COMMIT_PORTS; i++) begin
+        assign waw_check[i] = (issue_instr_i.use_rd_fpr && we_fpr_i[i] && waddr_i[i] == issue_instr_i.rd) ||
+                              we_gpr_i[i] && waddr_i[i] == issue_instr_i.rd;
+    end
+
+    assign issue_ack_o = issue_instr_valid_i &&
+                         (
+                          (!stall && !fu_busy && (rd_clobbered || (|waw_check))) ||
+                          (issue_instr_i.ex.valid) ||
+                          (issue_instr_i.fu == NONE)
+                         );
+
     // We can issue an instruction if we do not detect that any other instruction is writing the same
     // destination register.
     // We also need to check if there is an unresolved branch in the scoreboard.
-    always_comb begin : issue_scoreboard
-        // default assignment
-        issue_ack_o = 1'b0;
-        // check that we didn't stall, that the instruction we got is valid
-        // and that the functional unit we need is not busy
-        if (issue_instr_valid_i) begin
-            // check that the corresponding functional unit is not busy
-            if (!stall && !fu_busy) begin
-                // -----------------------------------------
-                // WAW - Write After Write Dependency Check
-                // -----------------------------------------
-                // no other instruction has the same destination register -> issue the instruction
-                if (is_rd_fpr(issue_instr_i.op) ? (rd_clobber_fpr_i[issue_instr_i.rd] == NONE)
-                                                : (rd_clobber_gpr_i[issue_instr_i.rd] == NONE)) begin
-                    issue_ack_o = 1'b1;
-                end
-                // or check that the target destination register will be written in this cycle by the
-                // commit stage
-                for (int unsigned i = 0; i < NR_COMMIT_PORTS; i++)
-                    if (is_rd_fpr(issue_instr_i.op) ? (we_fpr_i[i] && waddr_i[i] == issue_instr_i.rd)
-                                                    : (we_gpr_i[i] && waddr_i[i] == issue_instr_i.rd)) begin
-                        issue_ack_o = 1'b1;
-                    end
-            end
-            // we can also issue the instruction under the following two circumstances:
-            // we can do this even if we are stalled or no functional unit is ready (as we don't need one)
-            // the decoder needs to make sure that the instruction is marked as valid when it does not
-            // need any functional unit or if an exception occurred previous to the execute stage.
-            // 1. we already got an exception
-            if (issue_instr_i.ex.valid) begin
-                issue_ack_o = 1'b1;
-            end
-            // 2. it is an instruction which does not need any functional unit
-            if (issue_instr_i.fu == NONE) begin
-                issue_ack_o = 1'b1;
-            end
-        end
-    end
+    // always_comb begin : issue_scoreboard
+    //     // default assignment
+    //     issue_ack_o = 1'b0;
+    //     // check that we didn't stall, that the instruction we got is valid
+    //     // and that the functional unit we need is not busy
+    //     if (issue_instr_valid_i) begin
+    //         // check that the corresponding functional unit is not busy
+    //         if (!stall && !fu_busy) begin
+    //             // -----------------------------------------
+    //             // WAW - Write After Write Dependency Check
+    //             // -----------------------------------------
+    //             // no other instruction has the same destination register -> issue the instruction
+    //             if (is_rd_fpr(issue_instr_i.op) ? (rd_clobber_fpr_i[issue_instr_i.rd] == NONE)
+    //                                             : (rd_clobber_gpr_i[issue_instr_i.rd] == NONE)) begin
+    //                 issue_ack_o = 1'b1;
+    //             end
+    //             // or check that the target destination register will be written in this cycle by the
+    //             // commit stage
+    //             for (int unsigned i = 0; i < NR_COMMIT_PORTS; i++)
+    //                 if (is_rd_fpr(issue_instr_i.op) ? (we_fpr_i[i] && waddr_i[i] == issue_instr_i.rd)
+    //                                                 : (we_gpr_i[i] && waddr_i[i] == issue_instr_i.rd)) begin
+    //                     issue_ack_o = 1'b1;
+    //                 end
+    //         end
+    //         // we can also issue the instruction under the following two circumstances:
+    //         // we can do this even if we are stalled or no functional unit is ready (as we don't need one)
+    //         // the decoder needs to make sure that the instruction is marked as valid when it does not
+    //         // need any functional unit or if an exception occurred previous to the execute stage.
+    //         // 1. we already got an exception
+    //         if (issue_instr_i.ex.valid) begin
+    //             issue_ack_o = 1'b1;
+    //         end
+    //         // 2. it is an instruction which does not need any functional unit
+    //         if (issue_instr_i.fu == NONE) begin
+    //             issue_ack_o = 1'b1;
+    //         end
+    //     end
+    // end
 
     // ----------------------
     // Integer Register File
@@ -408,8 +366,8 @@ module issue_read_operands import ariane_pkg::*; #(
         end
     endgenerate
 
-    assign operand_a_regfile = is_rs1_fpr(issue_instr_i.op) ? {{riscv::XLEN-FLEN{1'b0}}, fprdata[0]} : rdata[0];
-    assign operand_b_regfile = is_rs2_fpr(issue_instr_i.op) ? {{riscv::XLEN-FLEN{1'b0}}, fprdata[1]} : rdata[1];
+    assign operand_a_regfile = issue_instr_i.use_rs1_fpr ? {{riscv::XLEN-FLEN{1'b0}}, fprdata[0]} : rdata[0];
+    assign operand_b_regfile = issue_instr_i.use_rs2_fpr ? {{riscv::XLEN-FLEN{1'b0}}, fprdata[1]} : rdata[1];
     assign operand_c_regfile = fprdata[2];
 
     // ----------------------
diff --git a/src/issue_stage.sv b/src/issue_stage.sv
index cc433b38..0bdde401 100644
--- a/src/issue_stage.sv
+++ b/src/issue_stage.sv
@@ -82,15 +82,12 @@ module issue_stage import ariane_pkg::*; #(
     fu_t  [2**REG_ADDR_SIZE-1:0] rd_clobber_gpr_sb_iro;
     fu_t  [2**REG_ADDR_SIZE-1:0] rd_clobber_fpr_sb_iro;
 
-    logic [REG_ADDR_SIZE-1:0]  rs1_iro_sb;
     riscv::xlen_t              rs1_sb_iro;
     logic                      rs1_valid_sb_iro;
 
-    logic [REG_ADDR_SIZE-1:0]  rs2_iro_sb;
     riscv::xlen_t              rs2_sb_iro;
     logic                      rs2_valid_iro_sb;
 
-    logic [REG_ADDR_SIZE-1:0]  rs3_iro_sb;
     logic [FLEN-1:0]           rs3_sb_iro;
     logic                      rs3_valid_iro_sb;
 
@@ -130,13 +127,10 @@ module issue_stage import ariane_pkg::*; #(
         .unresolved_branch_i   ( 1'b0                                      ),
         .rd_clobber_gpr_o      ( rd_clobber_gpr_sb_iro                     ),
         .rd_clobber_fpr_o      ( rd_clobber_fpr_sb_iro                     ),
-        .rs1_i                 ( rs1_iro_sb                                ),
         .rs1_o                 ( rs1_sb_iro                                ),
         .rs1_valid_o           ( rs1_valid_sb_iro                          ),
-        .rs2_i                 ( rs2_iro_sb                                ),
         .rs2_o                 ( rs2_sb_iro                                ),
         .rs2_valid_o           ( rs2_valid_iro_sb                          ),
-        .rs3_i                 ( rs3_iro_sb                                ),
         .rs3_o                 ( rs3_sb_iro                                ),
         .rs3_valid_o           ( rs3_valid_iro_sb                          ),
 
@@ -166,13 +160,10 @@ module issue_stage import ariane_pkg::*; #(
         .issue_ack_o         ( issue_ack_iro_sb                ),
         .fu_data_o           ( fu_data_o                       ),
         .flu_ready_i         ( flu_ready_i                     ),
-        .rs1_o               ( rs1_iro_sb                      ),
         .rs1_i               ( rs1_sb_iro                      ),
         .rs1_valid_i         ( rs1_valid_sb_iro                ),
-        .rs2_o               ( rs2_iro_sb                      ),
         .rs2_i               ( rs2_sb_iro                      ),
         .rs2_valid_i         ( rs2_valid_iro_sb                ),
-        .rs3_o               ( rs3_iro_sb                      ),
         .rs3_i               ( rs3_sb_iro                      ),
         .rs3_valid_i         ( rs3_valid_iro_sb                ),
         .rd_clobber_gpr_i    ( rd_clobber_gpr_sb_iro           ),
diff --git a/src/scoreboard.sv b/src/scoreboard.sv
index c78897da..98719910 100644
--- a/src/scoreboard.sv
+++ b/src/scoreboard.sv
@@ -28,15 +28,12 @@ module scoreboard #(
   output ariane_pkg::fu_t [2**ariane_pkg::REG_ADDR_SIZE-1:0]    rd_clobber_fpr_o,
 
   // regfile like interface to operand read stage
-  input  logic [ariane_pkg::REG_ADDR_SIZE-1:0]                  rs1_i,
   output riscv::xlen_t                                          rs1_o,
   output logic                                                  rs1_valid_o,
 
-  input  logic [ariane_pkg::REG_ADDR_SIZE-1:0]                  rs2_i,
   output riscv::xlen_t                                          rs2_o,
   output logic                                                  rs2_valid_o,
 
-  input  logic [ariane_pkg::REG_ADDR_SIZE-1:0]                  rs3_i,
   output logic [ariane_pkg::FLEN-1:0]                           rs3_o,
   output logic                                                  rs3_valid_o,
 
@@ -76,7 +73,7 @@ module scoreboard #(
   } mem_q [NR_ENTRIES-1:0], mem_n [NR_ENTRIES-1:0];
 
   logic                    issue_full, issue_en;
-  logic [BITS_ENTRIES-1:0] issue_cnt_n,      issue_cnt_q;
+  logic [BITS_ENTRIES:0]   issue_cnt_n,      issue_cnt_q;
   logic [BITS_ENTRIES-1:0] write_pointer_n,  write_pointer_q;
   logic [BITS_ENTRIES-1:0] issue_pointer_n,  issue_pointer_q;
   logic [NR_COMMIT_PORTS-1:0][BITS_ENTRIES-1:0] commit_pointer_n, commit_pointer_q;
@@ -89,7 +86,7 @@ module scoreboard #(
 
   // the issue queue is full don't issue any new instructions
   // works since aligned to power of 2
-  assign issue_full = &issue_cnt_q;
+  assign issue_full = (issue_cnt_q[BITS_ENTRIES] == 1'b1);
 
   assign sb_full_o = issue_full;
 
@@ -124,7 +121,8 @@ module scoreboard #(
       // decoded_instr_ack_o = 1'b1;
       mem_n[write_pointer_q] = {1'b1,
                                 1'b1,                                      // valid bit
-                                ariane_pkg::is_rd_fpr(decoded_instr_i.op), // whether rd goes to the fpr
+                                decoded_instr_i.use_rd_fpr,
+                                // ariane_pkg::is_rd_fpr(decoded_instr_i.op), // whether rd goes to the fpr
                                 decoded_instr_i                            // decoded instruction record
                                 };
       has_mem_access_n[write_pointer_q] = decoded_instr_i.fu inside {ariane_pkg::LOAD, ariane_pkg::STORE};
@@ -289,17 +287,22 @@ module scoreboard #(
   logic [NR_ENTRIES+NR_WB_PORTS-1:0][riscv::XLEN-1:0] rs_data;
   logic rs1_valid, rs2_valid;
 
+  logic [ariane_pkg::REG_ADDR_SIZE-1:0] rs1, rs2, rs3;
+  assign rs1 = issue_instr_o.rs1;
+  assign rs2 = issue_instr_o.rs2;
+  assign rs3 = issue_instr_o.result[ariane_pkg::REG_ADDR_SIZE-1:0];  // rs3 is encoded in imm field
+
   // WB ports have higher prio than entries
   for (genvar k = 0; unsigned'(k) < NR_WB_PORTS; k++) begin : gen_rs_wb
-    assign rs1_fwd_req[k] = (mem_q[trans_id_i[k]].sbe.rd == rs1_i) & wt_valid_i[k] & (~ex_i[k].valid) & (mem_q[trans_id_i[k]].is_rd_fpr_flag == ariane_pkg::is_rs1_fpr(issue_instr_o.op));
-    assign rs2_fwd_req[k] = (mem_q[trans_id_i[k]].sbe.rd == rs2_i) & wt_valid_i[k] & (~ex_i[k].valid) & (mem_q[trans_id_i[k]].is_rd_fpr_flag == ariane_pkg::is_rs2_fpr(issue_instr_o.op));
-    assign rs3_fwd_req[k] = (mem_q[trans_id_i[k]].sbe.rd == rs3_i) & wt_valid_i[k] & (~ex_i[k].valid) & (mem_q[trans_id_i[k]].is_rd_fpr_flag == ariane_pkg::is_imm_fpr(issue_instr_o.op));
+    assign rs1_fwd_req[k] = (mem_q[trans_id_i[k]].sbe.rd == rs1) & wt_valid_i[k] & (~ex_i[k].valid) & (mem_q[trans_id_i[k]].is_rd_fpr_flag == issue_instr_o.use_rs1_fpr);
+    assign rs2_fwd_req[k] = (mem_q[trans_id_i[k]].sbe.rd == rs2) & wt_valid_i[k] & (~ex_i[k].valid) & (mem_q[trans_id_i[k]].is_rd_fpr_flag == issue_instr_o.use_rs2_fpr);
+    assign rs3_fwd_req[k] = (mem_q[trans_id_i[k]].sbe.rd == rs3) & wt_valid_i[k] & (~ex_i[k].valid) & (mem_q[trans_id_i[k]].is_rd_fpr_flag == issue_instr_o.use_imm_fpr);
     assign rs_data[k]     = wbdata_i[k];
   end
   for (genvar k = 0; unsigned'(k) < NR_ENTRIES; k++) begin : gen_rs_entries
-    assign rs1_fwd_req[k+NR_WB_PORTS] = (mem_q[k].sbe.rd == rs1_i) & ~mem_q[k].pending & mem_q[k].issued & mem_q[k].sbe.valid & (mem_q[k].is_rd_fpr_flag == ariane_pkg::is_rs1_fpr(issue_instr_o.op));
-    assign rs2_fwd_req[k+NR_WB_PORTS] = (mem_q[k].sbe.rd == rs2_i) & ~mem_q[k].pending & mem_q[k].issued & mem_q[k].sbe.valid & (mem_q[k].is_rd_fpr_flag == ariane_pkg::is_rs2_fpr(issue_instr_o.op));
-    assign rs3_fwd_req[k+NR_WB_PORTS] = (mem_q[k].sbe.rd == rs3_i) & ~mem_q[k].pending & mem_q[k].issued & mem_q[k].sbe.valid & (mem_q[k].is_rd_fpr_flag == ariane_pkg::is_imm_fpr(issue_instr_o.op));
+    assign rs1_fwd_req[k+NR_WB_PORTS] = (mem_q[k].sbe.rd == rs1) & ~mem_q[k].pending & mem_q[k].issued & mem_q[k].sbe.valid & (mem_q[k].is_rd_fpr_flag == issue_instr_o.use_rs1_fpr);
+    assign rs2_fwd_req[k+NR_WB_PORTS] = (mem_q[k].sbe.rd == rs2) & ~mem_q[k].pending & mem_q[k].issued & mem_q[k].sbe.valid & (mem_q[k].is_rd_fpr_flag == issue_instr_o.use_rs2_fpr);
+    assign rs3_fwd_req[k+NR_WB_PORTS] = (mem_q[k].sbe.rd == rs3) & ~mem_q[k].pending & mem_q[k].issued & mem_q[k].sbe.valid & (mem_q[k].is_rd_fpr_flag == issue_instr_o.use_imm_fpr);
     assign rs_data[k+NR_WB_PORTS]     = mem_q[k].sbe.result;
   end
 
@@ -339,8 +342,8 @@ module scoreboard #(
   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));
+  assign rs1_valid_o = rs1_valid & ((|rs1) | issue_instr_o.use_rs1_fpr);
+  assign rs2_valid_o = rs2_valid & ((|rs2) | issue_instr_o.use_rs2_fpr);
 
   // sequential process
   always_ff @(posedge clk_i or negedge rst_ni) begin : regs
-- 
GitLab