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