mirror of
https://github.com/openhwgroup/cva6.git
synced 2025-04-22 21:27:10 -04:00
Add 8 element store buffer IPC 0.621 -> 0.635
This commit is contained in:
parent
28cf5eb3ab
commit
491d6dc367
2 changed files with 101 additions and 73 deletions
|
@ -49,6 +49,9 @@ module store_buffer (
|
|||
input logic data_gnt_i,
|
||||
input logic data_rvalid_i
|
||||
);
|
||||
// depth of store-buffer
|
||||
localparam int unsigned DEPTH = 8;
|
||||
|
||||
// we need to keep the tag portion of the address for a cycle later
|
||||
logic [43:0] address_tag_n, address_tag_q;
|
||||
logic tag_valid_n, tag_valid_q;
|
||||
|
@ -70,77 +73,89 @@ module store_buffer (
|
|||
logic [7:0] be;
|
||||
logic valid; // entry is valid
|
||||
logic is_speculative; // set if the entry isn't committed yet
|
||||
} commit_queue_n, commit_queue_q;
|
||||
} commit_queue_n [DEPTH-1:0], commit_queue_q [DEPTH-1:0];
|
||||
|
||||
logic [$clog2(DEPTH)-1:0] read_pointer_n, read_pointer_q;
|
||||
logic [$clog2(DEPTH)-1:0] commit_pointer_n, commit_pointer_q;
|
||||
logic [$clog2(DEPTH)-1:0] write_pointer_n, write_pointer_q;
|
||||
|
||||
// those signals can directly be output to the memory
|
||||
assign address_index_o = commit_queue_q.address[11:0];
|
||||
assign address_index_o = commit_queue_q[read_pointer_q].address[11:0];
|
||||
// if we got a new request we already saved the tag from the previous cycle
|
||||
assign address_tag_o = address_tag_q;
|
||||
assign data_wdata_o = commit_queue_q.data;
|
||||
assign data_be_o = commit_queue_q.be;
|
||||
assign tag_valid_o = tag_valid_q;
|
||||
assign data_wdata_o = commit_queue_q[read_pointer_q].data;
|
||||
assign data_be_o = commit_queue_q[read_pointer_q].be;
|
||||
// we will never kill a request in the store buffer since we already know that the translation is valid
|
||||
// e.g.: a kill request will only be necessary if we are not sure if the requested memory address will result in a TLB fault
|
||||
assign kill_req_o = 1'b0;
|
||||
|
||||
// no store is pending if we don't have any uncommitted data, e.g.: the queue is either not valid or the entry is
|
||||
// speculative (it can be flushed)
|
||||
assign no_st_pending_o = !commit_queue_q.valid || commit_queue_q.is_speculative;
|
||||
assign no_st_pending_o = (!commit_queue_q[commit_pointer_q].valid || commit_queue_q[commit_pointer_q].is_speculative);
|
||||
|
||||
assign data_we_o = 1'b1; // we will always write in the store queue
|
||||
// memory interface
|
||||
always_comb begin : store_if
|
||||
// if there is no commit pending and the uncommitted queue is empty as well we can accept the request
|
||||
// if we got a grant this implies that the value was not speculative anymore and that we
|
||||
// do not need to save the values anymore since the memory already processed them
|
||||
automatic logic ready = !commit_queue_q.valid || data_gnt_i;
|
||||
ready_o = ready && !flush_i;
|
||||
// we are ready if the top-most entry is not valid
|
||||
ready_o = !commit_queue_q[write_pointer_q].valid;
|
||||
// default assignments
|
||||
read_pointer_n = read_pointer_q;
|
||||
write_pointer_n = write_pointer_q;
|
||||
commit_pointer_n = commit_pointer_q;
|
||||
|
||||
address_tag_n = address_tag_q;
|
||||
commit_queue_n = commit_queue_q;
|
||||
tag_valid_n = 1'b0;
|
||||
address_tag_n = address_tag_q;
|
||||
commit_queue_n = commit_queue_q;
|
||||
|
||||
data_we_o = 1'b1; // we will always write in the store queue
|
||||
data_req_o = 1'b0;
|
||||
tag_valid_n = 1'b0;
|
||||
data_req_o = 1'b0;
|
||||
|
||||
// there should be no commit when we are flushing
|
||||
if (!flush_i) begin
|
||||
// if the entry in the commit queue is valid and not speculative anymore
|
||||
// we can issue this instruction
|
||||
// we can issue it as soon as the commit_i goes high or any number of cycles later
|
||||
// by looking at the is_speculative flag
|
||||
if (commit_queue_q.valid && (!commit_queue_q.is_speculative || commit_i)) begin
|
||||
data_req_o = 1'b1;
|
||||
if (data_gnt_i) begin
|
||||
// we can evict it from the commit buffer
|
||||
commit_queue_n.valid = 1'b0;
|
||||
// save the tag portion
|
||||
address_tag_n = commit_queue_q.address[55:12];
|
||||
// signal a valid tag the cycle afterwards
|
||||
tag_valid_n = 1'b1;
|
||||
end
|
||||
// if the entry in the commit queue is valid and not speculative anymore we can issue this instruction
|
||||
if (commit_queue_q[read_pointer_q].valid && !commit_queue_q[read_pointer_q].is_speculative) begin
|
||||
data_req_o = 1'b1;
|
||||
if (data_gnt_i) begin
|
||||
// we can evict it from the commit buffer
|
||||
commit_queue_n[read_pointer_q].valid = 1'b0;
|
||||
// save the tag portion
|
||||
address_tag_n = commit_queue_q[read_pointer_q].address[55:12];
|
||||
// signal a valid tag the cycle afterwards
|
||||
tag_valid_n = 1'b1;
|
||||
// advance the read_pointer
|
||||
read_pointer_n = read_pointer_q + 1'b1;
|
||||
end
|
||||
// we ignore the rvalid signal for now as we assume that the store
|
||||
// happened
|
||||
end
|
||||
// we ignore the rvalid signal for now as we assume that the store
|
||||
// happened
|
||||
|
||||
// shift the store request from the speculative buffer
|
||||
// to the non-speculative
|
||||
if (commit_i) begin
|
||||
commit_queue_n.is_speculative = 1'b0;
|
||||
commit_queue_n[commit_pointer_q].is_speculative = 1'b0;
|
||||
commit_pointer_n = commit_pointer_q + 1'b1;
|
||||
end
|
||||
|
||||
// LSU interface
|
||||
// we are ready to accept a new entry and the input data is valid
|
||||
if (ready && valid_i) begin
|
||||
commit_queue_n.address = paddr_i;
|
||||
commit_queue_n.data = data_i;
|
||||
commit_queue_n.be = be_i;
|
||||
commit_queue_n.valid = 1'b1;
|
||||
commit_queue_n.is_speculative = 1'b1;
|
||||
if (ready_o && valid_i) begin
|
||||
commit_queue_n[write_pointer_q].address = paddr_i;
|
||||
commit_queue_n[write_pointer_q].data = data_i;
|
||||
commit_queue_n[write_pointer_q].be = be_i;
|
||||
commit_queue_n[write_pointer_q].valid = 1'b1;
|
||||
commit_queue_n[write_pointer_q].is_speculative = 1'b1;
|
||||
// advance the write pointer
|
||||
write_pointer_n = write_pointer_q + 1;
|
||||
end
|
||||
|
||||
// when we flush evict the speculative store
|
||||
if (flush_i && commit_queue_q.is_speculative) begin
|
||||
commit_queue_n.valid = 1'b0;
|
||||
// when we flush evict the speculative stores
|
||||
if (flush_i) begin
|
||||
for (int unsigned i = 0; i < DEPTH; i++) begin
|
||||
if (commit_queue_q[i].is_speculative) begin
|
||||
commit_queue_n[i].valid = 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
write_pointer_n = commit_pointer_q;
|
||||
end
|
||||
|
||||
end
|
||||
|
@ -163,10 +178,13 @@ 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
|
||||
if ((page_offset_i[11:3] == commit_queue_q.address[11:3]) && commit_queue_q.valid) begin
|
||||
page_offset_matches_o = 1'b1;
|
||||
for (int unsigned i = 0; i < DEPTH; i++) begin
|
||||
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
|
||||
|
||||
// or it matches with the entry we are currently putting into the queue
|
||||
if ((page_offset_i[11:3] == paddr_i[11:3]) && valid_i) begin
|
||||
page_offset_matches_o = 1'b1;
|
||||
end
|
||||
|
@ -176,15 +194,22 @@ module store_buffer (
|
|||
// registers
|
||||
always_ff @(posedge clk_i or negedge rst_ni) begin : proc_
|
||||
if(~rst_ni) begin
|
||||
address_tag_q <= 'b0;
|
||||
tag_valid_q <= 1'b0;
|
||||
commit_queue_q <= '{default: 0};
|
||||
address_tag_q <= 'b0;
|
||||
tag_valid_q <= 1'b0;
|
||||
commit_queue_q <= '{default: 0};
|
||||
read_pointer_q <= '0;
|
||||
write_pointer_q <= '0;
|
||||
commit_pointer_q <= '0;
|
||||
end else begin
|
||||
commit_queue_q <= commit_queue_n;
|
||||
tag_valid_q <= tag_valid_n;
|
||||
address_tag_q <= address_tag_n;
|
||||
commit_queue_q <= commit_queue_n;
|
||||
tag_valid_q <= tag_valid_n;
|
||||
address_tag_q <= address_tag_n;
|
||||
read_pointer_q <= read_pointer_n;
|
||||
write_pointer_q <= write_pointer_n;
|
||||
commit_pointer_q <= commit_pointer_n;
|
||||
end
|
||||
end
|
||||
|
||||
`ifndef SYNTHESIS
|
||||
`ifndef verilator
|
||||
// assert that commit is never set when we are flushing this would be counter intuitive
|
||||
|
|
|
@ -87,47 +87,50 @@ module store_unit (
|
|||
IDLE: begin
|
||||
if (valid_i) begin
|
||||
|
||||
NS = VALID_STORE;
|
||||
NS = VALID_STORE;
|
||||
translation_req_o = 1'b1;
|
||||
|
||||
pop_st_o = 1'b1;
|
||||
// check if translation was valid and we have space in the store buffer
|
||||
// otherwise simply stall
|
||||
if (!dtlb_hit_i) begin
|
||||
NS = WAIT_TRANSLATION;
|
||||
pop_st_o = 1'b0;
|
||||
end
|
||||
|
||||
if (!st_ready) begin
|
||||
NS = WAIT_STORE_READY;
|
||||
pop_st_o = 1'b0;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
VALID_STORE: begin
|
||||
ready_o = 1'b0;
|
||||
// ready_o = 1'b0;
|
||||
valid_o = 1'b1;
|
||||
// post this store to the store buffer
|
||||
// post this store to the store buffer if we are not flushing
|
||||
if (!flush_i)
|
||||
st_valid = 1'b1;
|
||||
|
||||
pop_st_o = 1'b1;
|
||||
// we have another request
|
||||
if (valid_i) begin
|
||||
|
||||
// // we have another request
|
||||
// if (valid_i) begin
|
||||
translation_req_o = 1'b1;
|
||||
NS = VALID_STORE;
|
||||
pop_st_o = 1'b1;
|
||||
|
||||
// translation_req_o = 1'b1;
|
||||
if (!dtlb_hit_i) begin
|
||||
NS = WAIT_TRANSLATION;
|
||||
pop_st_o = 1'b0;
|
||||
end
|
||||
|
||||
// if (!dtlb_hit_i) begin
|
||||
// NS = WAIT_TRANSLATION;
|
||||
// end
|
||||
|
||||
// if (!st_ready) begin
|
||||
// NS = WAIT_STORE_READY;
|
||||
// end
|
||||
// // if we do not have another request go back to idle
|
||||
// end else begin
|
||||
// NS = IDLE;
|
||||
// end
|
||||
NS = IDLE;
|
||||
if (!st_ready) begin
|
||||
pop_st_o = 1'b0;
|
||||
NS = WAIT_STORE_READY;
|
||||
end
|
||||
// if we do not have another request go back to idle
|
||||
end else begin
|
||||
NS = IDLE;
|
||||
end
|
||||
end
|
||||
|
||||
// the store queue is currently full
|
||||
|
@ -137,7 +140,7 @@ module store_unit (
|
|||
translation_req_o = 1'b1;
|
||||
|
||||
if (st_ready && dtlb_hit_i) begin
|
||||
NS = VALID_STORE;
|
||||
NS = IDLE;
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -149,7 +152,7 @@ module store_unit (
|
|||
translation_req_o = 1'b1;
|
||||
|
||||
if (dtlb_hit_i) begin
|
||||
NS = VALID_STORE;
|
||||
NS = IDLE;
|
||||
end
|
||||
end
|
||||
endcase
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue