blob: bfab455c1ce968edd56a2b647613f6bb8d542bac [file] [log] [blame]
module ibex_fetch_fifo (
clk_i,
rst_ni,
clear_i,
busy_o,
in_valid_i,
in_addr_i,
in_rdata_i,
in_err_i,
out_valid_o,
out_ready_i,
out_addr_o,
out_addr_next_o,
out_rdata_o,
out_err_o,
out_err_plus2_o
);
parameter [31:0] NUM_REQS = 2;
input wire clk_i;
input wire rst_ni;
input wire clear_i;
output wire [NUM_REQS - 1:0] busy_o;
input wire in_valid_i;
input wire [31:0] in_addr_i;
input wire [31:0] in_rdata_i;
input wire in_err_i;
output reg out_valid_o;
input wire out_ready_i;
output wire [31:0] out_addr_o;
output wire [31:0] out_addr_next_o;
output reg [31:0] out_rdata_o;
output reg out_err_o;
output reg out_err_plus2_o;
localparam [31:0] DEPTH = NUM_REQS + 1;
wire [(DEPTH * 32) - 1:0] rdata_d;
reg [(DEPTH * 32) - 1:0] rdata_q;
wire [DEPTH - 1:0] err_d;
reg [DEPTH - 1:0] err_q;
wire [DEPTH - 1:0] valid_d;
reg [DEPTH - 1:0] valid_q;
wire [DEPTH - 1:0] lowest_free_entry;
wire [DEPTH - 1:0] valid_pushed;
wire [DEPTH - 1:0] valid_popped;
wire [DEPTH - 1:0] entry_en;
wire pop_fifo;
wire [31:0] rdata;
wire [31:0] rdata_unaligned;
wire err;
wire err_unaligned;
wire err_plus2;
wire valid;
wire valid_unaligned;
wire aligned_is_compressed;
wire unaligned_is_compressed;
wire addr_incr_two;
wire [31:1] instr_addr_next;
wire [31:1] instr_addr_d;
reg [31:1] instr_addr_q;
wire instr_addr_en;
wire unused_addr_in;
assign rdata = (valid_q[0] ? rdata_q[0+:32] : in_rdata_i);
assign err = (valid_q[0] ? err_q[0] : in_err_i);
assign valid = valid_q[0] | in_valid_i;
assign rdata_unaligned = (valid_q[1] ? {rdata_q[47-:16], rdata[31:16]} : {in_rdata_i[15:0], rdata[31:16]});
assign err_unaligned = (valid_q[1] ? (err_q[1] & ~unaligned_is_compressed) | err_q[0] : (valid_q[0] & err_q[0]) | (in_err_i & (~valid_q[0] | ~unaligned_is_compressed)));
assign err_plus2 = (valid_q[1] ? err_q[1] & ~err_q[0] : (in_err_i & valid_q[0]) & ~err_q[0]);
assign valid_unaligned = (valid_q[1] ? 1'b1 : valid_q[0] & in_valid_i);
assign unaligned_is_compressed = (rdata[17:16] != 2'b11) & ~err;
assign aligned_is_compressed = (rdata[1:0] != 2'b11) & ~err;
always @(*)
if (out_addr_o[1]) begin
out_rdata_o = rdata_unaligned;
out_err_o = err_unaligned;
out_err_plus2_o = err_plus2;
if (unaligned_is_compressed)
out_valid_o = valid;
else
out_valid_o = valid_unaligned;
end
else begin
out_rdata_o = rdata;
out_err_o = err;
out_err_plus2_o = 1'b0;
out_valid_o = valid;
end
assign instr_addr_en = clear_i | (out_ready_i & out_valid_o);
assign addr_incr_two = (instr_addr_q[1] ? unaligned_is_compressed : aligned_is_compressed);
assign instr_addr_next = instr_addr_q[31:1] + {29'd0, ~addr_incr_two, addr_incr_two};
assign instr_addr_d = (clear_i ? in_addr_i[31:1] : instr_addr_next);
always @(posedge clk_i)
if (instr_addr_en)
instr_addr_q <= instr_addr_d;
else
instr_addr_q <= instr_addr_q;
assign out_addr_next_o = {instr_addr_next, 1'b0};
assign out_addr_o = {instr_addr_q, 1'b0};
assign unused_addr_in = in_addr_i[0];
assign busy_o = valid_q[DEPTH - 1:DEPTH - NUM_REQS];
assign pop_fifo = (out_ready_i & out_valid_o) & (~aligned_is_compressed | out_addr_o[1]);
generate
genvar i;
for (i = 0; i < (DEPTH - 1); i = i + 1) begin : g_fifo_next
if (i == 0) begin : g_ent0
assign lowest_free_entry[i] = ~valid_q[i];
end
else begin : g_ent_others
assign lowest_free_entry[i] = ~valid_q[i] & valid_q[i - 1];
end
assign valid_pushed[i] = (in_valid_i & lowest_free_entry[i]) | valid_q[i];
assign valid_popped[i] = (pop_fifo ? valid_pushed[i + 1] : valid_pushed[i]);
assign valid_d[i] = valid_popped[i] & ~clear_i;
assign entry_en[i] = (valid_pushed[i + 1] & pop_fifo) | ((in_valid_i & lowest_free_entry[i]) & ~pop_fifo);
assign rdata_d[i * 32+:32] = (valid_q[i + 1] ? rdata_q[(i + 1) * 32+:32] : in_rdata_i);
assign err_d[i] = (valid_q[i + 1] ? err_q[i + 1] : in_err_i);
end
endgenerate
assign lowest_free_entry[DEPTH - 1] = ~valid_q[DEPTH - 1] & valid_q[DEPTH - 2];
assign valid_pushed[DEPTH - 1] = valid_q[DEPTH - 1] | (in_valid_i & lowest_free_entry[DEPTH - 1]);
assign valid_popped[DEPTH - 1] = (pop_fifo ? 1'b0 : valid_pushed[DEPTH - 1]);
assign valid_d[DEPTH - 1] = valid_popped[DEPTH - 1] & ~clear_i;
assign entry_en[DEPTH - 1] = in_valid_i & lowest_free_entry[DEPTH - 1];
assign rdata_d[(DEPTH - 1) * 32+:32] = in_rdata_i;
assign err_d[DEPTH - 1] = in_err_i;
always @(posedge clk_i or negedge rst_ni)
if (!rst_ni)
valid_q <= {DEPTH {1'sb0}};
else
valid_q <= valid_d;
generate
for (i = 0; i < DEPTH; i = i + 1) begin : g_fifo_regs
always @(posedge clk_i)
if (!rst_ni) begin
rdata_q[i * 32+:32] <=0;
err_q[i] <= 0;
end else begin
if (entry_en[i]) begin
rdata_q[i * 32+:32] <= rdata_d[i * 32+:32];
err_q[i] <= err_d[i];
end
else begin
rdata_q[i * 32+:32] <= rdata_q[i * 32+:32];
err_q[i] <= err_q[i];
end
end
end
endgenerate
endmodule