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