New LSU arbitration scheme

This commit is contained in:
Florian Zaruba 2017-06-23 22:58:00 +02:00
parent 43959a587b
commit ff91fdbfec
8 changed files with 182 additions and 101 deletions

View file

@ -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;

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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;

View file

@ -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

View file

@ -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/*