diff --git a/include/ariane_pkg.sv b/include/ariane_pkg.sv index 290219e3fca5d2ab86a10fc46f9f443dc665b72a..9c35b0b6ab48698d8eb0e0cb5a765f905e0cc124 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 e0c551e79008c34dca3810b3d9a0db2cd99958f4..4ea5de725a8582604c894313382488af6abcbbe7 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 1bdd15a8bfef214d8eb1277510f4ff19474f9b64..7e6a2b2708b275b23d6a2ae8f7a164276df2bd7a 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 cc433b38a35d7f97f70eff06603e8f195ca654f8..0bdde4010404ef0f2d68e2257b356f00bbc666a0 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 c78897da17055ad20532c554ba231d40d12ac9a6..9871991048ce8f0fb904bf00cfa5e5a50df6dde1 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