../src/lowrisc_ibex_ibex_core_0.1/rtl/ibex_fetch_fifo.sv Cov: 100%

   1: // Copyright lowRISC contributors.
   2: // Copyright 2018 ETH Zurich and University of Bologna, see also CREDITS.md.
   3: // Licensed under the Apache License, Version 2.0, see LICENSE for details.
   4: // SPDX-License-Identifier: Apache-2.0
   5: 
   6: /**
   7:  * Fetch Fifo for 32 bit memory interface
   8:  *
   9:  * input port: send address and data to the FIFO
  10:  * clear_i clears the FIFO for the following cycle, including any new request
  11:  */
  12: 
  13: `include "prim_assert.sv"
  14: 
  15: module ibex_fetch_fifo #(
  16:   parameter int unsigned NUM_REQS = 2
  17: ) (
  18:     input  logic                clk_i,
  19:     input  logic                rst_ni,
  20: 
  21:     // control signals
  22:     input  logic                clear_i,   // clears the contents of the FIFO
  23:     output logic [NUM_REQS-1:0] busy_o,
  24: 
  25:     // input port
  26:     input  logic                in_valid_i,
  27:     input  logic [31:0]         in_addr_i,
  28:     input  logic [31:0]         in_rdata_i,
  29:     input  logic                in_err_i,
  30: 
  31:     // output port
  32:     output logic                out_valid_o,
  33:     input  logic                out_ready_i,
  34:     output logic [31:0]         out_addr_o,
  35:     output logic [31:0]         out_rdata_o,
  36:     output logic                out_err_o,
  37:     output logic                out_err_plus2_o
  38: );
  39: 
  40:   localparam int unsigned DEPTH = NUM_REQS+1;
  41: 
  42:   // index 0 is used for output
  43:   logic [DEPTH-1:0] [31:0]  rdata_d,   rdata_q;
  44:   logic [DEPTH-1:0]         err_d,     err_q;
  45:   logic [DEPTH-1:0]         valid_d,   valid_q;
  46:   logic [DEPTH-1:0]         lowest_free_entry;
  47:   logic [DEPTH-1:0]         valid_pushed, valid_popped;
  48:   logic [DEPTH-1:0]         entry_en;
  49: 
  50:   logic                     pop_fifo;
  51:   logic             [31:0]  rdata, rdata_unaligned;
  52:   logic                     err,   err_unaligned, err_plus2;
  53:   logic                     valid, valid_unaligned;
  54: 
  55:   logic                     aligned_is_compressed, unaligned_is_compressed;
  56: 
  57:   logic                     addr_incr_two;
  58:   logic [31:1]              instr_addr_d, instr_addr_q;
  59:   logic                     instr_addr_en;
  60:   logic                     unused_addr_in;
  61: 
  62:   /////////////////
  63:   // Output port //
  64:   /////////////////
  65: 
  66:   assign rdata = valid_q[0] ? rdata_q[0] : in_rdata_i;
  67:   assign err   = valid_q[0] ? err_q[0]   : in_err_i;
  68:   assign valid = valid_q[0] | in_valid_i;
  69: 
  70:   // The FIFO contains word aligned memory fetches, but the instructions contained in each entry
  71:   // might be half-word aligned (due to compressed instructions)
  72:   // e.g.
  73:   //              | 31               16 | 15               0 |
  74:   // FIFO entry 0 | Instr 1 [15:0]      | Instr 0 [15:0]     |
  75:   // FIFO entry 1 | Instr 2 [15:0]      | Instr 1 [31:16]    |
  76:   //
  77:   // The FIFO also has a direct bypass path, so a complete instruction might be made up of data
  78:   // from the FIFO and new incoming data.
  79:   //
  80: 
  81:   // Construct the output data for an unaligned instruction
  82:   assign rdata_unaligned = valid_q[1] ? {rdata_q[1][15:0], rdata[31:16]} :
  83:                                         {in_rdata_i[15:0], rdata[31:16]};
  84: 
  85:   // If entry[1] is valid, an error can come from entry[0] or entry[1], unless the
  86:   // instruction in entry[0] is compressed (entry[1] is a new instruction)
  87:   // If entry[1] is not valid, and entry[0] is, an error can come from entry[0] or the incoming
  88:   // data, unless the instruction in entry[0] is compressed
  89:   // If entry[0] is not valid, the error must come from the incoming data
  90:   assign err_unaligned   = valid_q[1] ? ((err_q[1] & ~unaligned_is_compressed) | err_q[0]) :
  91:                                         ((valid_q[0] & err_q[0]) |
  92:                                          (in_err_i & (~valid_q[0] | ~unaligned_is_compressed)));
  93: 
  94:   // Record when an error is caused by the second half of an unaligned 32bit instruction.
  95:   // Only needs to be correct when unaligned and if err_unaligned is set
  96:   assign err_plus2       = valid_q[1] ? (err_q[1] & ~err_q[0]) :
  97:                                         (in_err_i & valid_q[0] & ~err_q[0]);
  98: 
  99:   // An uncompressed unaligned instruction is only valid if both parts are available
 100:   assign valid_unaligned = valid_q[1] ? 1'b1 :
 101:                                         (valid_q[0] & in_valid_i);
 102: 
 103:   // If there is an error, rdata is unknown
 104:   assign unaligned_is_compressed = (rdata[17:16] != 2'b11) | err;
 105:   assign aligned_is_compressed   = (rdata[ 1: 0] != 2'b11) & ~err;
 106: 
 107:   ////////////////////////////////////////
 108:   // Instruction aligner (if unaligned) //
 109:   ////////////////////////////////////////
 110: 
 111:   always_comb begin
 112:     if (out_addr_o[1]) begin
 113:       // unaligned case
 114:       out_rdata_o     = rdata_unaligned;
 115:       out_err_o       = err_unaligned;
 116:       out_err_plus2_o = err_plus2;
 117: 
 118:       if (unaligned_is_compressed) begin
 119:         out_valid_o = valid;
 120:       end else begin
 121:         out_valid_o = valid_unaligned;
 122:       end
 123:     end else begin
 124:       // aligned case
 125:       out_rdata_o     = rdata;
 126:       out_err_o       = err;
 127:       out_err_plus2_o = 1'b0;
 128:       out_valid_o     = valid;
 129:     end
 130:   end
 131: 
 132:   /////////////////////////
 133:   // Instruction address //
 134:   /////////////////////////
 135: 
 136:   // Update the address on branches and every time an instruction is driven
 137:   assign instr_addr_en = clear_i | (out_ready_i & out_valid_o);
 138: 
 139:   // Increment the address by two every time a compressed instruction is popped
 140:   assign addr_incr_two = instr_addr_q[1] ? unaligned_is_compressed :
 141:                                            aligned_is_compressed;
 142: 
 143:   assign instr_addr_d = clear_i ? in_addr_i[31:1] :
 144:                                   (instr_addr_q[31:1] +
 145:                                    // Increment address by 4 or 2
 146:                                    {29'd0,~addr_incr_two,addr_incr_two});
 147: 
 148:   always_ff @(posedge clk_i) begin
 149:     if (instr_addr_en) begin
 150:       instr_addr_q <= instr_addr_d;
 151:     end
 152:   end
 153: 
 154:   assign out_addr_o[31:1] = instr_addr_q[31:1];
 155:   assign out_addr_o[0]    = 1'b0;
 156: 
 157:   // The LSB of the address is unused, since all addresses are halfword aligned
 158:   assign unused_addr_in = in_addr_i[0];
 159: 
 160:   /////////////////
 161:   // FIFO status //
 162:   /////////////////
 163: 
 164:   // Indicate the fill level of fifo-entries. This is used to determine when a new request can be
 165:   // made on the bus. The prefetch buffer only needs to know about the upper entries which overlap
 166:   // with NUM_REQS.
 167:   assign busy_o = valid_q[DEPTH-1:DEPTH-NUM_REQS];
 168: 
 169:   /////////////////////
 170:   // FIFO management //
 171:   /////////////////////
 172: 
 173:   // Since an entry can contain unaligned instructions, popping an entry can leave the entry valid
 174:   assign pop_fifo = out_ready_i & out_valid_o & (~aligned_is_compressed | out_addr_o[1]);
 175: 
 176:   for (genvar i = 0; i < (DEPTH - 1); i++) begin : g_fifo_next
 177:     // Calculate lowest free entry (write pointer)
 178:     if (i == 0) begin : g_ent0
 179:       assign lowest_free_entry[i] = ~valid_q[i];
 180:     end else begin : g_ent_others
 181:       assign lowest_free_entry[i] = ~valid_q[i] & valid_q[i-1];
 182:     end
 183: 
 184:     // An entry is set when an incoming request chooses the lowest available entry
 185:     assign valid_pushed[i] = (in_valid_i & lowest_free_entry[i]) |
 186:                              valid_q[i];
 187:     // Popping the FIFO shifts all entries down
 188:     assign valid_popped[i] = pop_fifo ? valid_pushed[i+1] : valid_pushed[i];
 189:     // All entries are wiped out on a clear
 190:     assign valid_d[i] = valid_popped[i] & ~clear_i;
 191: 
 192:     // data flops are enabled if there is new data to shift into it, or
 193:     assign entry_en[i] = (valid_pushed[i+1] & pop_fifo) |
 194:                          // a new request is incoming and this is the lowest free entry
 195:                          (in_valid_i & lowest_free_entry[i] & ~pop_fifo);
 196: 
 197:     // take the next entry or the incoming data
 198:     assign rdata_d[i]  = valid_q[i+1] ? rdata_q[i+1] : in_rdata_i;
 199:     assign err_d  [i]  = valid_q[i+1] ? err_q  [i+1] : in_err_i;
 200:   end
 201:   // The top entry is similar but with simpler muxing
 202:   assign lowest_free_entry[DEPTH-1] = ~valid_q[DEPTH-1] & valid_q[DEPTH-2];
 203:   assign valid_pushed     [DEPTH-1] = valid_q[DEPTH-1] | (in_valid_i & lowest_free_entry[DEPTH-1]);
 204:   assign valid_popped     [DEPTH-1] = pop_fifo ? 1'b0 : valid_pushed[DEPTH-1];
 205:   assign valid_d [DEPTH-1]          = valid_popped[DEPTH-1] & ~clear_i;
 206:   assign entry_en[DEPTH-1]          = in_valid_i & lowest_free_entry[DEPTH-1];
 207:   assign rdata_d [DEPTH-1]          = in_rdata_i;
 208:   assign err_d   [DEPTH-1]          = in_err_i;
 209: 
 210:   ////////////////////
 211:   // FIFO registers //
 212:   ////////////////////
 213: 
 214:   always_ff @(posedge clk_i or negedge rst_ni) begin
 215:     if (!rst_ni) begin
 216:       valid_q <= '0;
 217:     end else begin
 218:       valid_q <= valid_d;
 219:     end
 220:   end
 221: 
 222:   for (genvar i = 0; i < DEPTH; i++) begin : g_fifo_regs
 223:     always_ff @(posedge clk_i) begin
 224:       if (entry_en[i]) begin
 225:         rdata_q[i]   <= rdata_d[i];
 226:         err_q[i]     <= err_d[i];
 227:       end
 228:     end
 229:   end
 230: 
 231:   ////////////////
 232:   // Assertions //
 233:   ////////////////
 234: 
 235:   // Must not push and pop simultaneously when FIFO full.
 236:   `ASSERT(IbexFetchFifoPushPopFull,
 237:       (in_valid_i && pop_fifo) |-> (!valid_q[DEPTH-1] || clear_i))
 238: 
 239:   // Must not push to FIFO when full.
 240:   `ASSERT(IbexFetchFifoPushFull,
 241:       (in_valid_i) |-> (!valid_q[DEPTH-1] || clear_i))
 242: 
 243: endmodule
 244: