../src/lowrisc_prim_all_0.1/rtl/prim_fifo_async.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 asynchronous fifo for use in a variety of devices.
   6: 
   7: `include "prim_assert.sv"
   8: 
   9: module prim_fifo_async #(
  10:   parameter  int unsigned Width  = 16,
  11:   parameter  int unsigned Depth  = 3,
  12:   localparam int unsigned DepthW = $clog2(Depth+1) // derived parameter representing [0..Depth]
  13: ) (
  14:   // write port
  15:   input                  clk_wr_i,
  16:   input                  rst_wr_ni,
  17:   input                  wvalid,
  18:   output                 wready,
  19:   input [Width-1:0]      wdata,
  20:   output [DepthW-1:0]    wdepth,
  21: 
  22:   // read port
  23:   input                  clk_rd_i,
  24:   input                  rst_rd_ni,
  25:   output                 rvalid,
  26:   input                  rready,
  27:   output [Width-1:0]     rdata,
  28:   output [DepthW-1:0]    rdepth
  29: );
  30: 
  31:   `ASSERT_INIT(paramCheckDepth,  Depth >= 3)
  32: 
  33:   localparam int unsigned PTRV_W = $clog2(Depth);
  34:   localparam logic [PTRV_W-1:0] DepthMinus1 = PTRV_W'(Depth - 1);
  35:   localparam int unsigned PTR_WIDTH = PTRV_W+1;
  36: 
  37:   logic [PTR_WIDTH-1:0]    fifo_wptr, fifo_rptr;
  38:   logic [PTR_WIDTH-1:0]    fifo_wptr_sync_combi,   fifo_rptr_sync;
  39:   logic [PTR_WIDTH-1:0]    fifo_wptr_gray_sync,    fifo_rptr_gray_sync;
  40:   logic [PTR_WIDTH-1:0]    fifo_wptr_gray,         fifo_rptr_gray;
  41:   logic                    fifo_incr_wptr, fifo_incr_rptr, empty;
  42: 
  43:   logic full_wclk, full_rclk;
  44: 
  45:   assign wready = !full_wclk;
  46:   assign rvalid = !empty;
  47: 
  48:   // create the write and read pointers
  49: 
  50:   assign fifo_incr_wptr = wvalid & wready;
  51:   assign fifo_incr_rptr = rvalid & rready;
  52: 
  53:   ///////////////////
  54:   // write pointer //
  55:   ///////////////////
  56: 
  57:   always_ff @(posedge clk_wr_i or negedge rst_wr_ni)
  58:     if (!rst_wr_ni) begin
  59:       fifo_wptr <= {(PTR_WIDTH){1'b0}};
  60:     end else if (fifo_incr_wptr) begin
  61:       if (fifo_wptr[PTR_WIDTH-2:0] == DepthMinus1) begin
  62:         fifo_wptr <= {~fifo_wptr[PTR_WIDTH-1],{(PTR_WIDTH-1){1'b0}}};
  63:       end else begin
  64:         fifo_wptr <= fifo_wptr + {{(PTR_WIDTH-1){1'b0}},1'b1};
  65:     end
  66:   end
  67: 
  68:   // gray-coded version
  69:   always_ff @(posedge clk_wr_i or negedge rst_wr_ni)
  70:     if (!rst_wr_ni) begin
  71:       fifo_wptr_gray <= {(PTR_WIDTH){1'b0}};
  72:     end else if (fifo_incr_wptr) begin
  73:       if (fifo_wptr[PTR_WIDTH-2:0] == DepthMinus1) begin
  74:         fifo_wptr_gray <= dec2gray({~fifo_wptr[PTR_WIDTH-1],{(PTR_WIDTH-1){1'b0}}});
  75:       end else begin
  76:         fifo_wptr_gray <= dec2gray(fifo_wptr + {{(PTR_WIDTH-1){1'b0}},1'b1});
  77:       end
  78:     end
  79: 
  80:   prim_flop_2sync #(.Width(PTR_WIDTH)) sync_wptr (
  81:     .clk_i    (clk_rd_i),
  82:     .rst_ni   (rst_rd_ni),
  83:     .d        (fifo_wptr_gray),
  84:     .q        (fifo_wptr_gray_sync));
  85: 
  86:   assign fifo_wptr_sync_combi = gray2dec(fifo_wptr_gray_sync);
  87: 
  88:   //////////////////
  89:   // read pointer //
  90:   //////////////////
  91: 
  92:   always_ff @(posedge clk_rd_i or negedge rst_rd_ni)
  93:     if (!rst_rd_ni) begin
  94:       fifo_rptr <= {(PTR_WIDTH){1'b0}};
  95:     end else if (fifo_incr_rptr) begin
  96:       if (fifo_rptr[PTR_WIDTH-2:0] == DepthMinus1) begin
  97:         fifo_rptr <= {~fifo_rptr[PTR_WIDTH-1],{(PTR_WIDTH-1){1'b0}}};
  98:       end else begin
  99:         fifo_rptr <= fifo_rptr + {{(PTR_WIDTH-1){1'b0}},1'b1};
 100:     end
 101:   end
 102: 
 103:   // gray-coded version
 104:   always_ff @(posedge clk_rd_i or negedge rst_rd_ni)
 105:     if (!rst_rd_ni) begin
 106:       fifo_rptr_gray <= {(PTR_WIDTH){1'b0}};
 107:     end else if (fifo_incr_rptr) begin
 108:       if (fifo_rptr[PTR_WIDTH-2:0] == DepthMinus1) begin
 109:         fifo_rptr_gray <= dec2gray({~fifo_rptr[PTR_WIDTH-1],{(PTR_WIDTH-1){1'b0}}});
 110:       end else begin
 111:         fifo_rptr_gray <= dec2gray(fifo_rptr + {{(PTR_WIDTH-1){1'b0}},1'b1});
 112:       end
 113:     end
 114: 
 115:   prim_flop_2sync #(.Width(PTR_WIDTH)) sync_rptr (
 116:     .clk_i    (clk_wr_i),
 117:     .rst_ni   (rst_wr_ni),
 118:     .d        (fifo_rptr_gray),
 119:     .q        (fifo_rptr_gray_sync));
 120: 
 121:   always_ff @(posedge clk_wr_i or negedge rst_wr_ni)
 122:     if (!rst_wr_ni) begin
 123:       fifo_rptr_sync <= {PTR_WIDTH{1'b0}};
 124:     end else begin
 125:       fifo_rptr_sync <= gray2dec(fifo_rptr_gray_sync);
 126:     end
 127: 
 128:   //////////////////
 129:   // empty / full //
 130:   //////////////////
 131: 
 132:   assign  full_wclk = (fifo_wptr == (fifo_rptr_sync ^ {1'b1,{(PTR_WIDTH-1){1'b0}}}));
 133:   assign  full_rclk = (fifo_wptr_sync_combi == (fifo_rptr ^ {1'b1,{(PTR_WIDTH-1){1'b0}}}));
 134: 
 135:   // Current depth in the write clock side
 136:   logic  wptr_msb;
 137:   logic  rptr_sync_msb;
 138:   logic  [PTRV_W-1:0] wptr_value;
 139:   logic  [PTRV_W-1:0] rptr_sync_value;
 140:   assign wptr_msb = fifo_wptr[PTR_WIDTH-1];
 141:   assign rptr_sync_msb = fifo_rptr_sync[PTR_WIDTH-1];
 142:   assign wptr_value = fifo_wptr[0+:PTRV_W];
 143:   assign rptr_sync_value = fifo_rptr_sync[0+:PTRV_W];
 144:   assign wdepth = (full_wclk) ? DepthW'(Depth) :
 145:                   (wptr_msb == rptr_sync_msb) ? DepthW'(wptr_value) - DepthW'(rptr_sync_value) :
 146:                   (DepthW'(Depth) - DepthW'(rptr_sync_value) + DepthW'(wptr_value)) ;
 147: 
 148:   // Same again in the read clock side
 149:   assign empty = (fifo_wptr_sync_combi ==  fifo_rptr);
 150:   logic  rptr_msb;
 151:   logic  wptr_sync_msb;
 152:   logic  [PTRV_W-1:0] rptr_value;
 153:   logic  [PTRV_W-1:0] wptr_sync_value;
 154:   assign wptr_sync_msb = fifo_wptr_sync_combi[PTR_WIDTH-1];
 155:   assign rptr_msb = fifo_rptr[PTR_WIDTH-1];
 156:   assign wptr_sync_value = fifo_wptr_sync_combi[0+:PTRV_W];
 157:   assign rptr_value = fifo_rptr[0+:PTRV_W];
 158:   assign rdepth = (full_rclk) ? DepthW'(Depth) :
 159:                   (wptr_sync_msb == rptr_msb) ? DepthW'(wptr_sync_value) - DepthW'(rptr_value) :
 160:                   (DepthW'(Depth) - DepthW'(rptr_value) + DepthW'(wptr_sync_value)) ;
 161: 
 162:   /////////////
 163:   // storage //
 164:   /////////////
 165: 
 166:   logic [Width-1:0] storage [Depth];
 167: 
 168:   always_ff @(posedge clk_wr_i)
 169:     if (fifo_incr_wptr) begin
 170:       storage[fifo_wptr[PTR_WIDTH-2:0]] <= wdata;
 171:     end
 172: 
 173:   assign rdata = storage[fifo_rptr[PTR_WIDTH-2:0]];
 174: 
 175:   // gray code conversion functions.  algorithm walks up from 0..N-1
 176:   // then flips the upper bit and walks down from N-1 to 0.
 177: 
 178:   function automatic [PTR_WIDTH-1:0] dec2gray(input logic [PTR_WIDTH-1:0] decval);
 179:     logic [PTR_WIDTH-1:0] decval_sub;
 180:     logic [PTR_WIDTH-2:0] decval_in;
 181:     logic                 unused_decval_msb;
 182: 
 183:     decval_sub = Depth - {1'b0,decval[PTR_WIDTH-2:0]} - 1'b1;
 184: 
 185:     {unused_decval_msb, decval_in} = decval[PTR_WIDTH-1] ? decval_sub : decval;
 186:     // Was done in two assigns for low bits and top bit
 187:     // but that generates a (bogus) verilator warning, so do in one assign
 188:     dec2gray = {decval[PTR_WIDTH-1],
 189:                 {1'b0,decval_in[PTR_WIDTH-2:1]} ^ decval_in[PTR_WIDTH-2:0]};
 190:   endfunction
 191: 
 192:   function automatic [PTR_WIDTH-1:0] gray2dec(input logic [PTR_WIDTH-1:0] grayval);
 193:     logic [PTR_WIDTH-2:0] dec_tmp, dec_tmp_sub;
 194:     logic                 unused_decsub_msb;
 195: 
 196:     dec_tmp[PTR_WIDTH-2] = grayval[PTR_WIDTH-2];
 197:     for (int i = PTR_WIDTH-3; i >= 0; i--)
 198:       dec_tmp[i] = dec_tmp[i+1]^grayval[i];
 199:     {unused_decsub_msb, dec_tmp_sub} = Depth - {1'b0,dec_tmp} - 1'b1;
 200:     if (grayval[PTR_WIDTH-1])
 201:       gray2dec = {1'b1,dec_tmp_sub};
 202:     else
 203:       gray2dec = {1'b0,dec_tmp};
 204:   endfunction
 205: 
 206:   // TODO: assertions on full, empty, gray transitions
 207: 
 208: endmodule
 209: