mirror of
https://github.com/openhwgroup/cva6.git
synced 2025-04-22 05:07:21 -04:00
New LSU arbitration scheme
This commit is contained in:
parent
43959a587b
commit
ff91fdbfec
8 changed files with 182 additions and 101 deletions
|
@ -14,7 +14,7 @@ package ariane_pkg;
|
|||
// ---------------
|
||||
// Global Config
|
||||
// ---------------
|
||||
localparam NR_SB_ENTRIES = 4; // number of scoreboard entries
|
||||
localparam NR_SB_ENTRIES = 8; // number of scoreboard entries
|
||||
localparam TRANS_ID_BITS = $clog2(NR_SB_ENTRIES); // depending on the number of scoreboard entries we need that many bits
|
||||
// to uniquely identify the entry in the scoreboard
|
||||
localparam NR_WB_PORTS = 4;
|
||||
|
|
|
@ -68,6 +68,7 @@ module fifo #(
|
|||
// but increment the read pointer...
|
||||
read_pointer_n = read_pointer_q + 1;
|
||||
// ... and decrement the overall count
|
||||
mem_n[read_pointer_q] = '0;
|
||||
status_cnt_n = status_cnt_q - 1;
|
||||
end
|
||||
// keep the count pointer stable if we push and pop at the same time
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
import ariane_pkg::*;
|
||||
|
||||
module issue_stage #(
|
||||
parameter int NR_ENTRIES = 4,
|
||||
parameter int NR_ENTRIES = 8,
|
||||
parameter int NR_WB_PORTS = 4
|
||||
)(
|
||||
input logic clk_i, // Clock
|
||||
|
|
|
@ -25,7 +25,7 @@ module load_unit (
|
|||
// load unit input port
|
||||
input logic valid_i,
|
||||
input lsu_ctrl_t lsu_ctrl_i,
|
||||
input logic [7:0] be_i,
|
||||
output logic pop_ld_o,
|
||||
// load unit output port
|
||||
output logic valid_o,
|
||||
output logic ready_o,
|
||||
|
@ -93,6 +93,7 @@ module load_unit (
|
|||
kill_req_o = 1'b0;
|
||||
tag_valid_o = 1'b0;
|
||||
data_be_o = lsu_ctrl_i.be;
|
||||
pop_ld_o = 1'b0;
|
||||
|
||||
case (CS)
|
||||
IDLE: begin
|
||||
|
@ -109,10 +110,11 @@ module load_unit (
|
|||
if (!data_gnt_i) begin
|
||||
NS = WAIT_GNT;
|
||||
end else begin
|
||||
if (dtlb_hit_i)
|
||||
if (dtlb_hit_i) begin
|
||||
// we got a grant and a hit on the DTLB so we can send the tag in the next cycle
|
||||
NS = SEND_TAG;
|
||||
else
|
||||
pop_ld_o = 1'b1;
|
||||
end else
|
||||
NS = ABORT_TRANSACTION;
|
||||
end
|
||||
end else begin
|
||||
|
@ -163,9 +165,10 @@ module load_unit (
|
|||
// we finally got a data grant
|
||||
if (data_gnt_i) begin
|
||||
// so we send the tag in the next cycle
|
||||
if (dtlb_hit_i)
|
||||
if (dtlb_hit_i) begin
|
||||
NS = SEND_TAG;
|
||||
else // should we not have hit on the TLB abort this transaction an retry later
|
||||
pop_ld_o = 1'b1;
|
||||
end else // should we not have hit on the TLB abort this transaction an retry later
|
||||
NS = ABORT_TRANSACTION;
|
||||
end
|
||||
// otherwise we keep waiting on our grant
|
||||
|
@ -187,10 +190,11 @@ module load_unit (
|
|||
NS = WAIT_GNT;
|
||||
end else begin
|
||||
// we got a grant so we can send the tag in the next cycle
|
||||
if (dtlb_hit_i)
|
||||
if (dtlb_hit_i) begin
|
||||
// we got a grant and a hit on the DTLB so we can send the tag in the next cycle
|
||||
NS = SEND_TAG;
|
||||
else // we missed on the TLB -> wait for the translation
|
||||
pop_ld_o = 1'b1;
|
||||
end else // we missed on the TLB -> wait for the translation
|
||||
NS = ABORT_TRANSACTION;
|
||||
end
|
||||
end else begin
|
||||
|
|
184
src/lsu.sv
184
src/lsu.sv
|
@ -87,8 +87,10 @@ module lsu #(
|
|||
// e.g.: they keep the value in the stall case
|
||||
lsu_ctrl_t lsu_ctrl;
|
||||
|
||||
// registered address in case of a necessary stall
|
||||
lsu_ctrl_t lsu_ctrl_n, lsu_ctrl_q, lsu_ctrl_nn, lsu_ctrl_qq;
|
||||
logic lsu_ctrl_full;
|
||||
lsu_ctrl_t lsu_ctrl_o;
|
||||
logic pop_st;
|
||||
logic pop_ld;
|
||||
|
||||
// Address Generation Unit (AGU)
|
||||
// ------------------------------
|
||||
|
@ -211,6 +213,7 @@ module lsu #(
|
|||
store_unit store_unit_i (
|
||||
.valid_i ( st_valid_i ),
|
||||
.lsu_ctrl_i ( lsu_ctrl ),
|
||||
.pop_st_o ( pop_st ),
|
||||
|
||||
.valid_o ( st_valid ),
|
||||
.ready_o ( st_ready_o ),
|
||||
|
@ -246,6 +249,7 @@ module lsu #(
|
|||
load_unit load_unit_i (
|
||||
.valid_i ( ld_valid_i ),
|
||||
.lsu_ctrl_i ( lsu_ctrl ),
|
||||
.pop_ld_o ( pop_ld ),
|
||||
|
||||
.valid_o ( ld_valid ),
|
||||
.ready_o ( ld_ready_o ),
|
||||
|
@ -299,16 +303,6 @@ module lsu #(
|
|||
.ex_o ( lsu_exception_o )
|
||||
);
|
||||
|
||||
// ------------------
|
||||
// LSU Control
|
||||
// ------------------
|
||||
always_comb begin : lsu_control
|
||||
// the LSU is ready if both, stores and loads are ready because we do not know
|
||||
// which unit we need for the instruction we get
|
||||
// additionally it might be the case that we still have one instruction in the buffer, check for that
|
||||
lsu_ready_o = ld_ready_o && st_ready_o && !lsu_ctrl_qq.valid;
|
||||
end
|
||||
|
||||
// determine whether this is a load or store
|
||||
always_comb begin : which_op
|
||||
|
||||
|
@ -443,57 +437,35 @@ module lsu #(
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
// ------------------
|
||||
// Input Select
|
||||
// LSU Control
|
||||
// ------------------
|
||||
// this process selects the input based on the current state of the LSU
|
||||
// it can either be feed-through from the issue stage or from the internal registers
|
||||
always_comb begin : input_select
|
||||
// if we are stalling use the values we saved
|
||||
if (lsu_ctrl_qq.valid && ld_ready_o && st_ready_o) begin
|
||||
lsu_ctrl = lsu_ctrl_qq;
|
||||
end else if (lsu_ready_o) begin
|
||||
lsu_ctrl = {lsu_valid_i, vaddr_i, operand_b_i, be_i, fu_i, operator_i, trans_id_i};
|
||||
end else begin // otherwise bypass them
|
||||
lsu_ctrl = lsu_ctrl_q;
|
||||
end
|
||||
end
|
||||
// 1st register stage
|
||||
always_comb begin : register_stage
|
||||
lsu_ctrl_n = lsu_ctrl_q;
|
||||
lsu_ctrl_nn = lsu_ctrl_qq;
|
||||
// if we are not ready it might be the case that we get another request from the issue stage
|
||||
if (!lsu_ready_o && lsu_valid_i) begin
|
||||
lsu_ctrl_nn = {lsu_valid_i, vaddr_i, operand_b_i, be_i, fu_i, operator_i, trans_id_i};
|
||||
end
|
||||
// if both units are ready, invalidate the buffer flag
|
||||
if (ld_ready_o && st_ready_o) begin
|
||||
lsu_ctrl_nn.valid = 1'b0;
|
||||
end
|
||||
// get new input data
|
||||
if (lsu_ready_o) begin
|
||||
lsu_ctrl_n = {lsu_valid_i, vaddr_i, operand_b_i, be_i, fu_i, operator_i, trans_id_i};
|
||||
end
|
||||
// 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.
|
||||
|
||||
if (flush_i) begin
|
||||
lsu_ctrl_nn.valid = 1'b0;
|
||||
lsu_ctrl_n.valid = 1'b0;
|
||||
end
|
||||
end
|
||||
// new data arrives here
|
||||
lsu_ctrl_t lsu_req_i;
|
||||
|
||||
// registers
|
||||
always_ff @(posedge clk_i or negedge rst_ni) begin
|
||||
if (~rst_ni) begin
|
||||
// 1st LSU stage
|
||||
lsu_ctrl_q <= '0;
|
||||
lsu_ctrl_qq <= '0;
|
||||
end else begin
|
||||
// 1st LSU stage
|
||||
lsu_ctrl_q <= lsu_ctrl_n;
|
||||
lsu_ctrl_qq <= lsu_ctrl_nn;
|
||||
end
|
||||
end
|
||||
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 ),
|
||||
.lus_req_valid_i ( lsu_valid_i ),
|
||||
.pop_ld_i ( pop_ld ),
|
||||
.pop_st_i ( pop_st ),
|
||||
|
||||
.ld_ready_i ( ld_ready_o ),
|
||||
.st_ready_i ( st_ready_o),
|
||||
|
||||
.lsu_ctrl_o ( lsu_ctrl ),
|
||||
.ready_o ( lsu_ready_o ),
|
||||
.*
|
||||
);
|
||||
// ------------
|
||||
// Assertions
|
||||
// ------------
|
||||
|
@ -526,4 +498,98 @@ module lsu #(
|
|||
// else begin $error("address contains X when request is set"); $stop(); end
|
||||
`endif
|
||||
`endif
|
||||
endmodule
|
||||
endmodule
|
||||
|
||||
module lsu_bypass (
|
||||
input logic clk_i,
|
||||
input logic rst_ni,
|
||||
input logic flush_i,
|
||||
|
||||
input lsu_ctrl_t lsu_req_i,
|
||||
input logic lus_req_valid_i,
|
||||
input logic pop_ld_i,
|
||||
input logic pop_st_i,
|
||||
|
||||
input logic ld_ready_i,
|
||||
input logic st_ready_i,
|
||||
|
||||
output lsu_ctrl_t lsu_ctrl_o,
|
||||
output logic ready_o
|
||||
);
|
||||
|
||||
lsu_ctrl_t [1:0] mem_n, mem_q;
|
||||
logic read_pointer_n, read_pointer_q;
|
||||
logic write_pointer_n, write_pointer_q;
|
||||
int status_cnt_n, status_cnt_q;
|
||||
|
||||
logic empty;
|
||||
assign empty = (status_cnt_q == 0);
|
||||
assign ready_o = empty;
|
||||
|
||||
always_comb begin
|
||||
automatic int status_cnt = status_cnt_q;
|
||||
automatic logic write_pointer = write_pointer_q;
|
||||
automatic logic read_pointer = read_pointer_q;
|
||||
|
||||
mem_n = mem_q;
|
||||
// we've got a valid LSU request
|
||||
if (lus_req_valid_i) begin
|
||||
mem_n[write_pointer_q] = lsu_req_i;
|
||||
write_pointer++;
|
||||
status_cnt++;
|
||||
end
|
||||
|
||||
if (pop_ld_i) begin
|
||||
// invalidate the result
|
||||
mem_n[read_pointer_q].valid = 1'b0;
|
||||
read_pointer++;
|
||||
status_cnt--;
|
||||
end
|
||||
|
||||
if (pop_st_i) begin
|
||||
// invalidate the result
|
||||
mem_n[read_pointer_q].valid = 1'b0;
|
||||
read_pointer++;
|
||||
status_cnt--;
|
||||
end
|
||||
|
||||
if (pop_st_i && pop_ld_i)
|
||||
mem_n = '{default: 0};
|
||||
|
||||
if (flush_i) begin
|
||||
status_cnt = '0;
|
||||
write_pointer = '0;
|
||||
read_pointer = '0;
|
||||
mem_n = '{default: 0};
|
||||
end
|
||||
// default assignments
|
||||
read_pointer_n = read_pointer;
|
||||
write_pointer_n = write_pointer;
|
||||
status_cnt_n = status_cnt;
|
||||
end
|
||||
|
||||
// output assignment
|
||||
always_comb begin : output_assignments
|
||||
if (empty) begin
|
||||
lsu_ctrl_o = lsu_req_i;
|
||||
end else begin
|
||||
lsu_ctrl_o = mem_q[read_pointer_q];
|
||||
end
|
||||
end
|
||||
|
||||
// registers
|
||||
always_ff @(posedge clk_i or negedge rst_ni) begin
|
||||
if(~rst_ni) begin
|
||||
mem_q <= '{default: 0};
|
||||
status_cnt_q <= '0;
|
||||
write_pointer_q <= '0;
|
||||
read_pointer_q <= '0;
|
||||
end else begin
|
||||
mem_q <= mem_n;
|
||||
status_cnt_q <= status_cnt_n;
|
||||
write_pointer_q <= write_pointer_n;
|
||||
read_pointer_q <= read_pointer_n;
|
||||
end
|
||||
end
|
||||
endmodule
|
||||
|
||||
|
|
38
src/mmu.sv
38
src/mmu.sv
|
@ -86,14 +86,14 @@ module mmu #(
|
|||
);
|
||||
// instruction error
|
||||
// instruction error valid signal and exception, delayed one cycle
|
||||
logic ierr_valid_q, ierr_valid_n;
|
||||
exception fetch_ex_q, fetch_ex_n;
|
||||
logic ierr_valid_q, ierr_valid_n;
|
||||
exception fetch_ex_q, fetch_ex_n;
|
||||
|
||||
logic iaccess_err; // insufficient privilege to access this instruction page
|
||||
logic daccess_err; // insufficient privilege to access this data page
|
||||
logic ptw_active; // PTW is currently walking a page table
|
||||
logic walking_instr; // PTW is walking because of an ITLB miss
|
||||
logic ptw_error; // PTW threw an exception
|
||||
logic iaccess_err; // insufficient privilege to access this instruction page
|
||||
logic daccess_err; // insufficient privilege to access this data page
|
||||
logic ptw_active; // PTW is currently walking a page table
|
||||
logic walking_instr; // PTW is walking because of an ITLB miss
|
||||
logic ptw_error; // PTW threw an exception
|
||||
|
||||
logic update_is_2M;
|
||||
logic update_is_1G;
|
||||
|
@ -101,19 +101,19 @@ module mmu #(
|
|||
logic [0:0] update_asid;
|
||||
pte_t update_content;
|
||||
|
||||
logic itlb_update;
|
||||
logic itlb_lu_access;
|
||||
pte_t itlb_content;
|
||||
logic itlb_is_2M;
|
||||
logic itlb_is_1G;
|
||||
logic itlb_lu_hit;
|
||||
logic itlb_update;
|
||||
logic itlb_lu_access;
|
||||
pte_t itlb_content;
|
||||
logic itlb_is_2M;
|
||||
logic itlb_is_1G;
|
||||
logic itlb_lu_hit;
|
||||
|
||||
logic dtlb_update;
|
||||
logic dtlb_lu_access;
|
||||
pte_t dtlb_content;
|
||||
logic dtlb_is_2M;
|
||||
logic dtlb_is_1G;
|
||||
logic dtlb_lu_hit;
|
||||
logic dtlb_update;
|
||||
logic dtlb_lu_access;
|
||||
pte_t dtlb_content;
|
||||
logic dtlb_is_2M;
|
||||
logic dtlb_is_1G;
|
||||
logic dtlb_lu_hit;
|
||||
|
||||
// Assignments
|
||||
assign itlb_lu_access = fetch_req_i;
|
||||
|
|
|
@ -26,6 +26,7 @@ module store_unit (
|
|||
// store unit input port
|
||||
input logic valid_i,
|
||||
input lsu_ctrl_t lsu_ctrl_i,
|
||||
output logic pop_st_o,
|
||||
input logic commit_i,
|
||||
// store unit output port
|
||||
output logic valid_o,
|
||||
|
@ -79,6 +80,7 @@ module store_unit (
|
|||
ready_o = 1'b1;
|
||||
valid_o = 1'b0;
|
||||
st_valid = 1'b0;
|
||||
pop_st_o = 1'b0;
|
||||
ex_o = ex_i;
|
||||
trans_id_n = lsu_ctrl_i.trans_id;
|
||||
NS = CS;
|
||||
|
@ -104,27 +106,31 @@ module store_unit (
|
|||
end
|
||||
|
||||
VALID_STORE: begin
|
||||
ready_o = 1'b0;
|
||||
valid_o = 1'b1;
|
||||
// post this store to the store buffer
|
||||
if (!flush_i)
|
||||
st_valid = 1'b1;
|
||||
|
||||
// we have another request
|
||||
if (valid_i) begin
|
||||
pop_st_o = 1'b1;
|
||||
|
||||
translation_req_o = 1'b1;
|
||||
// // we have another request
|
||||
// if (valid_i) begin
|
||||
|
||||
if (!dtlb_hit_i) begin
|
||||
NS = WAIT_TRANSLATION;
|
||||
end
|
||||
// translation_req_o = 1'b1;
|
||||
|
||||
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
|
||||
// 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;
|
||||
end
|
||||
|
||||
// the store queue is currently full
|
||||
|
|
|
@ -14,18 +14,22 @@ add wave -noupdate -group issue_stage -group issue_read_operands /core_tb/dut/is
|
|||
add wave -noupdate -group issue_stage /core_tb/dut/issue_stage_i/*
|
||||
|
||||
add wave -noupdate -group ex_stage -group alu /core_tb/dut/ex_stage_i/alu_i/*
|
||||
|
||||
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 lsu_bypass /core_tb/dut/ex_stage_i/lsu_i/lsu_bypass_i/*
|
||||
add wave -noupdate -group ex_stage -group lsu -group mmu /core_tb/dut/ex_stage_i/lsu_i/mmu_i/*
|
||||
add wave -noupdate -group ex_stage -group lsu -group mmu -group itlb /core_tb/dut/ex_stage_i/lsu_i/mmu_i/itlb_i/*
|
||||
add wave -noupdate -group ex_stage -group lsu -group mmu -group dtlb /core_tb/dut/ex_stage_i/lsu_i/mmu_i/dtlb_i/*
|
||||
add wave -noupdate -group ex_stage -group lsu -group mmu -group ptw /core_tb/dut/ex_stage_i/lsu_i/mmu_i/ptw_i/*
|
||||
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 lsu_arbiter /core_tb/dut/ex_stage_i/lsu_i/lsu_arbiter_i/*
|
||||
|
||||
add wave -noupdate -group ex_stage -group branch_unit /core_tb/dut/ex_stage_i/branch_unit_i/*
|
||||
|
||||
add wave -noupdate -group ex_stage -group csr_buffer /core_tb/dut/ex_stage_i/csr_buffer_i/*
|
||||
add wave -noupdate -group ex_stage /core_tb/dut/ex_stage_i/*
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue