../src/lowrisc_prim_all_0.1/rtl/prim_fifo_sync.sv Cov: 97.8%

   1: // Copyright lowRISC contributors.
   2: // Licensed under the Apache License, Version 2.0, see LICENSE for details.
   3: // SPDX-License-Identifier: Apache-2.0
   4: //
   5: // Generic synchronous fifo for use in a variety of devices.
   6: 
   7: `include "prim_assert.sv"
   8: 
   9: module prim_fifo_sync #(
  10:   parameter int unsigned Width       = 16,
  11:   parameter bit Pass                 = 1'b1, // if == 1 allow requests to pass through empty FIFO
  12:   parameter int unsigned Depth       = 4,
  13:   parameter bit OutputZeroIfEmpty    = 1'b1, // if == 1 always output 0 when FIFO is empty
  14:   // derived parameter
  15:   localparam int unsigned DepthWNorm = $clog2(Depth+1),
  16:   localparam int unsigned DepthW     = (DepthWNorm == 0) ? 1 : DepthWNorm
  17: ) (
  18:   input                   clk_i,
  19:   input                   rst_ni,
  20:   // synchronous clear / flush port
  21:   input                   clr_i,
  22:   // write port
  23:   input                   wvalid,
  24:   output                  wready,
  25:   input   [Width-1:0]     wdata,
  26:   // read port
  27:   output                  rvalid,
  28:   input                   rready,
  29:   output  [Width-1:0]     rdata,
  30:   // occupancy
  31:   output  [DepthW-1:0]    depth
  32: );
  33: 
  34:   // FIFO is in complete passthrough mode
  35:   if (Depth == 0) begin : gen_passthru_fifo
  36:     `ASSERT_INIT(paramCheckPass, Pass == 1)
  37: 
  38:     assign depth = 1'b0; //output is meaningless
  39: 
  40:     // devie facing
  41:     assign rvalid = wvalid;
  42:     assign rdata = wdata;
  43: 
  44:     // host facing
  45:     assign wready = rready;
  46: 
  47:     // this avoids lint warnings
  48:     logic unused_clr;
  49:     assign unused_clr = clr_i;
  50: 
  51:   // Normal FIFO construction
  52:   end else begin : gen_normal_fifo
  53: 
  54:     // consider Depth == 1 case when $clog2(1) == 0
  55:     localparam int unsigned PTRV_W    = $clog2(Depth) + ~|$clog2(Depth);
  56:     localparam int unsigned PTR_WIDTH = PTRV_W+1;
  57: 
  58:     logic [PTR_WIDTH-1:0] fifo_wptr, fifo_rptr;
  59:     logic                 fifo_incr_wptr, fifo_incr_rptr, fifo_empty;
  60: 
  61:     // create the write and read pointers
  62:     logic  full, empty;
  63:     logic  wptr_msb;
  64:     logic  rptr_msb;
  65:     logic  [PTRV_W-1:0] wptr_value;
  66:     logic  [PTRV_W-1:0] rptr_value;
  67: 
  68:     assign wptr_msb = fifo_wptr[PTR_WIDTH-1];
  69:     assign rptr_msb = fifo_rptr[PTR_WIDTH-1];
  70:     assign wptr_value = fifo_wptr[0+:PTRV_W];
  71:     assign rptr_value = fifo_rptr[0+:PTRV_W];
  72:     assign depth = (full)                 ? DepthW'(Depth) :
  73:                    (wptr_msb == rptr_msb) ? DepthW'(wptr_value) - DepthW'(rptr_value) :
  74:                    (DepthW'(Depth) - DepthW'(rptr_value) + DepthW'(wptr_value)) ;
  75: 
  76:     assign fifo_incr_wptr = wvalid & wready;
  77:     assign fifo_incr_rptr = rvalid & rready;
  78: 
  79:     assign wready = ~full;
  80:     assign rvalid = ~empty;
  81: 
  82:     always_ff @(posedge clk_i or negedge rst_ni) begin
  83:       if (!rst_ni) begin
  84:         fifo_wptr <= {(PTR_WIDTH){1'b0}};
  85:       end else if (clr_i) begin
  86:         fifo_wptr <= {(PTR_WIDTH){1'b0}};
  87:       end else if (fifo_incr_wptr) begin
  88:         if (fifo_wptr[PTR_WIDTH-2:0] == (Depth-1)) begin
  89:           fifo_wptr <= {~fifo_wptr[PTR_WIDTH-1],{(PTR_WIDTH-1){1'b0}}};
  90:         end else begin
  91:           fifo_wptr <= fifo_wptr + {{(PTR_WIDTH-1){1'b0}},1'b1};
  92:         end
  93:       end
  94:     end
  95: 
  96:     always_ff @(posedge clk_i or negedge rst_ni) begin
  97:       if (!rst_ni) begin
  98:         fifo_rptr <= {(PTR_WIDTH){1'b0}};
  99:       end else if (clr_i) begin
 100:         fifo_rptr <= {(PTR_WIDTH){1'b0}};
 101:       end else if (fifo_incr_rptr) begin
 102:         if (fifo_rptr[PTR_WIDTH-2:0] == (Depth-1)) begin
 103:           fifo_rptr <= {~fifo_rptr[PTR_WIDTH-1],{(PTR_WIDTH-1){1'b0}}};
 104:         end else begin
 105:           fifo_rptr <= fifo_rptr + {{(PTR_WIDTH-1){1'b0}},1'b1};
 106:         end
 107:       end
 108:     end
 109: 
 110:     assign  full       = (fifo_wptr == (fifo_rptr ^ {1'b1,{(PTR_WIDTH-1){1'b0}}}));
 111:     assign  fifo_empty = (fifo_wptr ==  fifo_rptr);
 112: 
 113: 
 114:     // the generate blocks below are needed to avoid lint errors due to array indexing
 115:     // in the where the fifo only has one storage element
 116:     logic [Depth-1:0][Width-1:0] storage;
 117:     logic [Width-1:0] storage_rdata;
 118:     if (Depth == 1) begin : gen_depth_eq1
 119:       assign storage_rdata = storage[0];
 120: 
 121:       always_ff @(posedge clk_i)
 122:         if (fifo_incr_wptr) begin
 123:           storage[0] <= wdata;
 124:         end
 125:     // fifo with more than one storage element
 126:     end else begin : gen_depth_gt1
 127:       assign storage_rdata = storage[fifo_rptr[PTR_WIDTH-2:0]];
 128: 
 129:       always_ff @(posedge clk_i)
 130:         if (fifo_incr_wptr) begin
 131:           storage[fifo_wptr[PTR_WIDTH-2:0]] <= wdata;
 132:         end
 133:     end
 134: 
 135:     logic [Width-1:0] rdata_int;
 136:     if (Pass == 1'b1) begin : gen_pass
 137:       assign rdata_int = (fifo_empty && wvalid) ? wdata : storage_rdata;
 138:       assign empty = fifo_empty & ~wvalid;
 139:     end else begin : gen_nopass
 140:       assign rdata_int = storage_rdata;
 141:       assign empty = fifo_empty;
 142:     end
 143: 
 144:     if (OutputZeroIfEmpty == 1'b1) begin : gen_output_zero
 145:       assign rdata = empty ? 'b0 : rdata_int;
 146:     end else begin : gen_no_output_zero
 147:       assign rdata = rdata_int;
 148:     end
 149: 
 150:     `ASSERT(depthShallNotExceedParamDepth, !empty |-> depth <= DepthW'(Depth))
 151:   end // block: gen_normal_fifo
 152: 
 153: 
 154:   //////////////////////
 155:   // Known Assertions //
 156:   //////////////////////
 157: 
 158:   `ASSERT(DataKnown_A, rvalid |-> !$isunknown(rdata))
 159:   `ASSERT_KNOWN(DepthKnown_A, depth)
 160:   `ASSERT_KNOWN(RvalidKnown_A, rvalid)
 161:   `ASSERT_KNOWN(WreadyKnown_A, wready)
 162: 
 163: endmodule
 164: