mirror of
https://github.com/lowRISC/ibex.git
synced 2025-04-22 12:57:13 -04:00
LSU cleanup, abort misaligned ops if first part fails
This commit cleans up the LSU and fixes two bugs: 1. If a misalgned transaction creates an error during the first part of the transaction, the second part is not pushed out and the transaction is aborted. Previously, the LSU tried to output also the second part but did not adhere to the defined protocol. 2. Misaligned operations are again working correctly. Previously, the generation of the byte enable and the alignment of read data was broken as these operations rely on the updated address from the AGU to have the same alignment as the original address. This partially resolves #121.
This commit is contained in:
parent
c84ca25755
commit
8613e880fc
4 changed files with 230 additions and 246 deletions
|
@ -130,7 +130,8 @@ module ibex_core #(
|
|||
// ID performance counter signals
|
||||
logic is_decoding;
|
||||
|
||||
logic data_misaligned;
|
||||
// LSU signals
|
||||
logic lsu_addr_incr_req;
|
||||
logic [31:0] lsu_addr_last;
|
||||
|
||||
// Jump and branch target and decision (EX->IF)
|
||||
|
@ -187,7 +188,7 @@ module ibex_core #(
|
|||
logic if_valid;
|
||||
logic id_valid;
|
||||
|
||||
logic data_valid_lsu;
|
||||
logic lsu_data_valid;
|
||||
|
||||
// Signals between instruction core interface and pipe (if and id stages)
|
||||
logic instr_req_int; // Id stage asserts a req to instruction core interface
|
||||
|
@ -391,7 +392,7 @@ module ibex_core #(
|
|||
|
||||
.id_ready_o ( id_ready ),
|
||||
.ex_valid_i ( ex_valid ),
|
||||
.lsu_valid_i ( data_valid_lsu ),
|
||||
.lsu_valid_i ( lsu_data_valid ),
|
||||
|
||||
.id_valid_o ( id_valid ),
|
||||
|
||||
|
@ -425,7 +426,7 @@ module ibex_core #(
|
|||
.data_reg_offset_ex_o ( data_reg_offset_ex ), // to load store unit
|
||||
.data_wdata_ex_o ( data_wdata_ex ), // to load store unit
|
||||
|
||||
.data_misaligned_i ( data_misaligned ),
|
||||
.lsu_addr_incr_req_i ( lsu_addr_incr_req ),
|
||||
.lsu_addr_last_i ( lsu_addr_last ),
|
||||
|
||||
.lsu_load_err_i ( lsu_load_err ),
|
||||
|
@ -501,44 +502,42 @@ module ibex_core #(
|
|||
/////////////////////
|
||||
|
||||
ibex_load_store_unit load_store_unit_i (
|
||||
.clk_i ( clk ),
|
||||
.rst_ni ( rst_ni ),
|
||||
.clk_i ( clk ),
|
||||
.rst_ni ( rst_ni ),
|
||||
|
||||
//output to data memory
|
||||
.data_req_o ( data_req_o ),
|
||||
.data_gnt_i ( data_gnt_i ),
|
||||
.data_rvalid_i ( data_rvalid_i ),
|
||||
.data_err_i ( data_err_i ),
|
||||
// data interface
|
||||
.data_req_o ( data_req_o ),
|
||||
.data_gnt_i ( data_gnt_i ),
|
||||
.data_rvalid_i ( data_rvalid_i ),
|
||||
.data_err_i ( data_err_i ),
|
||||
|
||||
.data_addr_o ( data_addr_o ),
|
||||
.data_we_o ( data_we_o ),
|
||||
.data_be_o ( data_be_o ),
|
||||
.data_wdata_o ( data_wdata_o ),
|
||||
.data_rdata_i ( data_rdata_i ),
|
||||
.data_addr_o ( data_addr_o ),
|
||||
.data_we_o ( data_we_o ),
|
||||
.data_be_o ( data_be_o ),
|
||||
.data_wdata_o ( data_wdata_o ),
|
||||
.data_rdata_i ( data_rdata_i ),
|
||||
|
||||
// signal from ex stage
|
||||
.data_we_ex_i ( data_we_ex ),
|
||||
.data_type_ex_i ( data_type_ex ),
|
||||
.data_wdata_ex_i ( data_wdata_ex ),
|
||||
.data_reg_offset_ex_i ( data_reg_offset_ex ),
|
||||
.data_sign_ext_ex_i ( data_sign_ext_ex ),
|
||||
// signals to/from ID/EX stage
|
||||
.data_we_ex_i ( data_we_ex ),
|
||||
.data_type_ex_i ( data_type_ex ),
|
||||
.data_wdata_ex_i ( data_wdata_ex ),
|
||||
.data_reg_offset_ex_i ( data_reg_offset_ex ),
|
||||
.data_sign_ext_ex_i ( data_sign_ext_ex ),
|
||||
|
||||
.data_rdata_ex_o ( regfile_wdata_lsu ),
|
||||
.data_req_ex_i ( data_req_ex ),
|
||||
.data_rdata_ex_o ( regfile_wdata_lsu ),
|
||||
.data_req_ex_i ( data_req_ex ),
|
||||
|
||||
.adder_result_ex_i ( alu_adder_result_ex),
|
||||
.adder_result_ex_i ( alu_adder_result_ex ),
|
||||
|
||||
.data_misaligned_o ( data_misaligned ),
|
||||
.addr_last_o ( lsu_addr_last ),
|
||||
.addr_incr_req_o ( lsu_addr_incr_req ),
|
||||
.addr_last_o ( lsu_addr_last ),
|
||||
.data_valid_o ( lsu_data_valid ),
|
||||
|
||||
// exception signals
|
||||
.load_err_o ( lsu_load_err ),
|
||||
.store_err_o ( lsu_store_err ),
|
||||
.load_err_o ( lsu_load_err ),
|
||||
.store_err_o ( lsu_store_err ),
|
||||
|
||||
// control signals
|
||||
.data_valid_o ( data_valid_lsu ),
|
||||
.lsu_update_addr_o ( ),
|
||||
.busy_o ( lsu_busy )
|
||||
.busy_o ( lsu_busy )
|
||||
);
|
||||
|
||||
|
||||
|
@ -780,7 +779,7 @@ module ibex_core #(
|
|||
.ex_reg_addr_i ( id_stage_i.regfile_waddr ),
|
||||
.ex_reg_we_i ( id_stage_i.regfile_we ),
|
||||
.ex_reg_wdata_i ( id_stage_i.regfile_wdata ),
|
||||
.data_valid_lsu_i ( data_valid_lsu ),
|
||||
.lsu_data_valid_i ( lsu_data_valid ),
|
||||
.ex_data_addr_i ( data_addr_o ),
|
||||
.ex_data_req_i ( data_req_o ),
|
||||
.ex_data_gnt_i ( data_gnt_i ),
|
||||
|
|
|
@ -106,7 +106,7 @@ module ibex_id_stage #(
|
|||
output logic [1:0] data_reg_offset_ex_o,
|
||||
output logic [31:0] data_wdata_ex_o,
|
||||
|
||||
input logic data_misaligned_i,
|
||||
input logic lsu_addr_incr_req_i,
|
||||
input logic [31:0] lsu_addr_last_i,
|
||||
|
||||
// Interrupt signals
|
||||
|
@ -240,12 +240,12 @@ module ibex_id_stage #(
|
|||
/////////////
|
||||
|
||||
// Misaligned loads/stores result in two aligned loads/stores, compute second address
|
||||
assign alu_op_a_mux_sel = data_misaligned_i ? OP_A_FWD : alu_op_a_mux_sel_dec;
|
||||
assign alu_op_b_mux_sel = data_misaligned_i ? OP_B_IMM : alu_op_b_mux_sel_dec;
|
||||
assign imm_b_mux_sel = data_misaligned_i ? IMM_B_INCR_ADDR : imm_b_mux_sel_dec;
|
||||
assign alu_op_a_mux_sel = lsu_addr_incr_req_i ? OP_A_FWD : alu_op_a_mux_sel_dec;
|
||||
assign alu_op_b_mux_sel = lsu_addr_incr_req_i ? OP_B_IMM : alu_op_b_mux_sel_dec;
|
||||
assign imm_b_mux_sel = lsu_addr_incr_req_i ? IMM_B_INCR_ADDR : imm_b_mux_sel_dec;
|
||||
|
||||
// do not write back the second address since the first calculated address was the correct one
|
||||
assign regfile_we_id = data_misaligned_i ? 1'b0 : regfile_we_dec & ~deassert_we;
|
||||
assign regfile_we_id = lsu_addr_incr_req_i ? 1'b0 : regfile_we_dec & ~deassert_we;
|
||||
|
||||
///////////////////
|
||||
// Operand A MUX //
|
||||
|
@ -287,7 +287,7 @@ module ibex_id_stage #(
|
|||
assign alu_operand_b = (alu_op_b_mux_sel == OP_B_IMM) ? imm_b : regfile_rdata_b;
|
||||
|
||||
// Signals used by tracer
|
||||
assign operand_a_fw_id = data_misaligned_i ? lsu_addr_last_i : regfile_rdata_a;
|
||||
assign operand_a_fw_id = lsu_addr_incr_req_i ? lsu_addr_last_i : regfile_rdata_a;
|
||||
assign operand_b_fw_id = regfile_rdata_b;
|
||||
|
||||
assign unused_operand_a_fw_id = operand_a_fw_id;
|
||||
|
@ -676,7 +676,7 @@ module ibex_id_stage #(
|
|||
|
||||
`ifdef CHECK_MISALIGNED
|
||||
assert property (
|
||||
@(posedge clk_i) (~data_misaligned_i) ) else
|
||||
@(posedge clk_i) (~lsu_addr_incr_req_i) ) else
|
||||
$display("Misaligned memory access at %x",pc_id_i);
|
||||
`endif
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ module ibex_load_store_unit (
|
|||
input logic clk_i,
|
||||
input logic rst_ni,
|
||||
|
||||
// output to data memory
|
||||
// data interface
|
||||
output logic data_req_o,
|
||||
input logic data_gnt_i,
|
||||
input logic data_rvalid_i,
|
||||
|
@ -42,52 +42,56 @@ module ibex_load_store_unit (
|
|||
output logic [31:0] data_wdata_o,
|
||||
input logic [31:0] data_rdata_i,
|
||||
|
||||
// signals from ex stage
|
||||
input logic data_we_ex_i, // write enable -> from EX
|
||||
input logic [1:0] data_type_ex_i, // data type: word, half word, byte -> from EX
|
||||
input logic [31:0] data_wdata_ex_i, // data to write to memory -> from EX
|
||||
input logic [1:0] data_reg_offset_ex_i, // register byte offset for stores -> from EX
|
||||
input logic data_sign_ext_ex_i, // sign extension -> from EX
|
||||
// signals to/from ID/EX stage
|
||||
input logic data_we_ex_i, // write enable -> from ID/EX
|
||||
input logic [1:0] data_type_ex_i, // data type: word, half word, byte -> from ID/EX
|
||||
input logic [31:0] data_wdata_ex_i, // data to write to memory -> from ID/EX
|
||||
input logic [1:0] data_reg_offset_ex_i, // register byte offset for stores -> from ID/EX
|
||||
input logic data_sign_ext_ex_i, // sign extension -> from ID/EX
|
||||
|
||||
output logic [31:0] data_rdata_ex_o, // requested data -> to EX
|
||||
input logic data_req_ex_i, // data request -> from EX
|
||||
output logic [31:0] data_rdata_ex_o, // requested data -> to ID/EX
|
||||
input logic data_req_ex_i, // data request -> from ID/EX
|
||||
|
||||
input logic [31:0] adder_result_ex_i, // address computed in ALU -> from EX
|
||||
input logic [31:0] adder_result_ex_i, // address computed in ALU -> from ID/EX
|
||||
|
||||
output logic data_misaligned_o, // misaligned access detected -> to controller
|
||||
output logic addr_incr_req_o, // request address increment for
|
||||
// misaligned accesses -> to ID/EX
|
||||
output logic [31:0] addr_last_o, // address of last transaction -> to controller
|
||||
// -> mtval
|
||||
// -> AGU for misaligned accesses
|
||||
output logic data_valid_o, // LSU has completed transaction -> to
|
||||
|
||||
// exception signals
|
||||
output logic load_err_o,
|
||||
output logic store_err_o,
|
||||
|
||||
// stall signal
|
||||
output logic lsu_update_addr_o, // LSU ready for new data in EX stage
|
||||
output logic data_valid_o,
|
||||
|
||||
output logic busy_o
|
||||
);
|
||||
|
||||
logic [31:0] data_addr;
|
||||
logic [31:0] data_addr_w_aligned;
|
||||
logic [31:0] addr_last_q, addr_last_n;
|
||||
logic [31:0] addr_last_q, addr_last_d;
|
||||
|
||||
// registers for data_rdata alignment and sign extension
|
||||
logic [1:0] data_type_q;
|
||||
logic [1:0] rdata_offset_q;
|
||||
logic data_sign_ext_q;
|
||||
logic data_we_q;
|
||||
logic [31:0] rdata_q, rdata_d;
|
||||
logic [1:0] rdata_offset_q, rdata_offset_d;
|
||||
logic [1:0] data_type_q, data_type_d;
|
||||
logic data_sign_ext_q, data_sign_ext_d;
|
||||
logic data_we_q, data_we_d;
|
||||
|
||||
logic [1:0] wdata_offset; // mux control for data to be written to memory
|
||||
|
||||
logic [3:0] data_be;
|
||||
logic [31:0] data_wdata;
|
||||
|
||||
logic misaligned_st; // high if we are currently performing the second part
|
||||
// of a misaligned store
|
||||
logic data_misaligned, data_misaligned_q;
|
||||
logic [31:0] data_rdata_ext;
|
||||
|
||||
logic [31:0] rdata_w_ext; // word realignment for misaligned loads
|
||||
logic [31:0] rdata_h_ext; // sign extension for half words
|
||||
logic [31:0] rdata_b_ext; // sign extension for bytes
|
||||
|
||||
logic split_misaligned_access;
|
||||
logic handle_misaligned_q, handle_misaligned_d; // high after receiving grant for first
|
||||
// part of a misaligned access
|
||||
|
||||
typedef enum logic [2:0] {
|
||||
IDLE, WAIT_GNT_MIS, WAIT_RVALID_MIS, WAIT_GNT, WAIT_RVALID
|
||||
|
@ -95,15 +99,16 @@ module ibex_load_store_unit (
|
|||
|
||||
ls_fsm_e ls_fsm_cs, ls_fsm_ns;
|
||||
|
||||
logic [31:0] rdata_q;
|
||||
assign data_addr = adder_result_ex_i;
|
||||
|
||||
///////////////////
|
||||
// BE generation //
|
||||
///////////////////
|
||||
|
||||
always_comb begin
|
||||
unique case (data_type_ex_i) // Data type 00 Word, 01 Half word, 11,10 byte
|
||||
2'b00: begin // Writing a word
|
||||
if (!misaligned_st) begin // non-misaligned case
|
||||
if (!handle_misaligned_q) begin // first part of potentially misaligned transaction
|
||||
unique case (data_addr[1:0])
|
||||
2'b00: data_be = 4'b1111;
|
||||
2'b01: data_be = 4'b1110;
|
||||
|
@ -111,7 +116,7 @@ module ibex_load_store_unit (
|
|||
2'b11: data_be = 4'b1000;
|
||||
default: data_be = 'X;
|
||||
endcase // case (data_addr[1:0])
|
||||
end else begin // misaligned case
|
||||
end else begin // second part of misaligned transaction
|
||||
unique case (data_addr[1:0])
|
||||
2'b00: data_be = 4'b0000; // this is not used, but included for completeness
|
||||
2'b01: data_be = 4'b0001;
|
||||
|
@ -123,7 +128,7 @@ module ibex_load_store_unit (
|
|||
end
|
||||
|
||||
2'b01: begin // Writing a half word
|
||||
if (!misaligned_st) begin // non-misaligned case
|
||||
if (!handle_misaligned_q) begin // first part of potentially misaligned transaction
|
||||
unique case (data_addr[1:0])
|
||||
2'b00: data_be = 4'b0011;
|
||||
2'b01: data_be = 4'b0110;
|
||||
|
@ -131,7 +136,7 @@ module ibex_load_store_unit (
|
|||
2'b11: data_be = 4'b1000;
|
||||
default: data_be = 'X;
|
||||
endcase // case (data_addr[1:0])
|
||||
end else begin // misaligned case
|
||||
end else begin // second part of misaligned transaction
|
||||
data_be = 4'b0001;
|
||||
end
|
||||
end
|
||||
|
@ -151,6 +156,10 @@ module ibex_load_store_unit (
|
|||
endcase // case (data_type_ex_i)
|
||||
end
|
||||
|
||||
/////////////////////
|
||||
// WData alignment //
|
||||
/////////////////////
|
||||
|
||||
// prepare data to be written to the memory
|
||||
// we handle misaligned accesses, half word and byte accesses and
|
||||
// register offsets here
|
||||
|
@ -165,32 +174,40 @@ module ibex_load_store_unit (
|
|||
endcase // case (wdata_offset)
|
||||
end
|
||||
|
||||
/////////////////////
|
||||
// RData alignment //
|
||||
/////////////////////
|
||||
|
||||
// FF for rdata alignment and sign-extension
|
||||
always_ff @(posedge clk_i or negedge rst_ni) begin
|
||||
if (!rst_ni) begin
|
||||
data_type_q <= 2'h0;
|
||||
rdata_offset_q <= 2'h0;
|
||||
data_sign_ext_q <= 1'b0;
|
||||
data_we_q <= 1'b0;
|
||||
end else if (data_gnt_i) begin
|
||||
// request was granted, we wait for rvalid and can continue to WB
|
||||
data_type_q <= data_type_ex_i;
|
||||
rdata_offset_q <= data_addr[1:0];
|
||||
data_sign_ext_q <= data_sign_ext_ex_i;
|
||||
data_we_q <= data_we_ex_i;
|
||||
// rdata_q holds data returned from memory for first part of misaligned loads
|
||||
always_comb begin
|
||||
rdata_d = rdata_q;
|
||||
if (data_rvalid_i & ~data_we_q & handle_misaligned_q) begin
|
||||
rdata_d = data_rdata_i;
|
||||
end
|
||||
end
|
||||
|
||||
////////////////////
|
||||
// Sign extension //
|
||||
////////////////////
|
||||
// update control signals for next read data upon receiving grant
|
||||
assign rdata_offset_d = data_gnt_i ? data_addr[1:0] : rdata_offset_q;
|
||||
assign data_type_d = data_gnt_i ? data_type_ex_i : data_type_q;
|
||||
assign data_sign_ext_d = data_gnt_i ? data_sign_ext_ex_i : data_sign_ext_q;
|
||||
assign data_we_d = data_gnt_i ? data_we_ex_i : data_we_q;
|
||||
|
||||
logic [31:0] data_rdata_ext;
|
||||
|
||||
logic [31:0] rdata_w_ext; // sign extension for words, actually only misaligned assembly
|
||||
logic [31:0] rdata_h_ext; // sign extension for half words
|
||||
logic [31:0] rdata_b_ext; // sign extension for bytes
|
||||
// registers for rdata alignment and sign-extension
|
||||
always_ff @(posedge clk_i or negedge rst_ni) begin
|
||||
if (!rst_ni) begin
|
||||
rdata_q <= '0;
|
||||
rdata_offset_q <= 2'h0;
|
||||
data_type_q <= 2'h0;
|
||||
data_sign_ext_q <= 1'b0;
|
||||
data_we_q <= 1'b0;
|
||||
end else begin
|
||||
rdata_q <= rdata_d;
|
||||
rdata_offset_q <= rdata_offset_d;
|
||||
data_type_q <= data_type_d;
|
||||
data_sign_ext_q <= data_sign_ext_d;
|
||||
data_we_q <= data_we_d;
|
||||
end
|
||||
end
|
||||
|
||||
// take care of misaligned words
|
||||
always_comb begin
|
||||
|
@ -203,6 +220,10 @@ module ibex_load_store_unit (
|
|||
endcase
|
||||
end
|
||||
|
||||
////////////////////
|
||||
// Sign extension //
|
||||
////////////////////
|
||||
|
||||
// sign extension for half words
|
||||
always_comb begin
|
||||
unique case (rdata_offset_q)
|
||||
|
@ -291,47 +312,130 @@ module ibex_load_store_unit (
|
|||
endcase //~case(rdata_type_q)
|
||||
end
|
||||
|
||||
// store last output address for mtval + AGU for misaligned transactions
|
||||
// do not update in case of errors, mtval needs the failing address
|
||||
/////////////
|
||||
// LSU FSM //
|
||||
/////////////
|
||||
|
||||
// check for misaligned accesses that need to be split into two word-aligned accesses
|
||||
assign split_misaligned_access =
|
||||
((data_type_ex_i == 2'b00) && (data_addr[1:0] != 2'b00)) || // misaligned word access
|
||||
((data_type_ex_i == 2'b01) && (data_addr[1:0] == 2'b11)); // misaligned half-word access
|
||||
|
||||
// FSM
|
||||
always_comb begin
|
||||
addr_last_n = addr_last_q;
|
||||
if (data_req_o & data_gnt_i & ~(load_err_o | store_err_o)) begin
|
||||
addr_last_n = data_addr_o;
|
||||
end
|
||||
end
|
||||
ls_fsm_ns = ls_fsm_cs;
|
||||
|
||||
always_ff @(posedge clk_i or negedge rst_ni) begin
|
||||
if (!rst_ni) begin
|
||||
ls_fsm_cs <= IDLE;
|
||||
addr_last_q <= '0;
|
||||
rdata_q <= '0;
|
||||
data_misaligned_q <= '0;
|
||||
end else begin
|
||||
ls_fsm_cs <= ls_fsm_ns;
|
||||
addr_last_q <= addr_last_n;
|
||||
if (lsu_update_addr_o) begin
|
||||
data_misaligned_q <= data_misaligned;
|
||||
end
|
||||
if (data_rvalid_i && !data_we_q) begin
|
||||
// if we have detected a misaligned access, and we are
|
||||
// currently doing the first part of this access, then
|
||||
// store the data coming from memory in rdata_q.
|
||||
// In all other cases, rdata_q gets the value that we are
|
||||
// writing to the register file
|
||||
data_req_o = 1'b0;
|
||||
data_valid_o = 1'b0;
|
||||
addr_incr_req_o = 1'b0;
|
||||
handle_misaligned_d = handle_misaligned_q;
|
||||
|
||||
if (data_misaligned_q || data_misaligned) begin
|
||||
rdata_q <= data_rdata_i;
|
||||
end else begin
|
||||
rdata_q <= data_rdata_ext;
|
||||
unique case (ls_fsm_cs)
|
||||
|
||||
IDLE: begin
|
||||
if (data_req_ex_i) begin
|
||||
data_req_o = 1'b1;
|
||||
if (data_gnt_i) begin
|
||||
handle_misaligned_d = split_misaligned_access;
|
||||
ls_fsm_ns = split_misaligned_access ? WAIT_RVALID_MIS : WAIT_RVALID;
|
||||
end else begin
|
||||
ls_fsm_ns = split_misaligned_access ? WAIT_GNT_MIS : WAIT_GNT;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
WAIT_GNT_MIS: begin
|
||||
data_req_o = 1'b1;
|
||||
if (data_gnt_i) begin
|
||||
handle_misaligned_d = 1'b1;
|
||||
ls_fsm_ns = WAIT_RVALID_MIS;
|
||||
end
|
||||
end
|
||||
|
||||
WAIT_RVALID_MIS: begin
|
||||
// tell ID/EX stage to update the address
|
||||
addr_incr_req_o = 1'b1;
|
||||
if (data_rvalid_i) begin
|
||||
// first part rvalid is received
|
||||
if (data_err_i) begin
|
||||
// first part created an error, abort transaction
|
||||
data_valid_o = 1'b1;
|
||||
handle_misaligned_d = 1'b0;
|
||||
ls_fsm_ns = IDLE;
|
||||
end else begin
|
||||
// push out second request
|
||||
data_req_o = 1'b1;
|
||||
if (data_gnt_i) begin
|
||||
// second grant is received
|
||||
ls_fsm_ns = WAIT_RVALID;
|
||||
end else begin
|
||||
// second grant is NOT received, but first rvalid
|
||||
ls_fsm_ns = WAIT_GNT;
|
||||
end
|
||||
end
|
||||
end else begin
|
||||
// first part rvalid is NOT received
|
||||
ls_fsm_ns = WAIT_RVALID_MIS;
|
||||
end
|
||||
end
|
||||
|
||||
WAIT_GNT: begin
|
||||
// tell ID/EX stage to update the address
|
||||
addr_incr_req_o = handle_misaligned_q;
|
||||
data_req_o = 1'b1;
|
||||
if (data_gnt_i) begin
|
||||
ls_fsm_ns = WAIT_RVALID;
|
||||
end
|
||||
end
|
||||
|
||||
WAIT_RVALID: begin
|
||||
data_req_o = 1'b0;
|
||||
if (data_rvalid_i) begin
|
||||
data_valid_o = 1'b1;
|
||||
handle_misaligned_d = 1'b0;
|
||||
ls_fsm_ns = IDLE;
|
||||
end else begin
|
||||
ls_fsm_ns = WAIT_RVALID;
|
||||
end
|
||||
end
|
||||
|
||||
default: begin
|
||||
ls_fsm_ns = ls_fsm_e'(1'bX);
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
// store last address for mtval + AGU for misaligned transactions:
|
||||
// - misaligned address needed for correct generation of data_be and data_rdata_ext
|
||||
// - do not update in case of errors, mtval needs the failing address
|
||||
always_comb begin
|
||||
addr_last_d = addr_last_q;
|
||||
if (data_req_o & data_gnt_i & ~(load_err_o | store_err_o)) begin
|
||||
addr_last_d = data_addr;
|
||||
end
|
||||
end
|
||||
|
||||
// output to register file
|
||||
assign data_rdata_ex_o = data_rvalid_i ? data_rdata_ext : rdata_q;
|
||||
// registers for FSM
|
||||
always_ff @(posedge clk_i or negedge rst_ni) begin
|
||||
if (!rst_ni) begin
|
||||
ls_fsm_cs <= IDLE;
|
||||
addr_last_q <= '0;
|
||||
handle_misaligned_q <= '0;
|
||||
end else begin
|
||||
ls_fsm_cs <= ls_fsm_ns;
|
||||
addr_last_q <= addr_last_d;
|
||||
handle_misaligned_q <= handle_misaligned_d;
|
||||
end
|
||||
end
|
||||
|
||||
// output data address must be aligned to word
|
||||
/////////////
|
||||
// Outputs //
|
||||
/////////////
|
||||
|
||||
// output to register file
|
||||
assign data_rdata_ex_o = data_rdata_ext;
|
||||
|
||||
// output data address must be word aligned
|
||||
assign data_addr_w_aligned = {data_addr[31:2], 2'b00};
|
||||
|
||||
// output to data interface
|
||||
|
@ -340,8 +444,7 @@ module ibex_load_store_unit (
|
|||
assign data_we_o = data_we_ex_i;
|
||||
assign data_be_o = data_be;
|
||||
|
||||
assign misaligned_st = data_misaligned_q;
|
||||
|
||||
// output to ID stage: mtval + AGU for misaligned transactions
|
||||
assign addr_last_o = addr_last_q;
|
||||
|
||||
// to know what kind of error to signal, we need to know the type of the transaction to which
|
||||
|
@ -349,130 +452,12 @@ module ibex_load_store_unit (
|
|||
assign load_err_o = data_err_i & data_rvalid_i & ~data_we_q;
|
||||
assign store_err_o = data_err_i & data_rvalid_i & data_we_q;
|
||||
|
||||
// FSM
|
||||
always_comb begin
|
||||
ls_fsm_ns = ls_fsm_cs;
|
||||
|
||||
data_req_o = 1'b0;
|
||||
|
||||
lsu_update_addr_o = 1'b0;
|
||||
|
||||
data_valid_o = 1'b0;
|
||||
data_misaligned_o = 1'b0;
|
||||
|
||||
unique case(ls_fsm_cs)
|
||||
// starts from not active and stays in IDLE until request was granted
|
||||
IDLE: begin
|
||||
if (data_req_ex_i) begin
|
||||
data_req_o = data_req_ex_i;
|
||||
if (data_gnt_i) begin
|
||||
lsu_update_addr_o = 1'b1;
|
||||
ls_fsm_ns = data_misaligned ? WAIT_RVALID_MIS : WAIT_RVALID;
|
||||
end else begin
|
||||
ls_fsm_ns = data_misaligned ? WAIT_GNT_MIS : WAIT_GNT;
|
||||
end
|
||||
end
|
||||
end // IDLE
|
||||
|
||||
WAIT_GNT_MIS: begin
|
||||
data_req_o = 1'b1;
|
||||
if (data_gnt_i) begin
|
||||
lsu_update_addr_o = 1'b1;
|
||||
ls_fsm_ns = WAIT_RVALID_MIS;
|
||||
end
|
||||
end // WAIT_GNT_MIS
|
||||
|
||||
// wait for rvalid in WB stage and send a new request if there is any
|
||||
WAIT_RVALID_MIS: begin
|
||||
//tell the controller to update the address
|
||||
data_misaligned_o = 1'b1;
|
||||
data_req_o = 1'b0;
|
||||
lsu_update_addr_o = data_gnt_i;
|
||||
|
||||
if (data_rvalid_i) begin
|
||||
//if first part rvalid is received
|
||||
data_req_o = 1'b1;
|
||||
if (data_gnt_i) begin
|
||||
//second grant is received
|
||||
ls_fsm_ns = WAIT_RVALID;
|
||||
//in this stage we already received the first valid but no the second one
|
||||
//it differes from WAIT_RVALID_MIS because we do not send other requests
|
||||
end else begin
|
||||
//second grant is NOT received, but first rvalid yes
|
||||
//lsu_update_addr_o is 0 so data_misaligned_q stays high in WAIT_GNT
|
||||
//increase address stays the same as well
|
||||
ls_fsm_ns = WAIT_GNT; // [1]
|
||||
end
|
||||
end else begin
|
||||
//if first part rvalid is NOT received
|
||||
//the second grand is not received either by protocol.
|
||||
//stay here
|
||||
ls_fsm_ns = WAIT_RVALID_MIS;
|
||||
end
|
||||
end
|
||||
|
||||
WAIT_GNT: begin
|
||||
data_misaligned_o = data_misaligned_q;
|
||||
//useful in case [1]
|
||||
data_req_o = 1'b1;
|
||||
if (data_gnt_i) begin
|
||||
lsu_update_addr_o = 1'b1;
|
||||
ls_fsm_ns = WAIT_RVALID;
|
||||
end
|
||||
end //~ WAIT_GNT
|
||||
|
||||
WAIT_RVALID: begin
|
||||
data_req_o = 1'b0;
|
||||
|
||||
if (data_rvalid_i) begin
|
||||
data_valid_o = 1'b1;
|
||||
ls_fsm_ns = IDLE;
|
||||
end else begin
|
||||
ls_fsm_ns = WAIT_RVALID;
|
||||
end
|
||||
end //~ WAIT_RVALID
|
||||
|
||||
default: begin
|
||||
ls_fsm_ns = ls_fsm_e'(1'bX);
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
// check for misaligned accesses that need a second memory access
|
||||
// If one is detected, this is signaled with data_misaligned_o to
|
||||
// the controller which selectively stalls the pipeline
|
||||
always_comb begin
|
||||
data_misaligned = 1'b0;
|
||||
|
||||
if (data_req_ex_i && !data_misaligned_q) begin
|
||||
unique case (data_type_ex_i)
|
||||
2'b00: begin // word
|
||||
if (data_addr[1:0] != 2'b00) begin
|
||||
data_misaligned = 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
2'b01: begin // half word
|
||||
if (data_addr[1:0] == 2'b11) begin
|
||||
data_misaligned = 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
2'b10,
|
||||
2'b11:;
|
||||
|
||||
default: data_misaligned = 1'bX;
|
||||
endcase // case (data_type_ex_i)
|
||||
end
|
||||
end
|
||||
|
||||
assign data_addr = adder_result_ex_i;
|
||||
|
||||
assign busy_o = (ls_fsm_cs == WAIT_RVALID) | (data_req_o == 1'b1);
|
||||
|
||||
////////////////
|
||||
// Assertions //
|
||||
////////////////
|
||||
|
||||
`ifndef VERILATOR
|
||||
// make sure there is no new request when the old one is not yet completely done
|
||||
// i.e. it should not be possible to get a grant without an rvalid for the
|
||||
|
|
|
@ -62,7 +62,7 @@ module ibex_tracer #(
|
|||
input logic [(RegAddrWidth-1):0] ex_reg_addr_i,
|
||||
input logic ex_reg_we_i,
|
||||
input logic [31:0] ex_reg_wdata_i,
|
||||
input logic data_valid_lsu_i,
|
||||
input logic lsu_data_valid_i,
|
||||
input logic ex_data_req_i,
|
||||
input logic ex_data_gnt_i,
|
||||
input logic ex_data_we_i,
|
||||
|
@ -433,7 +433,7 @@ module ibex_tracer #(
|
|||
end
|
||||
//we wait until the the data instruction ends
|
||||
do @(negedge clk_i);
|
||||
while (!data_valid_lsu_i);
|
||||
while (!lsu_data_valid_i);
|
||||
|
||||
if (!mem_acc.we) begin
|
||||
//load operations
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue