This commit is contained in:
Riccardo Tedeschi 2025-04-22 14:47:48 +02:00 committed by GitHub
commit 983e670bc8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 76 additions and 140 deletions

View file

@ -23,8 +23,8 @@ valid_cycles = {
"dhrystone_single": 24127,
"coremark_dual": 1001191,
"coremark_single": 1300030,
"dhrystone_cv32a65x": 31976,
"dhrystone_cv32a60x": 39449,
"dhrystone_cv32a65x": 30056,
"dhrystone_cv32a60x": 37474,
}
for arg in sys.argv[1:]:

View file

@ -136,7 +136,9 @@ module issue_read_operands
logic none, load, store, alu, alu2, ctrl_flow, mult, csr, fpu, fpu_vec, cvxif, accel;
} fus_busy_t;
logic [CVA6Cfg.NrIssuePorts-1:0] stall_raw, stall_waw, stall_rs1, stall_rs2, stall_rs3;
typedef logic [CVA6Cfg.TRANS_ID_BITS:0] clobber_t;
logic [CVA6Cfg.NrIssuePorts-1:0] stall_raw, stall_rs1, stall_rs2, stall_rs3;
logic [CVA6Cfg.NrIssuePorts-1:0] fu_busy; // functional unit is busy
fus_busy_t [CVA6Cfg.NrIssuePorts-1:0] fus_busy; // which functional units are considered busy
logic [CVA6Cfg.NrIssuePorts-1:0] issue_ack;
@ -182,10 +184,17 @@ module issue_read_operands
logic [CVA6Cfg.NrIssuePorts-1:0][CVA6Cfg.XLEN-1:0] rs3_res;
// clobber
fu_t [2**ariane_pkg::REG_ADDR_SIZE-1:0] rd_clobber_gpr, rd_clobber_fpr;
logic [2**ariane_pkg::REG_ADDR_SIZE-1:0][CVA6Cfg.NR_SB_ENTRIES:0] gpr_clobber_vld;
logic [2**ariane_pkg::REG_ADDR_SIZE-1:0][CVA6Cfg.NR_SB_ENTRIES:0] fpr_clobber_vld;
ariane_pkg::fu_t [ CVA6Cfg.NR_SB_ENTRIES:0] clobber_fu;
clobber_t [2**ariane_pkg::REG_ADDR_SIZE-1:0] rd_clobber_gpr, rd_clobber_fpr;
// Csr issued check
logic [CVA6Cfg.NR_SB_ENTRIES-1:0] csr_issued_raw;
logic [ CVA6Cfg.NR_SB_ENTRIES:0] csr_issued;
for (genvar i = 0; i < CVA6Cfg.NR_SB_ENTRIES; i++) begin
assign csr_issued_raw[i] = fwd_i.still_issued[i] && fwd_i.sbe[i].fu == ariane_pkg::CSR;
end
assign csr_issued = {1'b0, csr_issued_raw};
//forward logic
logic [CVA6Cfg.NrIssuePorts-1:0][CVA6Cfg.NR_SB_ENTRIES+CVA6Cfg.NrWbPorts-1:0]
@ -246,7 +255,7 @@ module issue_read_operands
// TODO check only for 1st instruction ??
// Allow a cvxif transaction if we WaW condition are ok.
assign cvxif_req_allowed = (issue_instr_i[0].fu == CVXIF) && !stall_waw[0];
assign cvxif_req_allowed = (issue_instr_i[0].fu == CVXIF);
assign cvxif_instruction_valid = !issue_instr_i[0].ex.valid && issue_instr_valid_i[0] && cvxif_req_allowed;
assign x_transaction_accepted_o = x_issue_valid_o && x_issue_ready_i && x_issue_resp_i.accept;
assign x_transaction_rejected = x_issue_valid_o && x_issue_ready_i && ~x_issue_resp_i.accept;
@ -412,74 +421,32 @@ module issue_read_operands
// RD clobber process
// -------------------
// rd_clobber output: output currently clobbered destination registers
logic [2*CVA6Cfg.NR_SB_ENTRIES-1:0] still_issued_rotated_raw;
logic [ CVA6Cfg.NR_SB_ENTRIES-1:0] still_issued_rotated;
logic [ CVA6Cfg.TRANS_ID_BITS-1:0] unrotated_index;
assign still_issued_rotated_raw = {fwd_i.still_issued, fwd_i.still_issued} >> fwd_i.commit_pointer;
assign still_issued_rotated = still_issued_rotated_raw[CVA6Cfg.NR_SB_ENTRIES-1:0];
always_comb begin : clobber_assign
gpr_clobber_vld = '0;
fpr_clobber_vld = '0;
rd_clobber_gpr = '{default: clobber_t'(CVA6Cfg.NR_SB_ENTRIES)};
rd_clobber_fpr = '{default: clobber_t'(CVA6Cfg.NR_SB_ENTRIES)};
// default (highest entry hast lowest prio in arbiter tree below)
clobber_fu[CVA6Cfg.NR_SB_ENTRIES] = ariane_pkg::NONE;
for (int unsigned i = 0; i < 2 ** ariane_pkg::REG_ADDR_SIZE; i++) begin
gpr_clobber_vld[i][CVA6Cfg.NR_SB_ENTRIES] = 1'b1;
fpr_clobber_vld[i][CVA6Cfg.NR_SB_ENTRIES] = 1'b1;
end
// check for all valid entries and set the clobber accordingly
unrotated_index = '0;
for (int unsigned i = 0; i < CVA6Cfg.NR_SB_ENTRIES; i++) begin
gpr_clobber_vld[fwd_i.sbe[i].rd][i] = fwd_i.still_issued[i] & ~(CVA6Cfg.FpPresent && ariane_pkg::is_rd_fpr(
fwd_i.sbe[i].op));
fpr_clobber_vld[fwd_i.sbe[i].rd][i] = fwd_i.still_issued[i] & (CVA6Cfg.FpPresent && ariane_pkg::is_rd_fpr(
fwd_i.sbe[i].op));
clobber_fu[i] = fwd_i.sbe[i].fu;
unrotated_index = i + fwd_i.commit_pointer;
if (still_issued_rotated[i]) begin
if (~(CVA6Cfg.FpPresent && ariane_pkg::is_rd_fpr(fwd_i.sbe[unrotated_index].op))) begin
rd_clobber_gpr[fwd_i.sbe[unrotated_index].rd] = clobber_t'(unrotated_index[CVA6Cfg.TRANS_ID_BITS-1:0]);
end else begin
rd_clobber_fpr[fwd_i.sbe[unrotated_index].rd] = clobber_t'(unrotated_index[CVA6Cfg.TRANS_ID_BITS-1:0]);
end
end
end
// GPR[0] is always free
gpr_clobber_vld[0] = '0;
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(CVA6Cfg.NR_SB_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[k]),
.idx_o ()
);
if (CVA6Cfg.FpPresent) begin
rr_arb_tree #(
.NumIn(CVA6Cfg.NR_SB_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[k]),
.idx_o ()
);
end else begin
assign rd_clobber_fpr[k] = NONE;
end
rd_clobber_gpr[0] = clobber_t'(CVA6Cfg.NR_SB_ENTRIES);
end
// ----------------------------------
@ -491,47 +458,48 @@ module issue_read_operands
for (genvar i = 0; i < CVA6Cfg.NrIssuePorts; i++) begin
for (genvar k = 0; unsigned'(k) < CVA6Cfg.NrWbPorts; k++) begin : gen_rs_wb
assign rs1_fwd_req[i][k] = (fwd_i.sbe[fwd_i.wb[k].trans_id].rd == issue_instr_i[i].rs1) & (fwd_i.still_issued[fwd_i.wb[k].trans_id]) & fwd_i.wb[k].valid & (~fwd_i.wb[k].ex_valid) & ((CVA6Cfg.FpPresent && ariane_pkg::is_rd_fpr(
fwd_i.sbe[fwd_i.wb[k].trans_id].op
)) == (CVA6Cfg.FpPresent && ariane_pkg::is_rs1_fpr(
assign rs1_fwd_req[i][k] = ((clobber_t'(fwd_i.wb[k].trans_id) == rd_clobber_gpr[issue_instr_i[i].rs1] && (!ariane_pkg::is_rs1_fpr(
issue_instr_i[i].op
)));
assign rs2_fwd_req[i][k] = (fwd_i.sbe[fwd_i.wb[k].trans_id].rd == issue_instr_i[i].rs2) & (fwd_i.still_issued[fwd_i.wb[k].trans_id]) & fwd_i.wb[k].valid & (~fwd_i.wb[k].ex_valid) & ((CVA6Cfg.FpPresent && ariane_pkg::is_rd_fpr(
fwd_i.sbe[fwd_i.wb[k].trans_id].op
)) == (CVA6Cfg.FpPresent && ariane_pkg::is_rs2_fpr(
))) || (clobber_t'(fwd_i.wb[k].trans_id) == rd_clobber_fpr[issue_instr_i[i].rs1] &&
(CVA6Cfg.FpPresent && ariane_pkg::is_rs1_fpr(
issue_instr_i[i].op
)));
assign rs3_fwd_req[i][k] = (fwd_i.sbe[fwd_i.wb[k].trans_id].rd == issue_instr_i[i].result[ariane_pkg::REG_ADDR_SIZE-1:0]) & (fwd_i.still_issued[fwd_i.wb[k].trans_id]) & fwd_i.wb[k].valid & (~fwd_i.wb[k].ex_valid) & ((CVA6Cfg.FpPresent && ariane_pkg::is_rd_fpr(
fwd_i.sbe[fwd_i.wb[k].trans_id].op
)) == (CVA6Cfg.FpPresent && ariane_pkg::is_imm_fpr(
)))) & fwd_i.wb[k].valid & (~fwd_i.wb[k].ex_valid);
assign rs2_fwd_req[i][k] = ((clobber_t'(fwd_i.wb[k].trans_id) == rd_clobber_gpr[issue_instr_i[i].rs2] && (!ariane_pkg::is_rs2_fpr(
issue_instr_i[i].op
)));
))) || (clobber_t'(fwd_i.wb[k].trans_id) == rd_clobber_fpr[issue_instr_i[i].rs2] &&
(CVA6Cfg.FpPresent && ariane_pkg::is_rs2_fpr(
issue_instr_i[i].op
)))) & fwd_i.wb[k].valid & (~fwd_i.wb[k].ex_valid);
assign rs3_fwd_req[i][k] = ((clobber_t'(fwd_i.wb[k].trans_id) == rd_clobber_gpr[issue_instr_i[i].result[ariane_pkg::REG_ADDR_SIZE-1:0]] && (!ariane_pkg::is_imm_fpr(
issue_instr_i[i].op
))) || (clobber_t'(fwd_i.wb[k].trans_id) ==
rd_clobber_fpr[issue_instr_i[i].result[ariane_pkg::REG_ADDR_SIZE-1:0]] &&
(CVA6Cfg.FpPresent && ariane_pkg::is_imm_fpr(
issue_instr_i[i].op
)))) & fwd_i.wb[k].valid & (~fwd_i.wb[k].ex_valid);
assign rs_data[i][k] = fwd_i.wb[k].data;
end
for (genvar k = 0; unsigned'(k) < CVA6Cfg.NR_SB_ENTRIES; k++) begin : gen_rs_entries
assign rs1_fwd_req[i][k+CVA6Cfg.NrWbPorts] = (fwd_i.sbe[k].rd == issue_instr_i[i].rs1) & fwd_i.still_issued[k] & fwd_i.sbe[k].valid & ((CVA6Cfg.FpPresent && ariane_pkg::is_rd_fpr(
fwd_i.sbe[k].op
)) == (CVA6Cfg.FpPresent && ariane_pkg::is_rs1_fpr(
assign rs1_fwd_req[i][k+CVA6Cfg.NrWbPorts] = ((rd_clobber_gpr[issue_instr_i[i].rs1] == clobber_t'(k) &&(!ariane_pkg::is_rs1_fpr(
issue_instr_i[i].op
)));
assign rs2_fwd_req[i][k+CVA6Cfg.NrWbPorts] = (fwd_i.sbe[k].rd == issue_instr_i[i].rs2) & fwd_i.still_issued[k] & fwd_i.sbe[k].valid & ((CVA6Cfg.FpPresent && ariane_pkg::is_rd_fpr(
fwd_i.sbe[k].op
)) == (CVA6Cfg.FpPresent && ariane_pkg::is_rs2_fpr(
))) || (rd_clobber_fpr[issue_instr_i[i].rs1] == clobber_t'(k) &&
(CVA6Cfg.FpPresent && ariane_pkg::is_rs1_fpr(
issue_instr_i[i].op
)));
assign rs3_fwd_req[i][k+CVA6Cfg.NrWbPorts] = (fwd_i.sbe[k].rd == issue_instr_i[i].result[ariane_pkg::REG_ADDR_SIZE-1:0]) & fwd_i.still_issued[k] & fwd_i.sbe[k].valid & ((CVA6Cfg.FpPresent && ariane_pkg::is_rd_fpr(
fwd_i.sbe[k].op
)) == (CVA6Cfg.FpPresent && ariane_pkg::is_imm_fpr(
)))) & fwd_i.still_issued[k] & fwd_i.sbe[k].valid;
assign rs2_fwd_req[i][k+CVA6Cfg.NrWbPorts] = ((rd_clobber_gpr[issue_instr_i[i].rs2] == clobber_t'(k) && (!ariane_pkg::is_rs2_fpr(
issue_instr_i[i].op
)));
))) || (rd_clobber_fpr[issue_instr_i[i].rs2] == clobber_t'(k) &&
(CVA6Cfg.FpPresent && ariane_pkg::is_rs2_fpr(
issue_instr_i[i].op
)))) & fwd_i.still_issued[k] & fwd_i.sbe[k].valid;
assign rs3_fwd_req[i][k+CVA6Cfg.NrWbPorts] = ((rd_clobber_gpr[issue_instr_i[i].result[ariane_pkg::REG_ADDR_SIZE-1:0]] == clobber_t'(k) && (!ariane_pkg::is_imm_fpr(
issue_instr_i[i].op
))) || (rd_clobber_fpr[issue_instr_i[i].result[ariane_pkg::REG_ADDR_SIZE-1:0]] ==
clobber_t'(k) && (CVA6Cfg.FpPresent && ariane_pkg::is_imm_fpr(
issue_instr_i[i].op
)))) & fwd_i.still_issued[k] & fwd_i.sbe[k].valid;
assign rs_data[i][k+CVA6Cfg.NrWbPorts] = fwd_i.sbe[k].result;
end
@ -603,27 +571,27 @@ module issue_read_operands
assign rs1_has_raw[i] = !issue_instr_i[i].use_zimm && ((CVA6Cfg.FpPresent && is_rs1_fpr(
issue_instr_i[i].op
)) ? rd_clobber_fpr[issue_instr_i[i].rs1] != NONE :
rd_clobber_gpr[issue_instr_i[i].rs1] != NONE);
)) ? rd_clobber_fpr[issue_instr_i[i].rs1] != clobber_t'(CVA6Cfg.NR_SB_ENTRIES) :
rd_clobber_gpr[issue_instr_i[i].rs1] != clobber_t'(CVA6Cfg.NR_SB_ENTRIES));
assign rs1_valid[i] = rs1_available[i] && (CVA6Cfg.FpPresent && is_rs1_fpr(
issue_instr_i[i].op
) ? 1'b1 : ((rd_clobber_gpr[issue_instr_i[i].rs1] != CSR) ||
) ? 1'b1 : (!(csr_issued[rd_clobber_gpr[issue_instr_i[i].rs1]]) ||
(CVA6Cfg.RVS && issue_instr_i[i].op == SFENCE_VMA)));
assign rs2_has_raw[i] = ((CVA6Cfg.FpPresent && is_rs2_fpr(
issue_instr_i[i].op
)) ? rd_clobber_fpr[issue_instr_i[i].rs2] != NONE :
rd_clobber_gpr[issue_instr_i[i].rs2] != NONE);
)) ? rd_clobber_fpr[issue_instr_i[i].rs2] != clobber_t'(CVA6Cfg.NR_SB_ENTRIES) :
rd_clobber_gpr[issue_instr_i[i].rs2] != clobber_t'(CVA6Cfg.NR_SB_ENTRIES));
assign rs2_valid[i] = rs2_available[i] && (CVA6Cfg.FpPresent && is_rs2_fpr(
issue_instr_i[i].op
) ? 1'b1 : ((rd_clobber_gpr[issue_instr_i[i].rs2] != CSR) ||
) ? 1'b1 : (!(csr_issued[rd_clobber_gpr[issue_instr_i[i].rs2]]) ||
(CVA6Cfg.RVS && issue_instr_i[i].op == SFENCE_VMA)));
assign rs3_has_raw[i] = ((CVA6Cfg.FpPresent && is_imm_fpr(
issue_instr_i[i].op
)) ? rd_clobber_fpr[issue_instr_i[i].result[REG_ADDR_SIZE-1:0]] != NONE : 0);
)) ? rd_clobber_fpr[issue_instr_i[i].result[REG_ADDR_SIZE-1:0]] != CVA6Cfg.NR_SB_ENTRIES : 0);
assign rs3_valid[i] = rs3_available[i];
assign rs3_fpr[i] = (CVA6Cfg.FpPresent && ariane_pkg::is_imm_fpr(issue_instr_i[i].op));
@ -902,40 +870,6 @@ module issue_read_operands
end
end
always_comb begin : gen_check_waw_dependencies
stall_waw = '1;
for (int unsigned i = 0; i < CVA6Cfg.NrIssuePorts; i++) begin
if (issue_instr_valid_i[i] && !fu_busy[i]) begin
// -----------------------------------------
// WAW - Write After Write Dependency Check
// -----------------------------------------
// no other instruction has the same destination register -> issue the instruction
if ((CVA6Cfg.FpPresent && ariane_pkg::is_rd_fpr(
issue_instr_i[i].op
)) ? (rd_clobber_fpr[issue_instr_i[i].rd] == NONE) :
(rd_clobber_gpr[issue_instr_i[i].rd] == NONE)) begin
stall_waw[i] = 1'b0;
end
// or check that the target destination register will be written in this cycle by the
// commit stage
for (int unsigned c = 0; c < CVA6Cfg.NrCommitPorts; c++) begin
if ((CVA6Cfg.FpPresent && ariane_pkg::is_rd_fpr(
issue_instr_i[i].op
)) ? (we_fpr_i[c] && waddr_i[c] == issue_instr_i[i].rd) :
(we_gpr_i[c] && waddr_i[c] == issue_instr_i[i].rd)) begin
stall_waw[i] = 1'b0;
end
end
if (i > 0) begin
if ((issue_instr_i[i].rd == issue_instr_i[i-1].rd) && (issue_instr_i[i].rd != '0)) begin
stall_waw[i] = 1'b1;
end
end
end
end
end
// 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.
@ -946,7 +880,7 @@ module issue_read_operands
// check that the instruction we got is valid
// and that the functional unit we need is not busy
if (issue_instr_valid_i[i] && !fu_busy[i]) begin
if (!stall_raw[i] && !stall_waw[i]) begin
if (!stall_raw[i]) begin
issue_ack[i] = 1'b1;
end
if (issue_instr_i[i].ex.valid) begin

View file

@ -172,6 +172,7 @@ module issue_stage
typedef struct packed {
logic [CVA6Cfg.NR_SB_ENTRIES-1:0] still_issued;
logic [CVA6Cfg.TRANS_ID_BITS-1:0] issue_pointer;
logic [CVA6Cfg.TRANS_ID_BITS-1:0] commit_pointer;
writeback_t [CVA6Cfg.NrWbPorts-1:0] wb;
scoreboard_entry_t [CVA6Cfg.NR_SB_ENTRIES-1:0] sbe;
} forwarding_t;

View file

@ -295,6 +295,7 @@ module scoreboard #(
assign fwd_o.still_issued = still_issued;
assign fwd_o.issue_pointer = issue_pointer;
assign fwd_o.commit_pointer = commit_pointer_q[0];
assign fwd_o.wb = wb;
for (genvar i = 0; i < CVA6Cfg.NR_SB_ENTRIES; i++) begin
assign fwd_o.sbe[i] = mem_q[i].sbe;