blob: 5d069fe92c793da5775bdfee799d7a412b6d9af3 [file] [log] [blame]
/////////////////////////
// Author: Peichen Guo //
// RIOS Lab work //
// HeHe Core //
/////////////////////////
`ifndef LSQ_V
`define LSQ_V
`include "../params.vh"
module lsq (
// global input
input clk,
input rstn,
input flush,
// <> s0
input [VIRTUAL_ADDR_LEN - 1 : 0] address_i,
input [ROB_INDEX_WIDTH - 1 : 0] rob_index_i,
input [XLEN - 1 : 0] rs2_data_i,
input opcode_i,
input [1:0] size_i,
input load_sign_i,
input valid_i,
input [PHY_REG_ADDR_WIDTH - 1 : 0] rd_addr_i,
input [EXCEPTION_CODE_WIDTH - 1 : 0] ecause_i,
input exception_valid_i,
// <> rob
output load_data_valid_o,
output [XLEN - 1 : 0] load_data_o,
output [PHY_REG_ADDR_WIDTH - 1 : 0] rd_addr_o,
output [ROB_INDEX_WIDTH - 1 : 0] rob_index_o,
output ls_done_o,
output lsu_ready_o,
output exception_valid_o,
output [EXCEPTION_CODE_WIDTH - 1 : 0] ecause_o,
// lsu <> dcache
input req_ready_i,
output req_valid_o,
output req_opcode_o, // 0 for load, 1 for store
output req_sign_o,
output [1:0] req_size_o,
output [VIRTUAL_ADDR_LEN - 1 : 0] req_addr_o,
output [XLEN - 1 : 0] req_data_o,
// output [ROB_INDEX_WIDTH - 1 : 0] req_rob_index_o,
output [LSU_LSQ_SIZE_WIDTH - 1: 0] req_lsq_index_o,
input resp_valid_i,
input [LSU_LSQ_SIZE_WIDTH - 1: 0] resp_lsq_index_i,
input [XLEN - 1 : 0]resp_data_i,
output resp_ready_o
);
reg [LSU_LOAD_QUEUE_ENTRY_WIDTH - 1 : 0] load_store_queue[LSU_LSQ_SIZE -1 : 0];
reg [XLEN - 1 : 0] store_data_queue[LSU_LSQ_SIZE -1 : 0];
reg [XLEN - 1 : 0] load_data_queue[LSU_LSQ_SIZE -1 : 0];
wire [LSU_LSQ_SIZE_WIDTH - 1 : 0] head;
wire [LSU_LSQ_SIZE_WIDTH - 1 : 0] tail;
wire [LSU_LSQ_SIZE_WIDTH - 1 : 0] req_pt;
wire rob_in_ready = ~load_store_queue[tail][0]; // tail entry can write
wire enque = rob_in_ready & valid_i;
wire resp_bypass = (resp_valid_i & (resp_lsq_index_i == head));
// FIXME: 这里时序非常差 verilator里需要半个周期来setup
wire rob_out_valid = (load_store_queue[head][0] & load_store_queue[head][1]) | // valid & done
resp_bypass; // correct resp
wire deque = rob_out_valid ; // done and
wire req_valid = load_store_queue[req_pt][0] & ~load_store_queue[req_pt][2] &
~load_store_queue[req_pt][3]; // valid & ~send & ~exception
wire req_send = req_valid & req_ready_i;
wire resp_ready = 1; // FIXME: 不知道啥时候不会是1 
wire resp_accept = resp_ready & resp_valid_i;
wire [LSU_LOAD_QUEUE_ENTRY_WIDTH - 1 : 0] load_entry_in;
assign load_entry_in =
// { 51 : 20 19 : 18 17 : 12 11 : 10 9 8
{address_i, rob_index_i, rd_addr_i, size_i, load_sign_i, opcode_i,
// 7:4 3 2(send) 1(done) 0(valid)
ecause_i, exception_valid_i, exception_valid_i, exception_valid_i, valid_i};
assign req_valid_o = req_valid;
assign req_opcode_o = load_store_queue[req_pt][8];
assign req_sign_o = load_store_queue[req_pt][9];
assign req_size_o = load_store_queue[req_pt][11:10];
// assign req_rob_index_o = load_store_queue[req_pt][20:18];
assign req_addr_o = load_store_queue[req_pt][51:20];
assign req_data_o = store_data_queue[req_pt];
assign req_lsq_index_o = req_pt;
assign resp_ready_o = resp_ready;
assign ls_done_o = rob_out_valid; // valid & done | correct_resp
assign load_data_valid_o = rob_out_valid & (load_store_queue[head][8] == 0); // valid & done & load
assign load_data_o = resp_bypass ? resp_data_i : load_data_queue[head];
assign rd_addr_o = load_store_queue[head][17:12];
assign rob_index_o = load_store_queue[head][19:18];
assign exception_valid_o = rob_out_valid & load_store_queue[head][3];
assign ecause_o = load_store_queue[head][7 : 4];
assign lsu_ready_o = rob_in_ready;
always @(posedge clk) begin
// $display("bypass:%x", resp_bypass);
// $display("resp_valid_i:%x", resp_valid_i);
if(rstn | flush) begin
integer rst_flush_gen_i;
for(rst_flush_gen_i = 0; rst_flush_gen_i < LSU_LSQ_SIZE;
rst_flush_gen_i = rst_flush_gen_i + 1) begin
load_store_queue[rst_flush_gen_i] <= '0;
load_data_queue[rst_flush_gen_i] <= '0;
store_data_queue[rst_flush_gen_i] <= '0;
end
end
else begin
if(enque) begin
// $display("lsq enque,opcode: %h, tail is %h @ 0x%h",
// opcode_i, tail, address_i);
load_store_queue[tail] <= load_entry_in;
if(opcode_i) begin // store
store_data_queue[tail] <= rs2_data_i;
end
end
if(enque)
store_data_queue[tail] <= rs2_data_i;
if(req_send) begin
// if((load_store_queue[req_pt][52:21] & 'h10000) == 0)
// $display("lsq req send @ %x, req_pt is %h, opcode: %h",
// load_store_queue[req_pt][52:21], req_pt, load_store_queue[req_pt][8]);
load_store_queue[req_pt][2] <= 1'b1; // send
if(load_store_queue[req_pt][8] == 1) begin
load_store_queue[req_pt][1] <= 1'b1; // set store done
end
end
if(resp_accept) begin
// FIXME: 此时假定resp为head时不需要写入。因为假定了rob 永远ready
// $display("lsq resp recieve @%x, lsq id is %h, data is %h",
// load_store_queue[resp_lsq_index_i][52:21], resp_lsq_index_i, resp_data_i);
if(resp_lsq_index_i != head) begin //需要写入data寄存器
load_store_queue[resp_lsq_index_i][1] <= 1'b1; // set done
load_data_queue[resp_lsq_index_i] <= resp_data_i;
end
end
if(deque) begin
// $display("lsq deque, head is %h", head);
load_store_queue[head][0] <= 0;
end
end
end
//head pointer
counter #(
.CNT_SIZE(LSU_LSQ_SIZE),
.CNT_SIZE_WIDTH(LSU_LSQ_SIZE_WIDTH)
) queue_head_cnt(
.clk(clk),
.reset(rstn),
.cnt_add_flag(deque),
.cnt(head),
/* verilator lint_off PINCONNECTEMPTY */
.cnt_end()
/* verilator lint_on PINCONNECTEMPTY */
);
//tail pointer
counter #(
.CNT_SIZE(LSU_LSQ_SIZE),
.CNT_SIZE_WIDTH(LSU_LSQ_SIZE_WIDTH)
) queue_tail_cnt(
.clk(clk),
.reset(rstn),
.cnt_add_flag(enque),
.cnt(tail),
/* verilator lint_off PINCONNECTEMPTY */
.cnt_end()
/* verilator lint_on PINCONNECTEMPTY */
);
// req_pt emit pointer
counter #(
.CNT_SIZE(LSU_LSQ_SIZE),
.CNT_SIZE_WIDTH(LSU_LSQ_SIZE_WIDTH)
) queue_req_cnt(
.clk(clk),
.reset(rstn),
.cnt_add_flag(req_send),
.cnt(req_pt),
/* verilator lint_off PINCONNECTEMPTY */
.cnt_end()
/* verilator lint_on PINCONNECTEMPTY */
);
endmodule
`endif //LSQ_V