diff --git a/src/ariane.sv b/src/ariane.sv index 76029f22f..9f1fd2209 100644 --- a/src/ariane.sv +++ b/src/ariane.sv @@ -186,6 +186,7 @@ module ariane logic csr_commit_commit_ex; // LSU Commit logic lsu_commit_commit_ex; + logic lsu_commit_ready_ex_commit; logic no_st_pending_ex_commit; // -------------- // ID <-> COMMIT @@ -430,6 +431,7 @@ module ariane .lsu_trans_id_o ( lsu_trans_id_ex_id ), .lsu_valid_o ( lsu_valid_ex_id ), .lsu_commit_i ( lsu_commit_commit_ex ), // from commit + .lsu_commit_ready_o ( lsu_commit_ready_ex_commit ), // to commit .lsu_exception_o ( lsu_exception_ex_id ), .no_st_pending_o ( no_st_pending_ex_commit ), @@ -479,6 +481,7 @@ module ariane .wdata_a_o ( wdata_a_commit_id ), .we_a_o ( we_a_commit_id ), .commit_lsu_o ( lsu_commit_commit_ex ), + .commit_lsu_ready_i ( lsu_commit_ready_ex_commit ), .commit_csr_o ( csr_commit_commit_ex ), .pc_o ( pc_commit ), .csr_op_o ( csr_op_commit_csr ), diff --git a/src/commit_stage.sv b/src/commit_stage.sv index 034bdb40b..bcb5e1a2e 100644 --- a/src/commit_stage.sv +++ b/src/commit_stage.sv @@ -41,6 +41,7 @@ module commit_stage ( input exception csr_exception_i, // commit signals to ex output logic commit_lsu_o, // commit the pending store + input logic commit_lsu_ready_i, input logic no_st_pending_i, // there is no store pending output logic commit_csr_o, // commit the pending CSR instruction output logic fence_i_o, // flush icache and pipeline @@ -69,6 +70,8 @@ module commit_stage ( // we will not commit the instruction if we took an exception // but we do not commit the instruction if we requested a halt if (commit_instr_i.valid && !halt_i) begin + + commit_ack_o = 1'b1; // register will be the all zero register. // and also acknowledge the instruction, this is mainly done for the instruction tracer // as it will listen on the instruction ack signal. For the overall result it does not make any @@ -82,11 +85,13 @@ module commit_stage ( // do not commit the instruction if we got an exception since the store buffer will be cleared // by the subsequent flush triggered by an exception if (commit_instr_i.fu == STORE) begin - commit_lsu_o = 1'b1; + if (commit_lsu_ready_i) + commit_lsu_o = 1'b1; + else // if the LSU buffer is not ready - do not commit, wait + commit_ack_o = 1'b0; end end - commit_ack_o = 1'b1; // --------- // CSR Logic // --------- diff --git a/src/ex_stage.sv b/src/ex_stage.sv index 1ecedcecc..5ba9cc55b 100644 --- a/src/ex_stage.sv +++ b/src/ex_stage.sv @@ -60,6 +60,7 @@ module ex_stage #( output logic [63:0] lsu_result_o, output logic [TRANS_ID_BITS-1:0] lsu_trans_id_o, input logic lsu_commit_i, + output logic lsu_commit_ready_o, // commit queue is ready to accept another commit request output exception lsu_exception_o, output logic no_st_pending_o, // CSR @@ -144,7 +145,8 @@ module ex_stage #( // Load-Store Unit // ---------------- lsu lsu_i ( - .commit_i ( lsu_commit_i ), + .commit_i ( lsu_commit_i ), + .commit_ready_o ( lsu_commit_ready_o ), .* ); diff --git a/src/lsu.sv b/src/lsu.sv index def9fb983..665083529 100644 --- a/src/lsu.sv +++ b/src/lsu.sv @@ -38,6 +38,7 @@ module lsu #( output logic [63:0] lsu_result_o, output logic lsu_valid_o, // transaction id for which the output is the requested one input logic commit_i, // commit the pending store + output logic commit_ready_o, // commit queue is ready to accept another commit request input logic enable_translation_i, // enable virtual memory translation input logic en_ld_st_translation_i, // enable virtual memory translation for load/stores diff --git a/src/store_buffer.sv b/src/store_buffer.sv index ec7f14308..3713e0aeb 100644 --- a/src/store_buffer.sv +++ b/src/store_buffer.sv @@ -29,6 +29,7 @@ module store_buffer ( output logic page_offset_matches_o, input logic commit_i, // commit the instruction which was placed there most recently + output logic commit_ready_o, // commit queue is ready to accept another commit request output logic ready_o, // the store queue is ready to accept a new request // it is only ready if it can unconditionally commit the instruction, e.g.: // the commit buffer needs to be empty @@ -49,8 +50,10 @@ module store_buffer ( input logic data_gnt_i, input logic data_rvalid_i ); - // depth of store-buffer - localparam int unsigned DEPTH = 4; + // depth of store-buffers + localparam int unsigned DEPTH_SPEC = 4; + // allocate more space for the commit buffer to be on the save side + localparam int unsigned DEPTH_COMMIT = 4; // we need to keep the tag portion of the address for a cycle later logic [43:0] address_tag_n, address_tag_q; @@ -65,27 +68,27 @@ module store_buffer ( logic [63:0] data; logic [7:0] be; logic valid; // this entry is valid, we need this for checking if the address offset matches - } speculative_queue_n [DEPTH-1:0], speculative_queue_q [DEPTH-1:0], - commit_queue_n [DEPTH-1:0], commit_queue_q [DEPTH-1:0]; + } speculative_queue_n [DEPTH_SPEC-1:0], speculative_queue_q [DEPTH_SPEC-1:0], + commit_queue_n [DEPTH_COMMIT-1:0], commit_queue_q [DEPTH_COMMIT-1:0]; // keep a status count for both buffers - logic [$clog2(DEPTH):0] speculative_status_cnt_n, speculative_status_cnt_q; - logic [$clog2(DEPTH):0] commit_status_cnt_n, commit_status_cnt_q; + logic [$clog2(DEPTH_SPEC):0] speculative_status_cnt_n, speculative_status_cnt_q; + logic [$clog2(DEPTH_COMMIT):0] commit_status_cnt_n, commit_status_cnt_q; // Speculative queue - logic [$clog2(DEPTH)-1:0] speculative_read_pointer_n, speculative_read_pointer_q; - logic [$clog2(DEPTH)-1:0] speculative_write_pointer_n, speculative_write_pointer_q; + logic [$clog2(DEPTH_SPEC)-1:0] speculative_read_pointer_n, speculative_read_pointer_q; + logic [$clog2(DEPTH_SPEC)-1:0] speculative_write_pointer_n, speculative_write_pointer_q; // Commit Queue - logic [$clog2(DEPTH)-1:0] commit_read_pointer_n, commit_read_pointer_q; - logic [$clog2(DEPTH)-1:0] commit_write_pointer_n, commit_write_pointer_q; + logic [$clog2(DEPTH_COMMIT)-1:0] commit_read_pointer_n, commit_read_pointer_q; + logic [$clog2(DEPTH_COMMIT)-1:0] commit_write_pointer_n, commit_write_pointer_q; // ---------------------------------------- // Speculative Queue - Core Interface // ---------------------------------------- always_comb begin : core_if - automatic logic [DEPTH:0] speculative_status_cnt = speculative_status_cnt_q; + automatic logic [DEPTH_SPEC:0] speculative_status_cnt = speculative_status_cnt_q; // we are ready if the speculative and the commit queue have a space left - ready_o = (speculative_status_cnt_q < DEPTH) && (commit_status_cnt_q < DEPTH); + ready_o = speculative_status_cnt_q < (DEPTH_SPEC - 1); // default assignments speculative_status_cnt_n = speculative_status_cnt_q; speculative_read_pointer_n = speculative_read_pointer_q; @@ -93,7 +96,7 @@ module store_buffer ( speculative_queue_n = speculative_queue_q; // LSU interface // we are ready to accept a new entry and the input data is valid - if (ready_o && valid_i) begin + if (valid_i) begin speculative_queue_n[speculative_write_pointer_q].address = paddr_i; speculative_queue_n[speculative_write_pointer_q].data = data_i; speculative_queue_n[speculative_write_pointer_q].be = be_i; @@ -116,9 +119,9 @@ module store_buffer ( speculative_status_cnt_n = speculative_status_cnt; // when we flush evict the speculative stores - if (flush_i) begin + if (ready_o && flush_i) begin // reset all valid flags - for (int unsigned i = 0; i < DEPTH; i++) + for (int unsigned i = 0; i < DEPTH_SPEC; i++) speculative_queue_n[i].valid = 1'b0; speculative_write_pointer_n = speculative_read_pointer_q; @@ -141,7 +144,8 @@ module store_buffer ( assign data_we_o = 1'b1; // we will always write in the store queue always_comb begin : store_if - automatic logic [DEPTH:0] commit_status_cnt = commit_status_cnt_q; + automatic logic [DEPTH_COMMIT:0] commit_status_cnt = commit_status_cnt_q; + commit_ready_o = (commit_status_cnt_q < DEPTH_COMMIT); // no store is pending if we don't have any element in the commit queue e.g.: it is empty no_st_pending_o = (commit_status_cnt_q == 0); // default assignments @@ -201,12 +205,14 @@ module store_buffer ( always_comb begin : address_checker page_offset_matches_o = 1'b0; // check if the LSBs are identical and the entry is valid - for (int unsigned i = 0; i < DEPTH; i++) begin + for (int unsigned i = 0; i < DEPTH_COMMIT; i++) begin // Check if the page offset matches and whether the entry is valid, for the commit queue if ((page_offset_i[11:3] == commit_queue_q[i].address[11:3]) && commit_queue_q[i].valid) begin page_offset_matches_o = 1'b1; break; end + end + for (int unsigned i = 0; i < DEPTH_SPEC; i++) begin // do the same for the speculative queue if ((page_offset_i[11:3] == speculative_queue_q[i].address[11:3]) && speculative_queue_q[i].valid) begin page_offset_matches_o = 1'b1; @@ -255,6 +261,10 @@ module store_buffer ( assert property ( @(posedge clk_i) rst_ni && flush_i |-> !commit_i) else $error ("You are trying to commit and flush in the same cycle"); + + assert property ( + @(posedge clk_i) rst_ni && !ready_o |-> !valid_i) + else $error ("You are trying to push new data although the buffer is not ready"); `endif `endif endmodule diff --git a/src/store_unit.sv b/src/store_unit.sv index f473e7fe9..32c8a62a2 100644 --- a/src/store_unit.sv +++ b/src/store_unit.sv @@ -28,6 +28,8 @@ module store_unit ( input lsu_ctrl_t lsu_ctrl_i, output logic pop_st_o, input logic commit_i, + output logic commit_ready_o, + // store unit output port output logic valid_o, output logic [TRANS_ID_BITS-1:0] trans_id_o,