hw/ip/prim/rtl/prim_fifo_sync.sv Cov: 100%

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