[prim/fifo_async] Add support for Depth <= 2

Move dec2gray and gray2dec functions into a generate context.
Generate simplified versions of pointers and depth output for
Depth <= 2.

Signed-off-by: Tom Roberts <tomroberts@lowrisc.org>
diff --git a/hw/ip/prim/rtl/prim_fifo_async.sv b/hw/ip/prim/rtl/prim_fifo_async.sv
index d69b754..d6ff80c 100644
--- a/hw/ip/prim/rtl/prim_fifo_async.sv
+++ b/hw/ip/prim/rtl/prim_fifo_async.sv
@@ -29,10 +29,10 @@
 );
 
   // Depth must be a power of 2 for the gray code pointers to work
-  `ASSERT_INIT(ParamCheckDepth_A, (Depth > 2) && (Depth == 2**$clog2(Depth)))
+  `ASSERT_INIT(ParamCheckDepth_A, (Depth == 2**$clog2(Depth)))
 
-  localparam int unsigned PTRV_W    = $clog2(Depth);
-  localparam int unsigned PTR_WIDTH = PTRV_W+1;
+  localparam int unsigned PTRV_W    = (Depth == 1) ? 1 : $clog2(Depth);
+  localparam int unsigned PTR_WIDTH = (Depth == 1) ? 1 : PTRV_W+1;
 
   logic [PTR_WIDTH-1:0] fifo_wptr_q, fifo_wptr_d;
   logic [PTR_WIDTH-1:0] fifo_rptr_q, fifo_rptr_d;
@@ -62,8 +62,6 @@
   end
 
   // gray-coded version
-  assign fifo_wptr_gray_d = dec2gray(fifo_wptr_d);
-
   always_ff @(posedge clk_wr_i or negedge rst_wr_ni) begin
     if (!rst_wr_ni) begin
       fifo_wptr_gray_q <= '0;
@@ -79,9 +77,6 @@
     .d_i      (fifo_wptr_gray_q),
     .q_o      (fifo_wptr_gray_sync));
 
-  // decimal version of write pointer in read domain
-  assign fifo_wptr_sync_combi = gray2dec(fifo_wptr_gray_sync);
-
   //////////////////
   // Read Pointer //
   //////////////////
@@ -100,8 +95,6 @@
   end
 
   // gray-coded version
-  assign fifo_rptr_gray_d = dec2gray(fifo_rptr_d);
-
   always_ff @(posedge clk_rd_i or negedge rst_rd_ni) begin
     if (!rst_rd_ni) begin
       fifo_rptr_gray_q <= '0;
@@ -117,9 +110,6 @@
     .d_i      (fifo_rptr_gray_q),
     .q_o      (fifo_rptr_gray_sync));
 
-  // decimal version of read pointer in write domain
-  assign fifo_rptr_sync_combi = gray2dec(fifo_rptr_gray_sync);
-
   // Registered version of synced read pointer
   always_ff @(posedge clk_wr_i or negedge rst_wr_ni) begin
     if (!rst_wr_ni) begin
@@ -137,33 +127,42 @@
   assign full_rclk  = (fifo_wptr_sync_combi == (fifo_rptr_q ^ {1'b1,{(PTR_WIDTH-1){1'b0}}}));
   assign empty_rclk = (fifo_wptr_sync_combi ==  fifo_rptr_q);
 
-  // Current depth in the write clock side
-  logic               wptr_msb;
-  logic               rptr_sync_msb;
-  logic  [PTRV_W-1:0] wptr_value;
-  logic  [PTRV_W-1:0] rptr_sync_value;
+  if (Depth > 1) begin : g_depth_calc
 
-  assign wptr_msb        = fifo_wptr_q[PTR_WIDTH-1];
-  assign rptr_sync_msb   = fifo_rptr_sync_q[PTR_WIDTH-1];
-  assign wptr_value      = fifo_wptr_q[0+:PTRV_W];
-  assign rptr_sync_value = fifo_rptr_sync_q[0+:PTRV_W];
-  assign wdepth_o = (full_wclk) ? DepthW'(Depth) :
-                    (wptr_msb == rptr_sync_msb) ? DepthW'(wptr_value) - DepthW'(rptr_sync_value) :
-                    (DepthW'(Depth) - DepthW'(rptr_sync_value) + DepthW'(wptr_value)) ;
+    // Current depth in the write clock side
+    logic               wptr_msb;
+    logic               rptr_sync_msb;
+    logic  [PTRV_W-1:0] wptr_value;
+    logic  [PTRV_W-1:0] rptr_sync_value;
 
-  // Current depth in the read clock side
-  logic               rptr_msb;
-  logic               wptr_sync_msb;
-  logic  [PTRV_W-1:0] rptr_value;
-  logic  [PTRV_W-1:0] wptr_sync_value;
+    assign wptr_msb        = fifo_wptr_q[PTR_WIDTH-1];
+    assign rptr_sync_msb   = fifo_rptr_sync_q[PTR_WIDTH-1];
+    assign wptr_value      = fifo_wptr_q[0+:PTRV_W];
+    assign rptr_sync_value = fifo_rptr_sync_q[0+:PTRV_W];
+    assign wdepth_o = (full_wclk) ? DepthW'(Depth) :
+                      (wptr_msb == rptr_sync_msb) ? DepthW'(wptr_value) - DepthW'(rptr_sync_value) :
+                      (DepthW'(Depth) - DepthW'(rptr_sync_value) + DepthW'(wptr_value)) ;
 
-  assign wptr_sync_msb   = fifo_wptr_sync_combi[PTR_WIDTH-1];
-  assign rptr_msb        = fifo_rptr_q[PTR_WIDTH-1];
-  assign wptr_sync_value = fifo_wptr_sync_combi[0+:PTRV_W];
-  assign rptr_value      = fifo_rptr_q[0+:PTRV_W];
-  assign rdepth_o = (full_rclk) ? DepthW'(Depth) :
-                    (wptr_sync_msb == rptr_msb) ? DepthW'(wptr_sync_value) - DepthW'(rptr_value) :
-                    (DepthW'(Depth) - DepthW'(rptr_value) + DepthW'(wptr_sync_value)) ;
+    // Current depth in the read clock side
+    logic               rptr_msb;
+    logic               wptr_sync_msb;
+    logic  [PTRV_W-1:0] rptr_value;
+    logic  [PTRV_W-1:0] wptr_sync_value;
+
+    assign wptr_sync_msb   = fifo_wptr_sync_combi[PTR_WIDTH-1];
+    assign rptr_msb        = fifo_rptr_q[PTR_WIDTH-1];
+    assign wptr_sync_value = fifo_wptr_sync_combi[0+:PTRV_W];
+    assign rptr_value      = fifo_rptr_q[0+:PTRV_W];
+    assign rdepth_o = (full_rclk) ? DepthW'(Depth) :
+                      (wptr_sync_msb == rptr_msb) ? DepthW'(wptr_sync_value) - DepthW'(rptr_value) :
+                      (DepthW'(Depth) - DepthW'(rptr_value) + DepthW'(wptr_sync_value)) ;
+
+  end else begin : g_no_depth_calc
+
+    assign rdepth_o = full_rclk;
+    assign wdepth_o = full_wclk;
+
+  end
 
   assign wready_o = !full_wclk;
   assign rvalid_o = !empty_rclk;
@@ -172,48 +171,91 @@
   // Storage //
   /////////////
 
-  always_ff @(posedge clk_wr_i) begin
-    if (fifo_incr_wptr) begin
-      storage[fifo_wptr_q[PTRV_W-1:0]] <= wdata_i;
-    end
-  end
+  if (Depth > 1) begin : g_storage_mux
 
-  assign rdata_o = storage[fifo_rptr_q[PTRV_W-1:0]];
+    always_ff @(posedge clk_wr_i) begin
+      if (fifo_incr_wptr) begin
+        storage[fifo_wptr_q[PTRV_W-1:0]] <= wdata_i;
+      end
+    end
+
+    assign rdata_o = storage[fifo_rptr_q[PTRV_W-1:0]];
+
+  end else begin : g_storage_simple
+
+    always_ff @(posedge clk_wr_i) begin
+      if (fifo_incr_wptr) begin
+        storage[0] <= wdata_i;
+      end
+    end
+
+    assign rdata_o = storage[0];
+
+  end
 
   //////////////////////////////////////
   // Decimal <-> Gray-code Conversion //
   //////////////////////////////////////
 
-  function automatic [PTR_WIDTH-1:0] dec2gray(input logic [PTR_WIDTH-1:0] decval);
-    logic [PTR_WIDTH-1:0] decval_sub;
-    logic [PTR_WIDTH-2:0] decval_in;
-    logic                 unused_decval_msb;
+  // This code is all in a generate context to avoid lint errors when Depth <= 2
+  if (Depth > 2) begin : g_full_gray_conversion
 
-    decval_sub = (PTR_WIDTH)'(Depth) - {1'b0, decval[PTR_WIDTH-2:0]} - 1'b1;
+    function automatic [PTR_WIDTH-1:0] dec2gray(input logic [PTR_WIDTH-1:0] decval);
+      logic [PTR_WIDTH-1:0] decval_sub;
+      logic [PTR_WIDTH-2:0] decval_in;
+      logic                 unused_decval_msb;
 
-    {unused_decval_msb, decval_in} = decval[PTR_WIDTH-1] ? decval_sub : decval;
-    // Was done in two assigns for low bits and top bit
-    // but that generates a (bogus) verilator warning, so do in one assign
-    dec2gray = {decval[PTR_WIDTH-1],
-                {1'b0,decval_in[PTR_WIDTH-2:1]} ^ decval_in[PTR_WIDTH-2:0]};
-  endfunction
+      decval_sub = (PTR_WIDTH)'(Depth) - {1'b0, decval[PTR_WIDTH-2:0]} - 1'b1;
 
-  // Algorithm walks up from 0..N-1 then flips the upper bit and walks down from N-1 to 0.
-  function automatic [PTR_WIDTH-1:0] gray2dec(input logic [PTR_WIDTH-1:0] grayval);
-    logic [PTR_WIDTH-2:0] dec_tmp, dec_tmp_sub;
-    logic                 unused_decsub_msb;
+      {unused_decval_msb, decval_in} = decval[PTR_WIDTH-1] ? decval_sub : decval;
+      // Was done in two assigns for low bits and top bit
+      // but that generates a (bogus) verilator warning, so do in one assign
+      dec2gray = {decval[PTR_WIDTH-1],
+                  {1'b0,decval_in[PTR_WIDTH-2:1]} ^ decval_in[PTR_WIDTH-2:0]};
+    endfunction
 
-    dec_tmp[PTR_WIDTH-2] = grayval[PTR_WIDTH-2];
-    for (int i = PTR_WIDTH-3; i >= 0; i--) begin
-      dec_tmp[i] = dec_tmp[i+1] ^ grayval[i];
-    end
-    {unused_decsub_msb, dec_tmp_sub} = (PTR_WIDTH-1)'(Depth) - {1'b0, dec_tmp} - 1'b1;
-    if (grayval[PTR_WIDTH-1]) begin
-      gray2dec = {1'b1, dec_tmp_sub};
-    end else begin
-      gray2dec = {1'b0, dec_tmp};
-    end
-  endfunction
+    // Algorithm walks up from 0..N-1 then flips the upper bit and walks down from N-1 to 0.
+    function automatic [PTR_WIDTH-1:0] gray2dec(input logic [PTR_WIDTH-1:0] grayval);
+      logic [PTR_WIDTH-2:0] dec_tmp, dec_tmp_sub;
+      logic                 unused_decsub_msb;
+
+      dec_tmp[PTR_WIDTH-2] = grayval[PTR_WIDTH-2];
+      for (int i = PTR_WIDTH-3; i >= 0; i--) begin
+        dec_tmp[i] = dec_tmp[i+1] ^ grayval[i];
+      end
+      {unused_decsub_msb, dec_tmp_sub} = (PTR_WIDTH-1)'(Depth) - {1'b0, dec_tmp} - 1'b1;
+      if (grayval[PTR_WIDTH-1]) begin
+        gray2dec = {1'b1, dec_tmp_sub};
+      end else begin
+        gray2dec = {1'b0, dec_tmp};
+      end
+    endfunction
+
+    // decimal version of read pointer in write domain
+    assign fifo_rptr_sync_combi = gray2dec(fifo_rptr_gray_sync);
+    // decimal version of write pointer in read domain
+    assign fifo_wptr_sync_combi = gray2dec(fifo_wptr_gray_sync);
+
+    assign fifo_rptr_gray_d = dec2gray(fifo_rptr_d);
+    assign fifo_wptr_gray_d = dec2gray(fifo_wptr_d);
+
+  end else if (Depth == 2) begin : g_simple_gray_conversion
+
+    assign fifo_rptr_sync_combi = {fifo_rptr_gray_sync[PTR_WIDTH-1], ^fifo_rptr_gray_sync};
+    assign fifo_wptr_sync_combi = {fifo_wptr_gray_sync[PTR_WIDTH-1], ^fifo_rptr_gray_sync};
+
+    assign fifo_rptr_gray_d = {fifo_rptr_d[PTR_WIDTH-1], ^fifo_rptr_d};
+    assign fifo_wptr_gray_d = {fifo_wptr_d[PTR_WIDTH-1], ^fifo_rptr_d};
+
+  end else begin : g_no_gray_conversion
+
+    assign fifo_rptr_sync_combi = fifo_rptr_gray_sync;
+    assign fifo_wptr_sync_combi = fifo_wptr_gray_sync;
+
+    assign fifo_rptr_gray_d = fifo_rptr_d;
+    assign fifo_wptr_gray_d = fifo_rptr_d;
+
+  end
 
   // TODO: assertions on full, empty, gray transitions