diff --git a/src/scoreboard.sv b/src/scoreboard.sv index a20b0ef1cabe3b5ba59230f1ce2f8e3cc7fc021a..92254af99c0b4c1cdc40605cdcf8bdaedf2a4acf 100644 --- a/src/scoreboard.sv +++ b/src/scoreboard.sv @@ -69,6 +69,7 @@ module scoreboard #( // this is the FIFO struct of the issue queue struct packed { + logic pending; // this bit indicates whether the instruction has still not reached EX logic issued; // this bit indicates whether we issued this instruction e.g.: if it is valid logic is_rd_fpr_flag; // redundant meta info, added for speed ariane_pkg::scoreboard_entry_t sbe; // this is the score board entry we will send to ex @@ -76,10 +77,14 @@ module scoreboard #( logic issue_full, issue_en; logic [BITS_ENTRIES-1: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; logic [$clog2(NR_COMMIT_PORTS):0] num_commit; + logic [NR_ENTRIES-1:0] flushed; + logic [$clog2(NR_ENTRIES)-1:0] num_flush; + logic [NR_ENTRIES-1:0] has_mem_access_n, has_mem_access_q; // the issue queue is full don't issue any new instructions @@ -99,17 +104,6 @@ module scoreboard #( // check instructions in the scoreboard for memory operations assign has_mem_access_o = (|has_mem_access_q); - // an instruction is ready for issue if we have place in the issue FIFO and it the decoder says it is valid - always_comb begin - issue_instr_o = decoded_instr_i; - // make sure we assign the correct trans ID - issue_instr_o.trans_id = issue_pointer_q; - // we are ready if we are not full and don't have any unresolved branches, but it can be - // the case that we have an unresolved branch which is cleared in that cycle (resolved_branch_i == 1) - issue_instr_valid_o = decoded_instr_valid_i & ~unresolved_branch_i & ~issue_full; - decoded_instr_ack_o = issue_ack_i & ~issue_full; - end - // maintain a FIFO with issued instructions // keep track of all issued instructions always_comb begin : issue_fifo @@ -117,17 +111,42 @@ module scoreboard #( mem_n = mem_q; issue_en = 1'b0; has_mem_access_n = has_mem_access_q; + decoded_instr_ack_o = 1'b0; + flushed = '0; + + decoded_instr_ack_o = decoded_instr_valid_i && ~issue_full; // if we got a acknowledge from the issue stage, put this scoreboard entry in the queue - if (decoded_instr_valid_i && decoded_instr_ack_o && !flush_unissued_instr_i) begin + if (decoded_instr_valid_i && ~issue_full && !flush_unissued_instr_i) begin // the decoded instruction we put in there is valid (1st bit) // increase the issue counter and advance issue pointer issue_en = 1'b1; - mem_n[issue_pointer_q] = {1'b1, // valid bit + // 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 // decoded instruction record }; - has_mem_access_n[issue_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}; + end + + issue_instr_o = mem_n[issue_pointer_q]; + issue_instr_o.trans_id = issue_pointer_q; + issue_instr_valid_o = mem_n[issue_pointer_q].pending & !flush_unissued_instr_i; + + if (issue_ack_i) begin + mem_n[issue_pointer_q].pending = 1'b0; + end + + if (flush_unissued_instr_i) begin + for (int unsigned i = 0; i < NR_ENTRIES; i++) begin + if (mem_q[i].pending) begin + mem_n[i].pending = 1'b0; + mem_n[i].issued = 1'b0; + flushed[i] = 1'b1; + has_mem_access_n[i] = 1'b0; + end + end end // ------------ @@ -135,7 +154,7 @@ module scoreboard #( // ------------ for (int unsigned i = 0; i < NR_ENTRIES; i++) begin // The FU is NONE -> this instruction is valid immediately - if (mem_q[i].sbe.fu == ariane_pkg::NONE && mem_q[i].issued) + if (mem_q[i].sbe.fu == ariane_pkg::NONE && mem_q[i].issued && ~mem_q[i].pending) mem_n[i].sbe.valid = 1'b1; end @@ -145,7 +164,7 @@ module scoreboard #( for (int unsigned i = 0; i < NR_WB_PORTS; i++) begin // check if this instruction was issued (e.g.: it could happen after a flush that there is still // something in the pipeline e.g. an incomplete memory operation) - if (wt_valid_i[i] && mem_q[trans_id_i[i]].issued) begin + if (wt_valid_i[i] && mem_q[trans_id_i[i]].issued && ~mem_q[trans_id_i[i]].pending) begin mem_n[trans_id_i[i]].sbe.valid = 1'b1; mem_n[trans_id_i[i]].sbe.result = wbdata_i[i]; // save the target address of a branch (needed for debug in commit stage) @@ -169,6 +188,7 @@ module scoreboard #( for (logic [BITS_ENTRIES-1:0] i = 0; i < NR_COMMIT_PORTS; i++) begin if (commit_ack_i[i]) begin // this instruction is no longer in issue e.g.: it is considered finished + mem_n[commit_pointer_q[i]].pending = 1'b0; mem_n[commit_pointer_q[i]].issued = 1'b0; mem_n[commit_pointer_q[i]].sbe.valid = 1'b0; has_mem_access_n[commit_pointer_q[i]] = 1'b0; @@ -181,6 +201,7 @@ module scoreboard #( if (flush_i) begin for (int unsigned i = 0; i < NR_ENTRIES; i++) begin // set all valid flags for all entries to zero + mem_n[i].pending = 1'b0; mem_n[i].issued = 1'b0; mem_n[i].sbe.valid = 1'b0; mem_n[i].sbe.ex.valid = 1'b0; @@ -190,16 +211,24 @@ module scoreboard #( end // FIFO counter updates + popcount #( + .INPUT_WIDTH(NR_ENTRIES) + ) i_popcount_flush ( + .data_i(flushed), + .popcount_o(num_flush) + ); + popcount #( .INPUT_WIDTH(NR_COMMIT_PORTS) - ) i_popcount ( + ) i_popcount_commit ( .data_i(commit_ack_i), .popcount_o(num_commit) ); - assign issue_cnt_n = (flush_i) ? '0 : issue_cnt_q - num_commit + issue_en; + assign issue_cnt_n = (flush_i) ? '0 : issue_cnt_q - num_commit - num_flush + issue_en; assign commit_pointer_n[0] = (flush_i) ? '0 : commit_pointer_q[0] + num_commit; - assign issue_pointer_n = (flush_i) ? '0 : issue_pointer_q + issue_en; + assign issue_pointer_n = (flush_i) ? '0 : issue_pointer_q + issue_ack_i; + assign write_pointer_n = (flush_i) ? '0 : write_pointer_q - num_flush + issue_en; // precompute offsets for commit slots for (genvar k=1; k < NR_COMMIT_PORTS; k++) begin : gen_cnt_incr @@ -227,8 +256,8 @@ module scoreboard #( // 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].issued & ~mem_q[i].is_rd_fpr_flag; - fpr_clobber_vld[mem_q[i].sbe.rd][i] = mem_q[i].issued & mem_q[i].is_rd_fpr_flag; + 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; end @@ -292,9 +321,9 @@ module scoreboard #( 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].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].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].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_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 rs_data[k+NR_WB_PORTS] = mem_q[k].sbe.result; end @@ -372,10 +401,12 @@ module scoreboard #( issue_cnt_q <= '0; commit_pointer_q <= '0; issue_pointer_q <= '0; + write_pointer_q <= '0; has_mem_access_q <= '0; end else begin issue_cnt_q <= issue_cnt_n; issue_pointer_q <= issue_pointer_n; + write_pointer_q <= write_pointer_n; mem_q <= mem_n; commit_pointer_q <= commit_pointer_n; has_mem_access_q <= has_mem_access_n;