🐛 Fix misaligned data in store buffer

This commit is contained in:
Florian Zaruba 2017-06-06 19:26:25 +02:00
parent 1ec3253441
commit 00e500f08c
5 changed files with 82 additions and 26 deletions

View file

@ -41,23 +41,23 @@ Check out the [contribution guide](CONTRIBUTING.md)
# Test Overview
| **Test Name** | **P/F/U** | **Test Name** | **P/F/U** | **Test Name** | **P/F/U** |
|---------------|----------------------|---------------|----------------------|---------------|--------------------|
| add | :white_check_mark: | lb | :white_check_mark: | sll | :white_check_mark: |
| addi | :white_check_mark: | lbu | :white_check_mark: | slli | :white_check_mark: |
| addiw | :white_check_mark: | ld | :white_check_mark: | slliw | :white_check_mark: |
| addw | :white_check_mark: | lh | :white_check_mark: | sllw | :white_check_mark: |
| and | :white_check_mark: | lhu | :white_check_mark: | slt | :white_check_mark: |
| andi | :white_check_mark: | lui | :white_check_mark: | slti | :white_check_mark: |
| auipc | :white_check_mark: | lw | :white_check_mark: | sltiu | :white_check_mark: |
| beq | :white_check_mark: | lwu | :white_check_mark: | sltu | :white_check_mark: |
| bge | :white_check_mark: | or | :white_check_mark: | sra | :white_check_mark: |
| bgeu | :white_check_mark: | ori | :white_check_mark: | srai | :white_check_mark: |
| blt | :white_check_mark: | sb | :white_large_square: | sraiw | :white_check_mark: |
| bltu | :white_check_mark: | sd | :white_large_square: | sraw | :white_check_mark: |
| bne | :white_check_mark: | sh | :white_large_square: | srl | :white_check_mark: |
| sub | :white_check_mark: | simple | :white_check_mark: | srli | :white_check_mark: |
| subw | :white_check_mark: | jal | :white_check_mark: | srliw | :white_check_mark: |
| sw | :white_large_square: | jalr | :white_check_mark: | srlw | :white_check_mark: |
| xor | :white_check_mark: | | | | |
| xori | :white_check_mark: | | | | |
| **Test Name** | **P/F/U** | **Test Name** | **P/F/U** | **Test Name** | **P/F/U** |
|---------------|--------------------|---------------|--------------------|---------------|--------------------|
| add | :white_check_mark: | lb | :white_check_mark: | sll | :white_check_mark: |
| addi | :white_check_mark: | lbu | :white_check_mark: | slli | :white_check_mark: |
| addiw | :white_check_mark: | ld | :white_check_mark: | slliw | :white_check_mark: |
| addw | :white_check_mark: | lh | :white_check_mark: | sllw | :white_check_mark: |
| and | :white_check_mark: | lhu | :white_check_mark: | slt | :white_check_mark: |
| andi | :white_check_mark: | lui | :white_check_mark: | slti | :white_check_mark: |
| auipc | :white_check_mark: | lw | :white_check_mark: | sltiu | :white_check_mark: |
| beq | :white_check_mark: | lwu | :white_check_mark: | sltu | :white_check_mark: |
| bge | :white_check_mark: | or | :white_check_mark: | sra | :white_check_mark: |
| bgeu | :white_check_mark: | ori | :white_check_mark: | srai | :white_check_mark: |
| blt | :white_check_mark: | sb | :white_check_mark: | sraiw | :white_check_mark: |
| bltu | :white_check_mark: | sd | :white_check_mark: | sraw | :white_check_mark: |
| bne | :white_check_mark: | sh | :white_check_mark: | srl | :white_check_mark: |
| sub | :white_check_mark: | simple | :white_check_mark: | srli | :white_check_mark: |
| subw | :white_check_mark: | jal | :white_check_mark: | srliw | :white_check_mark: |
| sw | :white_check_mark: | jalr | :white_check_mark: | srlw | :white_check_mark: |
| xor | :white_check_mark: | | | | |
| xori | :white_check_mark: | | | | |

View file

@ -56,7 +56,7 @@ module load_unit (
input logic data_rvalid_i,
input logic [63:0] data_rdata_i
);
enum logic [2:0] {IDLE, WAIT_GNT, SEND_TAG, ABORT_TRANSLATION, WAIT_FLUSH} NS, CS;
enum logic [2:0] {IDLE, WAIT_GNT, SEND_TAG, WAIT_PAGE_OFFSET, ABORT_TRANSLATION, WAIT_FLUSH} NS, CS;
// in order to decouple the response interface from the request interface we need a
// a queue which can hold all outstanding memory requests
typedef struct packed {
@ -141,6 +141,41 @@ module load_unit (
end else begin
// stall and wait for the store-buffer to drain
ready_o = 1'b0;
// wait for the store buffer to train and the page offset to not match anymore
NS = WAIT_PAGE_OFFSET;
end
end
end
// wait here for the page offset to not match anymore
WAIT_PAGE_OFFSET: begin
// we are definitely not ready to accept a new request
// we need unique access to the LSU
ready_o = 1'b0;
translation_req_o = 1'b1;
// we make a new request as soon as the page offset does not match anymore
// essentially the same part as above
if (!page_offset_matches_i) begin
// make a load request to memory
data_req_o = 1'b1;
// the translation request we got is valid
if (translation_valid_i) begin
// save the physical address for the next cycle
paddr_n = paddr_i;
// we got no data grant so wait for the grant before sending the tag
if (!data_gnt_i) begin
NS = WAIT_GNT;
end else begin
// put the request in the queue
push = 1'b1;
// we got a grant so we can send the tag in the next cycle
NS = SEND_TAG;
end
// we got a TLB miss
end else begin
// we need to abort the translation and let the PTW walker fix the TLB miss
NS = ABORT_TRANSLATION;
ready_o = 1'b0;
end
end
end
@ -262,9 +297,11 @@ module load_unit (
// do not push this request
push = 1'b0;
end
// if we just flushed and the queue is not empty or we are getting an rvalid this cycle wait in an extra stage
// if we just flushed and the queue is not empty or we are getting an rvalid this cycle wait in a extra stage
if (flush_i && (!empty || data_rvalid_i)) begin
NS = WAIT_FLUSH;
end else if (flush_i) begin
NS = IDLE;
end
end

View file

@ -128,7 +128,7 @@ module scoreboard #(
mem_n[trans_id_i[i]].sbe.result = wdata_i[i];
// write the exception back if it is valid
if (ex_i[i].valid)
mem_n[trans_id_i[i]].sbe.ex = ex_i[i];
mem_n[trans_id_i[i]].sbe.ex = ex_i[i];
end
end

View file

@ -59,8 +59,9 @@ module store_unit (
);
assign result_o = 64'b0;
logic [63:0] st_buffer_paddr; // physical address for store
logic [63:0] st_buffer_data; // store buffer data out
logic [63:0] st_buffer_paddr; // physical address for store
logic [63:0] st_buffer_data; // store buffer data out
logic [63:0] st_data; // aligned data to store buffer
logic [7:0] st_buffer_be;
logic st_buffer_valid;
// store buffer control signals
@ -108,13 +109,30 @@ module store_unit (
end
end
end
// -----------
// Re-aligner
// -----------
// re-align the write data to comply with the address offset
always_comb begin
st_data = data_i;
case (vaddr_i[2:0])
3'b000: st_data = data_i;
3'b001: st_data = {data_i[55:0], data_i[63:56]};
3'b010: st_data = {data_i[47:0], data_i[63:48]};
3'b011: st_data = {data_i[39:0], data_i[63:40]};
3'b100: st_data = {data_i[31:0], data_i[63:32]};
3'b101: st_data = {data_i[23:0], data_i[63:24]};
3'b110: st_data = {data_i[15:0], data_i[63:16]};
3'b111: st_data = {data_i[7:0], data_i[63:8]};
endcase
end
// ---------------
// Store Queue
// ---------------
store_queue store_queue_i (
// store queue write port
.valid_i ( st_valid ),
.data_i ( st_data ),
// store buffer in
.paddr_o ( st_buffer_paddr ),
.data_o ( st_buffer_data ),

View file

@ -12,6 +12,7 @@ add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/*
add wave -noupdate -group ex_stage -group lsu -group mem_arbiter /core_tb/dut/ex_stage_i/lsu_i/dcache_arbiter_i/*
add wave -noupdate -group ex_stage -group lsu -group mem_arbiter -group arbiter_fifo /core_tb/dut/ex_stage_i/lsu_i/dcache_arbiter_i/fifo_i/*
add wave -noupdate -group ex_stage -group lsu -group store_unit /core_tb/dut/ex_stage_i/lsu_i/store_unit_i/*
add wave -noupdate -group ex_stage -group lsu -group store_unit -group store_queue /core_tb/dut/ex_stage_i/lsu_i/store_unit_i/store_queue_i/*
add wave -noupdate -group ex_stage -group lsu -group load_unit /core_tb/dut/ex_stage_i/lsu_i/load_unit_i/*
add wave -noupdate -group ex_stage -group lsu -group load_unit -group fifo /core_tb/dut/ex_stage_i/lsu_i/load_unit_i/fifo_i/*
add wave -noupdate -group ex_stage -group lsu -group lsu_arbiter /core_tb/dut/ex_stage_i/lsu_i/lsu_arbiter_i/*