diff --git a/core/decode_and_issue.sv b/core/decode_and_issue.sv index a29279f..1a4cd67 100755 --- a/core/decode_and_issue.sv +++ b/core/decode_and_issue.sv @@ -202,7 +202,7 @@ module decode_and_issue ( //All units share the same operand ready logic except load-store which has an internal forwarding path always_comb begin unit_operands_ready = {NUM_UNITS{operands_ready}}; - //unit_operands_ready[LS_UNIT_WB_ID] = ~rs1_conflict; + unit_operands_ready[LS_UNIT_WB_ID] = ~rs1_conflict; end assign issue_ready = unit_needed_issue_stage & unit_ready; @@ -344,7 +344,7 @@ module decode_and_issue ( assign ls_inputs.fn3 = amo_op ? LS_W_fn3 : issue.fn3; assign ls_inputs.rs1 = rs_data[RS1]; assign ls_inputs.rs2 = rs_data[RS2]; - assign ls_inputs.forwarded_store = 0;//rs2_conflict; + assign ls_inputs.forwarded_store = rs2_conflict; assign ls_inputs.store_forward_id = rs_id[RS2]; //////////////////////////////////////////////////// diff --git a/core/interfaces.sv b/core/interfaces.sv index 45898a0..b8ede81 100755 --- a/core/interfaces.sv +++ b/core/interfaces.sv @@ -202,17 +202,22 @@ interface load_store_queue_interface; endinterface interface writeback_store_interface; - id_t id_needed_at_issue; - id_t id_needed_at_commit; - id_t commit_id; - logic commit; - logic [MAX_IDS-1:0] hold_for_store_ids; + id_t id_needed; + logic possibly_waiting; + logic waiting; + logic ack; - logic forwarding_data_ready; - logic [31:0] forwarded_data; + logic id_done; + logic [31:0] data; - modport ls (input forwarding_data_ready, forwarded_data, output id_needed_at_issue, id_needed_at_commit, commit_id, commit, hold_for_store_ids); - modport wb (output forwarding_data_ready, forwarded_data, input id_needed_at_issue, id_needed_at_commit, commit_id, commit, hold_for_store_ids); + modport ls ( + input id_done, data, + output id_needed, possibly_waiting ,waiting, ack + ); + modport wb ( + input id_needed, possibly_waiting, waiting, ack, + output id_done, data + ); endinterface interface ls_sub_unit_interface #(parameter BASE_ADDR = 32'h00000000, parameter UPPER_BOUND = 32'hFFFFFFFF, parameter BIT_CHECK = 4); diff --git a/core/load_store_queue.sv b/core/load_store_queue.sv index 2f8bf32..c80be6d 100644 --- a/core/load_store_queue.sv +++ b/core/load_store_queue.sv @@ -33,15 +33,12 @@ module load_store_queue //ID-based input buffer for Load/Store Unit input logic gc_issue_flush, load_store_queue_interface.queue lsq, - output logic [MAX_IDS-1:0] wb_hold_for_store_ids, - //Writeback data - input logic [31:0] writeback_data, - input logic writeback_valid + writeback_store_interface.ls wb_store, + + output logic ready_for_forwarded_store ); logic [MAX_IDS-1:0] valid; - logic [$clog2(MAX_IDS)-1:0] hold_for_store_ids [MAX_IDS]; - logic [$clog2(MAX_IDS)-1:0] hold_for_store_ids_r [MAX_IDS]; id_t oldest_id; typedef struct packed { @@ -122,40 +119,46 @@ module load_store_queue //ID-based input buffer for Load/Store Unit // ); //////////////////////////////////////////////////// - //Counters for determining if an existing ID's data is needed for a store - //As mutiple stores could need the same ID, there is a counter for each ID. + //Store Forwarding Support + //Only a single store can be forwarded at any given time + //The needed result is registered at the writeback stage when the + //needed ID is retired. + logic possible_new_forwarded_store;//To help shorten logic path for registering results in the writeback stage logic new_forwarded_store; logic forwarded_store_complete; + id_t needed_id_r; + logic waiting_r; + assign possible_new_forwarded_store = lsq.possible_issue & lsq.forwarded_store; assign new_forwarded_store = lsq.new_issue & lsq.forwarded_store; assign forwarded_store_complete = lsq.accepted & oldest_lsq_entry.forwarded_store; - always_comb begin - hold_for_store_ids = hold_for_store_ids_r; - if (new_forwarded_store) - hold_for_store_ids[lsq.data_id] = hold_for_store_ids_r[lsq.data_id] + 1; - if (forwarded_store_complete) - hold_for_store_ids[oldest_lsq_entry.data_id] = hold_for_store_ids_r[oldest_lsq_entry.data_id] - 1; + always_ff @ (posedge clk) begin + if (rst) + waiting_r <= 0; + else + waiting_r <= new_forwarded_store | (waiting_r & ~wb_store.id_done); end + assign wb_store.waiting = new_forwarded_store | waiting_r; + assign wb_store.possibly_waiting = possible_new_forwarded_store | waiting_r; + + assign wb_store.ack = forwarded_store_complete; + assign ready_for_forwarded_store = ~(waiting_r | wb_store.id_done); always_ff @ (posedge clk) begin - if (rst | gc_issue_flush) - hold_for_store_ids_r <= '{default: 0}; - else - hold_for_store_ids_r <= hold_for_store_ids; + if (new_forwarded_store) + needed_id_r <= lsq.data_id; end + assign wb_store.id_needed = possible_new_forwarded_store ? lsq.data_id : needed_id_r; + - always_comb begin - foreach (hold_for_store_ids_r[i]) - wb_hold_for_store_ids[i] = (hold_for_store_ids_r[i] != 0); - end //////////////////////////////////////////////////// //Output logic [31:0] data_for_alignment; assign oldest_lsq_entry = lsq_entries[oldest_id]; - assign lsq.transaction_ready = oldest_fifo.valid & (~oldest_lsq_entry.forwarded_store | writeback_valid); + assign lsq.transaction_ready = oldest_fifo.valid & (~oldest_lsq_entry.forwarded_store | wb_store.id_done); assign lsq.id_needed_by_store = oldest_lsq_entry.data_id; always_comb begin @@ -166,7 +169,7 @@ module load_store_queue //ID-based input buffer for Load/Store Unit lsq.transaction_out.fn3 = oldest_lsq_entry.fn3; lsq.transaction_out.id = oldest_id; - data_for_alignment = oldest_lsq_entry.forwarded_store ? writeback_data : oldest_lsq_entry.data_in; + data_for_alignment = oldest_lsq_entry.forwarded_store ? wb_store.data : oldest_lsq_entry.data_in; //Input: ABCD //Assuming aligned requests, //Possible byte selections: (A/C/D, B/D, C/D, D) diff --git a/core/load_store_unit.sv b/core/load_store_unit.sv index 4e02d6b..1beef9f 100755 --- a/core/load_store_unit.sv +++ b/core/load_store_unit.sv @@ -120,7 +120,7 @@ module load_store_unit ( logic [31:0] compare_addr; logic address_conflict; - + logic ready_for_forwarded_store; //////////////////////////////////////////////////// //Implementation //////////////////////////////////////////////////// @@ -190,7 +190,7 @@ endgenerate assign lsq.new_issue = issue.new_request & ~unaligned_addr; logic [MAX_IDS-1:0] wb_hold_for_store_ids; - load_store_queue lsq_block (.*, .writeback_valid(wb_store.forwarding_data_ready), .writeback_data(wb_store.forwarded_data)); + load_store_queue lsq_block (.*); assign shared_inputs = lsq.transaction_out; assign lsq.accepted = lsq.transaction_ready & ready_for_issue; @@ -228,7 +228,7 @@ endgenerate assign ready_for_issue = units_ready & (~unit_switch_stall); - assign issue.ready = lsq.ready; + assign issue.ready = lsq.ready & ~(ls_inputs.forwarded_store & ~ready_for_forwarded_store); assign issue_request = lsq.accepted; //////////////////////////////////////////////////// diff --git a/core/register_file_and_writeback.sv b/core/register_file_and_writeback.sv index 35d1305..eb2409a 100755 --- a/core/register_file_and_writeback.sv +++ b/core/register_file_and_writeback.sv @@ -39,6 +39,7 @@ module register_file_and_writeback input id_t id_for_rd [COMMIT_PORTS], //Writeback unit_writeback_interface.wb unit_wb[NUM_WB_UNITS], + writeback_store_interface.wb wb_store, //Trace signals output logic tr_rs1_forwarding_needed, @@ -148,6 +149,50 @@ module register_file_and_writeback rs_data[i] = rs_data_set[rs_sel[i]][i]; end end + + //////////////////////////////////////////////////// + //Store Forwarding Support + logic [31:0] commit_regs [COMMIT_PORTS]; + logic [$clog2(COMMIT_PORTS)-1:0] store_reg_sel; + logic [$clog2(COMMIT_PORTS)-1:0] store_reg_sel_r; + + generate for (i = 0; i < COMMIT_PORTS; i++) begin + always_ff @ (posedge clk) begin + if (wb_store.possibly_waiting & retired[i] & (wb_store.id_needed == ids_retiring[i])) + commit_regs[i] <= retiring_data[i]; + end + end endgenerate + + logic [COMMIT_PORTS-1:0] store_id_match; + always_comb begin + store_id_match = 0; + for (int i = 0; i < COMMIT_PORTS; i++) begin + if (wb_store.waiting & retired[i] & (wb_store.id_needed == ids_retiring[i])) + store_id_match[i] = 1; + end + + store_reg_sel = 0; + for (int i = 1; i < COMMIT_PORTS; i++) begin + if (retired[i] & (wb_store.id_needed == ids_retiring[i])) + store_reg_sel = ($clog2(COMMIT_PORTS))'(i); + end + end + + always_ff @ (posedge clk) begin + if (|store_id_match) + store_reg_sel_r <= store_reg_sel; + end + + always_ff @ (posedge clk) begin + if (rst | wb_store.ack) + wb_store.id_done <= 0; + else if (|store_id_match) + wb_store.id_done <= 1; + end + assign wb_store.data = commit_regs[store_reg_sel_r]; + + + //////////////////////////////////////////////////// //End of Implementation ////////////////////////////////////////////////////