✂️ Move address checker to store queue

This commit is contained in:
Florian Zaruba 2017-06-23 23:37:16 +02:00
parent ff91fdbfec
commit bfae40e2a8
5 changed files with 52 additions and 59 deletions

View file

@ -1,3 +1,4 @@
/* File: ariane_pkg.svh
* Author: Florian Zaruba <zarubaf@ethz.ch>
* Date: 8.4.2017
@ -19,6 +20,9 @@ package ariane_pkg;
// to uniquely identify the entry in the scoreboard
localparam NR_WB_PORTS = 4;
localparam ASID_WIDTH = 1;
localparam BTB_ENTRIES = 64;
localparam BITS_SATURATION_COUNTER = 2;
localparam logic [63:0] ISA_CODE = (1 << 2) // C - Compressed extension
| (1 << 8) // I - RV32I/64I/128I base ISA
| (1 << 12) // M - Integer Multiply/Divide extension

View file

@ -441,29 +441,22 @@ module lsu #(
// ------------------
// LSU Control
// ------------------
// The LSU consists of two independent block which share a common address translation block.
// The one block is the load unit, the other one is the store unit. They will signal their readiness
// with separate signals. If they are not ready the LSU control should keep the last applied signals stable.
// Furthermore it can be the case that another request for one of the two store units arrives in which case
// the LSU controll should sample it and store it for later application to the units. It does so, by storing it in a
// two element FIFO.
// new data arrives here
lsu_ctrl_t lsu_req_i;
assign lsu_req_i = {lsu_valid_i, vaddr_i, operand_b_i, be_i, fu_i, operator_i, trans_id_i};
lsu_bypass lsu_bypass_i (
.lsu_req_i ( lsu_req_i ),
.lsu_req_i ( lsu_req_i ),
.lus_req_valid_i ( lsu_valid_i ),
.pop_ld_i ( pop_ld ),
.pop_st_i ( pop_st ),
.pop_ld_i ( pop_ld ),
.pop_st_i ( pop_st ),
.ld_ready_i ( ld_ready_o ),
.st_ready_i ( st_ready_o),
.ld_ready_i ( ld_ready_o ),
.st_ready_i ( st_ready_o ),
.lsu_ctrl_o ( lsu_ctrl ),
.ready_o ( lsu_ready_o ),
.lsu_ctrl_o ( lsu_ctrl ),
.ready_o ( lsu_ready_o ),
.*
);
// ------------
@ -500,6 +493,15 @@ module lsu #(
`endif
endmodule
// ------------------
// LSU Control
// ------------------
// The LSU consists of two independent block which share a common address translation block.
// The one block is the load unit, the other one is the store unit. They will signal their readiness
// with separate signals. If they are not ready the LSU control should keep the last applied signals stable.
// Furthermore it can be the case that another request for one of the two store units arrives in which case
// the LSU controll should sample it and store it for later application to the units. It does so, by storing it in a
// two element FIFO.
module lsu_bypass (
input logic clk_i,
input logic rst_ni,

View file

@ -49,8 +49,8 @@ module pcgen (
assign fetch_address_o = npc_q;
btb #(
.NR_ENTRIES(64),
.BITS_SATURATION_COUNTER(2)
.NR_ENTRIES ( BTB_ENTRIES ),
.BITS_SATURATION_COUNTER ( BITS_SATURATION_COUNTER )
)
btb_i
(

View file

@ -25,10 +25,8 @@ module store_queue (
// otherwise we will run in a deadlock with the memory arbiter
output logic no_st_pending_o, // non-speculative queue is empty (e.g.: everything is committed to the memory hierarchy)
output logic [63:0] paddr_o, // physical address of the valid store
output logic [63:0] data_o, // data at the given address
output logic valid_o, // committed data is valid
output logic [7:0] be_o, // byte enable set
input logic [11:0] page_offset_i,
output logic page_offset_matches_o,
input logic commit_i, // commit the instruction which was placed there most recently
output logic ready_o, // the store queue is ready to accept a new request
@ -74,12 +72,6 @@ module store_queue (
logic is_speculative; // set if the entry isn't committed yet
} commit_queue_n, commit_queue_q;
// we can directly output the commit entry since we have just one element in the "queue"
assign paddr_o = commit_queue_q.address;
assign data_o = commit_queue_q.data;
assign be_o = commit_queue_q.be;
assign valid_o = commit_queue_q.valid;
// those signals can directly be output to the memory
assign address_index_o = commit_queue_q.address[11:0];
// if we got a new request we already saved the tag from the previous cycle
@ -153,6 +145,34 @@ module store_queue (
end
// ------------------
// Address Checker
// ------------------
// The load should return the data stored by the most recent store to the
// same physical address. The most direct way to implement this is to
// maintain physical addresses in the store buffer.
// Of course, there are other micro-architectural techniques to accomplish
// the same thing: you can interlock and wait for the store buffer to
// drain if the load VA matches any store VA modulo the page size (i.e.
// bits 11:0). As a special case, it is correct to bypass if the full VA
// matches, and no younger stores' VAs match in bits 11:0.
//
// checks if the requested load is in the store buffer
// page offsets are virtually and physically the same
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;
end
if ((page_offset_i[11:3] == paddr_i[11:3]) && valid_i) begin
page_offset_matches_o = 1'b1;
end
end
// registers
always_ff @(posedge clk_i or negedge rst_ni) begin : proc_
if(~rst_ni) begin

View file

@ -59,9 +59,6 @@ module store_unit (
enum logic [1:0] {IDLE, VALID_STORE, WAIT_TRANSLATION, WAIT_STORE_READY} NS, CS;
logic [63:0] st_buffer_paddr; // physical address for store
logic [63:0] st_data; // aligned data to store buffer
logic st_buffer_valid;
// store buffer control signals
logic st_ready;
logic st_valid;
@ -199,10 +196,6 @@ module store_unit (
.data_i ( st_data_q ),
.be_i ( st_be_q ),
// store buffer out
.paddr_o ( st_buffer_paddr ),
.data_o ( ),
.valid_o ( st_buffer_valid ),
.be_o ( ),
.ready_o ( st_ready ),
.*
);
@ -222,31 +215,5 @@ module store_unit (
trans_id_q <= trans_id_n;
end
end
// ------------------
// Address Checker
// ------------------
// The load should return the data stored by the most recent store to the
// same physical address. The most direct way to implement this is to
// maintain physical addresses in the store buffer.
// Of course, there are other micro-architectural techniques to accomplish
// the same thing: you can interlock and wait for the store buffer to
// drain if the load VA matches any store VA modulo the page size (i.e.
// bits 11:0). As a special case, it is correct to bypass if the full VA
// matches, and no younger stores' VAs match in bits 11:0.
//
// checks if the requested load is in the store buffer
// page offsets are virtually and physically the same
always_comb begin : address_checker
page_offset_matches_o = 1'b0;
// check if the LSBs are identical and the entry is valid
if ((lsu_ctrl_i.vaddr[11:3] == st_buffer_paddr[11:3]) && st_buffer_valid) begin
page_offset_matches_o = 1'b1;
end
if ((lsu_ctrl_i.vaddr[11:3] == paddr_i[11:3]) && (CS == VALID_STORE)) begin
page_offset_matches_o = 1'b1;
end
end
endmodule