Skip to content
Snippets Groups Projects
Commit 4f3ef52e authored by Alban Gruin's avatar Alban Gruin
Browse files

issue stage: critical path improvements


Signed-off-by: default avatarAlban Gruin <alban.gruin@irit.fr>
parent 5d9b7a15
Branches
No related tags found
No related merge requests found
...@@ -603,6 +603,10 @@ package ariane_pkg; ...@@ -603,6 +603,10 @@ package ariane_pkg;
logic valid; // is the result valid logic valid; // is the result valid
logic use_imm; // should we use the immediate as operand b? logic use_imm; // should we use the immediate as operand b?
logic use_zimm; // use zimm as operand a 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 logic use_pc; // set if we need to use the PC as operand a, PC from exception
exception_t ex; // exception has occurred exception_t ex; // exception has occurred
branchpredict_sbe_t bp; // branch predict scoreboard data structure branchpredict_sbe_t bp; // branch predict scoreboard data structure
......
...@@ -80,6 +80,10 @@ module decoder import ariane_pkg::*; ( ...@@ -80,6 +80,10 @@ module decoder import ariane_pkg::*; (
instruction_o.trans_id = '0; instruction_o.trans_id = '0;
instruction_o.is_compressed = is_compressed_i; instruction_o.is_compressed = is_compressed_i;
instruction_o.use_zimm = 1'b0; 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; instruction_o.bp = branch_predict_i;
ecall = 1'b0; ecall = 1'b0;
ebreak = 1'b0; ebreak = 1'b0;
...@@ -1005,6 +1009,11 @@ module decoder import ariane_pkg::*; ( ...@@ -1005,6 +1009,11 @@ module decoder import ariane_pkg::*; (
default: illegal_instr = 1'b1; default: illegal_instr = 1'b1;
endcase 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
end end
......
...@@ -26,13 +26,10 @@ module issue_read_operands import ariane_pkg::*; #( ...@@ -26,13 +26,10 @@ module issue_read_operands import ariane_pkg::*; #(
input logic issue_instr_valid_i, input logic issue_instr_valid_i,
output logic issue_ack_o, output logic issue_ack_o,
// lookup rd in scoreboard // lookup rd in scoreboard
output logic [REG_ADDR_SIZE-1:0] rs1_o,
input riscv::xlen_t rs1_i, input riscv::xlen_t rs1_i,
input logic rs1_valid_i, input logic rs1_valid_i,
output logic [REG_ADDR_SIZE-1:0] rs2_o,
input riscv::xlen_t rs2_i, input riscv::xlen_t rs2_i,
input logic rs2_valid_i, input logic rs2_valid_i,
output logic [REG_ADDR_SIZE-1:0] rs3_o,
input logic [FLEN-1:0] rs3_i, input logic [FLEN-1:0] rs3_i,
input logic rs3_valid_i, input logic rs3_valid_i,
// get clobber input // get clobber input
...@@ -149,93 +146,36 @@ module issue_read_operands import ariane_pkg::*; #( ...@@ -149,93 +146,36 @@ module issue_read_operands import ariane_pkg::*; #(
// --------------- // ---------------
// check that all operands are available, otherwise stall // check that all operands are available, otherwise stall
// forward corresponding register // forward corresponding register
always_comb begin : operands_available logic is_instr_csr_or_fence_rs1, is_instr_csr_or_fence_rs2;
stall = 1'b0; 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);
// operand forwarding signals 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);
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
if (is_rs2_fpr(issue_instr_i.op) ? rd_clobber_fpr_i[issue_instr_i.rs2] != NONE logic should_forward_rs1, should_forward_rs2, should_forward_rs3;
: rd_clobber_gpr_i[issue_instr_i.rs2] != NONE) begin 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);
// if the operand is available, forward it. CSRs don't write to/from FPR 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;
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 assign should_forward_rs3 = issue_instr_i.use_imm_fpr && rd_clobber_fpr_i[issue_instr_i.result[REG_ADDR_SIZE-1:0]] != NONE;
forward_rs2 = 1'b1;
end else begin // the operand is not available -> stall
stall = 1'b1;
end
end
if (is_imm_fpr(issue_instr_i.op) && rd_clobber_fpr_i[issue_instr_i.result[REG_ADDR_SIZE-1:0]] != NONE) begin assign stall = (should_forward_rs1 && !is_instr_csr_or_fence_rs1) ||
// if the operand is available, forward it. CSRs don't write to/from FPR so no need to check (should_forward_rs2 && !is_instr_csr_or_fence_rs2) ||
if (rs3_valid_i) begin (should_forward_rs3 && !rs3_valid_i);
forward_rs3 = 1'b1;
end else begin // the operand is not available -> stall
stall = 1'b1;
end
end
end
// Forwarding/Output MUX assign forward_rs1 = should_forward_rs1 && is_instr_csr_or_fence_rs1;
always_comb begin : forwarding_operand_select assign forward_rs2 = should_forward_rs2 && is_instr_csr_or_fence_rs2;
// default is regfiles (gpr or fpr) assign forward_rs3 = should_forward_rs3 && rs3_valid_i;
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
// use the zimm as operand a // Forwarding/Output MUX
if (issue_instr_i.use_zimm) begin assign operand_a_n = (issue_instr_i.use_zimm) ? {{riscv::XLEN-5{1'b0}}, issue_instr_i.rs1[4:0]} :
// zero extend operand a (issue_instr_i.use_pc) ? {{riscv::XLEN-riscv::VLEN{issue_instr_i.pc[riscv::VLEN-1]}}, issue_instr_i.pc} :
operand_a_n = {{riscv::XLEN-5{1'b0}}, issue_instr_i.rs1[4:0]}; (forward_rs1) ? rs1_i : operand_a_regfile;
end 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 :
// or is it an immediate (including PC), this is not the case for a store and control flow instructions (forward_rs2) ? rs2_i : operand_b_regfile;
// 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 assign imm_n = (forward_rs3) ? {{riscv::XLEN-FLEN{1'b0}}, rs3_i} :
operand_b_n = issue_instr_i.result; issue_instr_i.use_imm_fpr ? {{riscv::XLEN-FLEN{1'b0}}, operand_c_regfile} :
end issue_instr_i.result;
end 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) // 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. // 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::*; #( ...@@ -299,47 +239,65 @@ module issue_read_operands import ariane_pkg::*; #(
end end
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 // We can issue an instruction if we do not detect that any other instruction is writing the same
// destination register. // destination register.
// We also need to check if there is an unresolved branch in the scoreboard. // We also need to check if there is an unresolved branch in the scoreboard.
always_comb begin : issue_scoreboard // always_comb begin : issue_scoreboard
// default assignment // // default assignment
issue_ack_o = 1'b0; // issue_ack_o = 1'b0;
// check that we didn't stall, that the instruction we got is valid // // check that we didn't stall, that the instruction we got is valid
// and that the functional unit we need is not busy // // and that the functional unit we need is not busy
if (issue_instr_valid_i) begin // if (issue_instr_valid_i) begin
// check that the corresponding functional unit is not busy // // check that the corresponding functional unit is not busy
if (!stall && !fu_busy) begin // if (!stall && !fu_busy) begin
// ----------------------------------------- // // -----------------------------------------
// WAW - Write After Write Dependency Check // // WAW - Write After Write Dependency Check
// ----------------------------------------- // // -----------------------------------------
// no other instruction has the same destination register -> issue the instruction // // 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) // 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 // : (rd_clobber_gpr_i[issue_instr_i.rd] == NONE)) begin
issue_ack_o = 1'b1; // issue_ack_o = 1'b1;
end // end
// or check that the target destination register will be written in this cycle by the // // or check that the target destination register will be written in this cycle by the
// commit stage // // commit stage
for (int unsigned i = 0; i < NR_COMMIT_PORTS; i++) // 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) // 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 // : (we_gpr_i[i] && waddr_i[i] == issue_instr_i.rd)) begin
issue_ack_o = 1'b1; // issue_ack_o = 1'b1;
end // end
end // end
// we can also issue the instruction under the following two circumstances: // // 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) // // 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 // // 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. // // need any functional unit or if an exception occurred previous to the execute stage.
// 1. we already got an exception // // 1. we already got an exception
if (issue_instr_i.ex.valid) begin // if (issue_instr_i.ex.valid) begin
issue_ack_o = 1'b1; // issue_ack_o = 1'b1;
end // end
// 2. it is an instruction which does not need any functional unit // // 2. it is an instruction which does not need any functional unit
if (issue_instr_i.fu == NONE) begin // if (issue_instr_i.fu == NONE) begin
issue_ack_o = 1'b1; // issue_ack_o = 1'b1;
end // end
end // end
end // end
// ---------------------- // ----------------------
// Integer Register File // Integer Register File
...@@ -408,8 +366,8 @@ module issue_read_operands import ariane_pkg::*; #( ...@@ -408,8 +366,8 @@ module issue_read_operands import ariane_pkg::*; #(
end end
endgenerate endgenerate
assign operand_a_regfile = is_rs1_fpr(issue_instr_i.op) ? {{riscv::XLEN-FLEN{1'b0}}, fprdata[0]} : rdata[0]; assign operand_a_regfile = issue_instr_i.use_rs1_fpr ? {{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_b_regfile = issue_instr_i.use_rs2_fpr ? {{riscv::XLEN-FLEN{1'b0}}, fprdata[1]} : rdata[1];
assign operand_c_regfile = fprdata[2]; assign operand_c_regfile = fprdata[2];
// ---------------------- // ----------------------
......
...@@ -82,15 +82,12 @@ module issue_stage import ariane_pkg::*; #( ...@@ -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_gpr_sb_iro;
fu_t [2**REG_ADDR_SIZE-1:0] rd_clobber_fpr_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; riscv::xlen_t rs1_sb_iro;
logic rs1_valid_sb_iro; logic rs1_valid_sb_iro;
logic [REG_ADDR_SIZE-1:0] rs2_iro_sb;
riscv::xlen_t rs2_sb_iro; riscv::xlen_t rs2_sb_iro;
logic rs2_valid_iro_sb; logic rs2_valid_iro_sb;
logic [REG_ADDR_SIZE-1:0] rs3_iro_sb;
logic [FLEN-1:0] rs3_sb_iro; logic [FLEN-1:0] rs3_sb_iro;
logic rs3_valid_iro_sb; logic rs3_valid_iro_sb;
...@@ -130,13 +127,10 @@ module issue_stage import ariane_pkg::*; #( ...@@ -130,13 +127,10 @@ module issue_stage import ariane_pkg::*; #(
.unresolved_branch_i ( 1'b0 ), .unresolved_branch_i ( 1'b0 ),
.rd_clobber_gpr_o ( rd_clobber_gpr_sb_iro ), .rd_clobber_gpr_o ( rd_clobber_gpr_sb_iro ),
.rd_clobber_fpr_o ( rd_clobber_fpr_sb_iro ), .rd_clobber_fpr_o ( rd_clobber_fpr_sb_iro ),
.rs1_i ( rs1_iro_sb ),
.rs1_o ( rs1_sb_iro ), .rs1_o ( rs1_sb_iro ),
.rs1_valid_o ( rs1_valid_sb_iro ), .rs1_valid_o ( rs1_valid_sb_iro ),
.rs2_i ( rs2_iro_sb ),
.rs2_o ( rs2_sb_iro ), .rs2_o ( rs2_sb_iro ),
.rs2_valid_o ( rs2_valid_iro_sb ), .rs2_valid_o ( rs2_valid_iro_sb ),
.rs3_i ( rs3_iro_sb ),
.rs3_o ( rs3_sb_iro ), .rs3_o ( rs3_sb_iro ),
.rs3_valid_o ( rs3_valid_iro_sb ), .rs3_valid_o ( rs3_valid_iro_sb ),
...@@ -166,13 +160,10 @@ module issue_stage import ariane_pkg::*; #( ...@@ -166,13 +160,10 @@ module issue_stage import ariane_pkg::*; #(
.issue_ack_o ( issue_ack_iro_sb ), .issue_ack_o ( issue_ack_iro_sb ),
.fu_data_o ( fu_data_o ), .fu_data_o ( fu_data_o ),
.flu_ready_i ( flu_ready_i ), .flu_ready_i ( flu_ready_i ),
.rs1_o ( rs1_iro_sb ),
.rs1_i ( rs1_sb_iro ), .rs1_i ( rs1_sb_iro ),
.rs1_valid_i ( rs1_valid_sb_iro ), .rs1_valid_i ( rs1_valid_sb_iro ),
.rs2_o ( rs2_iro_sb ),
.rs2_i ( rs2_sb_iro ), .rs2_i ( rs2_sb_iro ),
.rs2_valid_i ( rs2_valid_iro_sb ), .rs2_valid_i ( rs2_valid_iro_sb ),
.rs3_o ( rs3_iro_sb ),
.rs3_i ( rs3_sb_iro ), .rs3_i ( rs3_sb_iro ),
.rs3_valid_i ( rs3_valid_iro_sb ), .rs3_valid_i ( rs3_valid_iro_sb ),
.rd_clobber_gpr_i ( rd_clobber_gpr_sb_iro ), .rd_clobber_gpr_i ( rd_clobber_gpr_sb_iro ),
......
...@@ -28,15 +28,12 @@ module scoreboard #( ...@@ -28,15 +28,12 @@ module scoreboard #(
output ariane_pkg::fu_t [2**ariane_pkg::REG_ADDR_SIZE-1:0] rd_clobber_fpr_o, output ariane_pkg::fu_t [2**ariane_pkg::REG_ADDR_SIZE-1:0] rd_clobber_fpr_o,
// regfile like interface to operand read stage // 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 riscv::xlen_t rs1_o,
output logic rs1_valid_o, output logic rs1_valid_o,
input logic [ariane_pkg::REG_ADDR_SIZE-1:0] rs2_i,
output riscv::xlen_t rs2_o, output riscv::xlen_t rs2_o,
output logic rs2_valid_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 [ariane_pkg::FLEN-1:0] rs3_o,
output logic rs3_valid_o, output logic rs3_valid_o,
...@@ -76,7 +73,7 @@ module scoreboard #( ...@@ -76,7 +73,7 @@ module scoreboard #(
} mem_q [NR_ENTRIES-1:0], mem_n [NR_ENTRIES-1:0]; } mem_q [NR_ENTRIES-1:0], mem_n [NR_ENTRIES-1:0];
logic issue_full, issue_en; 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] write_pointer_n, write_pointer_q;
logic [BITS_ENTRIES-1:0] issue_pointer_n, issue_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; logic [NR_COMMIT_PORTS-1:0][BITS_ENTRIES-1:0] commit_pointer_n, commit_pointer_q;
...@@ -89,7 +86,7 @@ module scoreboard #( ...@@ -89,7 +86,7 @@ module scoreboard #(
// the issue queue is full don't issue any new instructions // the issue queue is full don't issue any new instructions
// works since aligned to power of 2 // 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; assign sb_full_o = issue_full;
...@@ -124,7 +121,8 @@ module scoreboard #( ...@@ -124,7 +121,8 @@ module scoreboard #(
// decoded_instr_ack_o = 1'b1; // decoded_instr_ack_o = 1'b1;
mem_n[write_pointer_q] = {1'b1, mem_n[write_pointer_q] = {1'b1,
1'b1, // valid bit 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 decoded_instr_i // decoded instruction record
}; };
has_mem_access_n[write_pointer_q] = decoded_instr_i.fu inside {ariane_pkg::LOAD, ariane_pkg::STORE}; has_mem_access_n[write_pointer_q] = decoded_instr_i.fu inside {ariane_pkg::LOAD, ariane_pkg::STORE};
...@@ -289,17 +287,22 @@ module scoreboard #( ...@@ -289,17 +287,22 @@ module scoreboard #(
logic [NR_ENTRIES+NR_WB_PORTS-1:0][riscv::XLEN-1:0] rs_data; logic [NR_ENTRIES+NR_WB_PORTS-1:0][riscv::XLEN-1:0] rs_data;
logic rs1_valid, rs2_valid; 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 // WB ports have higher prio than entries
for (genvar k = 0; unsigned'(k) < NR_WB_PORTS; k++) begin : gen_rs_wb 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 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_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 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_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 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]; assign rs_data[k] = wbdata_i[k];
end end
for (genvar k = 0; unsigned'(k) < NR_ENTRIES; k++) begin : gen_rs_entries 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 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_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 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_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 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; assign rs_data[k+NR_WB_PORTS] = mem_q[k].sbe.result;
end end
...@@ -339,8 +342,8 @@ module scoreboard #( ...@@ -339,8 +342,8 @@ module scoreboard #(
assign rs3_o = (rs3_valid_o) ? rs_data[rs3_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! // 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 rs1_valid_o = rs1_valid & ((|rs1) | issue_instr_o.use_rs1_fpr);
assign rs2_valid_o = rs2_valid & ((|rs2_i) | ariane_pkg::is_rs2_fpr(issue_instr_o.op)); assign rs2_valid_o = rs2_valid & ((|rs2) | issue_instr_o.use_rs2_fpr);
// sequential process // sequential process
always_ff @(posedge clk_i or negedge rst_ni) begin : regs always_ff @(posedge clk_i or negedge rst_ni) begin : regs
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment