[prim/fifo] Add option to harden prim fifo pointers

Signed-off-by: Timothy Chen <timothytim@google.com>
diff --git a/hw/ip/prim/prim_fifo.core b/hw/ip/prim/prim_fifo.core
index 8f2b077..df12b43 100644
--- a/hw/ip/prim/prim_fifo.core
+++ b/hw/ip/prim/prim_fifo.core
@@ -11,10 +11,12 @@
       - lowrisc:prim:assert
       - lowrisc:prim:util
       - lowrisc:prim:flop_2sync
+      - lowrisc:prim:count_pkg
     files:
       - rtl/prim_fifo_async_sram_adapter.sv
       - rtl/prim_fifo_async.sv
       - rtl/prim_fifo_sync.sv
+      - rtl/prim_fifo_sync_cnt.sv
     file_type: systemVerilogSource
 
   files_verilator_waiver:
diff --git a/hw/ip/prim/rtl/prim_fifo_sync.sv b/hw/ip/prim/rtl/prim_fifo_sync.sv
index 77b8230..1f2115d 100644
--- a/hw/ip/prim/rtl/prim_fifo_sync.sv
+++ b/hw/ip/prim/rtl/prim_fifo_sync.sv
@@ -28,7 +28,8 @@
   output  [Width-1:0]     rdata_o,
   // occupancy
   output                  full_o,
-  output  [DepthW-1:0]    depth_o
+  output  [DepthW-1:0]    depth_o,
+  output                  err_o
 );
 
 
@@ -94,33 +95,48 @@
     assign full_o   = full;
     assign rvalid_o = ~empty & ~under_rst;
 
-    always_ff @(posedge clk_i or negedge rst_ni) begin
-      if (!rst_ni) begin
-        fifo_wptr <= {(PTR_WIDTH){1'b0}};
-      end else if (clr_i) begin
-        fifo_wptr <= {(PTR_WIDTH){1'b0}};
-      end else if (fifo_incr_wptr) begin
-        if (fifo_wptr[PTR_WIDTH-2:0] == (PTR_WIDTH-1)'(Depth-1)) begin
-          fifo_wptr <= {~fifo_wptr[PTR_WIDTH-1],{(PTR_WIDTH-1){1'b0}}};
-        end else begin
-          fifo_wptr <= fifo_wptr + {{(PTR_WIDTH-1){1'b0}},1'b1};
-        end
-      end
-    end
+    prim_fifo_sync_cnt #(
+      .Width(PTR_WIDTH),
+      .Depth(Depth),
+      .Secure('0)
+    ) u_fifo_cnt (
+      .clk_i,
+      .rst_ni,
+      .clr_i,
+      .incr_wptr_i(fifo_incr_wptr),
+      .incr_rptr_i(fifo_incr_rptr),
+      .wptr_o(fifo_wptr),
+      .rptr_o(fifo_rptr),
+      .err_o
+    );
 
-    always_ff @(posedge clk_i or negedge rst_ni) begin
-      if (!rst_ni) begin
-        fifo_rptr <= {(PTR_WIDTH){1'b0}};
-      end else if (clr_i) begin
-        fifo_rptr <= {(PTR_WIDTH){1'b0}};
-      end else if (fifo_incr_rptr) begin
-        if (fifo_rptr[PTR_WIDTH-2:0] == (PTR_WIDTH-1)'(Depth-1)) begin
-          fifo_rptr <= {~fifo_rptr[PTR_WIDTH-1],{(PTR_WIDTH-1){1'b0}}};
-        end else begin
-          fifo_rptr <= fifo_rptr + {{(PTR_WIDTH-1){1'b0}},1'b1};
-        end
-      end
-    end
+    //always_ff @(posedge clk_i or negedge rst_ni) begin
+    //  if (!rst_ni) begin
+    //    fifo_wptr <= {(PTR_WIDTH){1'b0}};
+    //  end else if (clr_i) begin
+    //    fifo_wptr <= {(PTR_WIDTH){1'b0}};
+    //  end else if (fifo_incr_wptr) begin
+    //    if (fifo_wptr[PTR_WIDTH-2:0] == (PTR_WIDTH-1)'(Depth-1)) begin
+    //      fifo_wptr <= {~fifo_wptr[PTR_WIDTH-1],{(PTR_WIDTH-1){1'b0}}};
+    //    end else begin
+    //      fifo_wptr <= fifo_wptr + {{(PTR_WIDTH-1){1'b0}},1'b1};
+    //    end
+    //  end
+    //end
+    //
+    //always_ff @(posedge clk_i or negedge rst_ni) begin
+    //  if (!rst_ni) begin
+    //    fifo_rptr <= {(PTR_WIDTH){1'b0}};
+    //  end else if (clr_i) begin
+    //    fifo_rptr <= {(PTR_WIDTH){1'b0}};
+    //  end else if (fifo_incr_rptr) begin
+    //    if (fifo_rptr[PTR_WIDTH-2:0] == (PTR_WIDTH-1)'(Depth-1)) begin
+    //      fifo_rptr <= {~fifo_rptr[PTR_WIDTH-1],{(PTR_WIDTH-1){1'b0}}};
+    //    end else begin
+    //      fifo_rptr <= fifo_rptr + {{(PTR_WIDTH-1){1'b0}},1'b1};
+    //    end
+    //  end
+    //end
 
     assign  full       = (fifo_wptr == (fifo_rptr ^ {1'b1,{(PTR_WIDTH-1){1'b0}}}));
     assign  fifo_empty = (fifo_wptr ==  fifo_rptr);
diff --git a/hw/ip/prim/rtl/prim_fifo_sync_cnt.sv b/hw/ip/prim/rtl/prim_fifo_sync_cnt.sv
new file mode 100644
index 0000000..b6d539c
--- /dev/null
+++ b/hw/ip/prim/rtl/prim_fifo_sync_cnt.sv
@@ -0,0 +1,102 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+// Generic synchronous fifo for use in a variety of devices.
+
+`include "prim_assert.sv"
+
+module prim_fifo_sync_cnt #(
+  parameter int Depth = 4,
+  parameter int Width = 16,
+  parameter bit Secure = 1'b0
+) (
+  input clk_i,
+  input rst_ni,
+  input clr_i,
+  input incr_wptr_i,
+  input incr_rptr_i,
+  output logic [Width-1:0] wptr_o,
+  output logic [Width-1:0] rptr_o,
+  output logic err_o
+);
+
+  logic wptr_wrap;
+  logic [Width-1:0] wptr_wrap_cnt;
+  logic rptr_wrap;
+  logic [Width-1:0] rptr_wrap_cnt;
+
+  assign wptr_wrap = incr_wptr_i & (wptr_o[Width-2:0] == unsigned'((Width-1)'(Depth-1)));
+  assign rptr_wrap = incr_rptr_i & (rptr_o[Width-2:0] == unsigned'((Width-1)'(Depth-1)));
+
+  assign wptr_wrap_cnt = {~wptr_o[Width-1],{(Width-1){1'b0}}};
+  assign rptr_wrap_cnt = {~rptr_o[Width-1],{(Width-1){1'b0}}};
+
+  if (Secure) begin : gen_secure_ptrs
+    logic wptr_err;
+    prim_count #(
+      .Width(Width),
+      .OutSelDnCnt(0),
+      .CntStyle(prim_count_pkg::DupCnt)
+    ) u_wptr (
+      .clk_i,
+      .rst_ni,
+      .clr_i,
+      .set_i(wptr_wrap),
+      .set_cnt_i(wptr_wrap_cnt),
+      .en_i(incr_wptr_i),
+      .step_i(Width'(1'b1)),
+      .cnt_o(wptr_o),
+      .err_o(wptr_err)
+    );
+
+    logic rptr_err;
+    prim_count #(
+      .Width(Width),
+      .OutSelDnCnt(0),
+      .CntStyle(prim_count_pkg::DupCnt)
+    ) u_rptr (
+      .clk_i,
+      .rst_ni,
+      .clr_i,
+      .set_i(rptr_wrap),
+      .set_cnt_i(rptr_wrap_cnt),
+      .en_i(incr_rptr_i),
+      .step_i(Width'(1'b1)),
+      .cnt_o(rptr_o),
+      .err_o(rptr_err)
+    );
+
+    assign err_o = wptr_err | rptr_err;
+
+  end else begin : gen_normal_ptrs
+    always_ff @(posedge clk_i or negedge rst_ni) begin
+      if (!rst_ni) begin
+        wptr_o <= {(Width){1'b0}};
+      end else if (clr_i) begin
+        wptr_o <= {(Width){1'b0}};
+      end else if (wptr_wrap) begin
+        wptr_o <= wptr_wrap_cnt;
+      end else if (incr_wptr_i) begin
+        wptr_o <= wptr_o + {{(Width-1){1'b0}},1'b1};
+      end
+    end
+
+    always_ff @(posedge clk_i or negedge rst_ni) begin
+      if (!rst_ni) begin
+        rptr_o <= {(Width){1'b0}};
+      end else if (clr_i) begin
+        rptr_o <= {(Width){1'b0}};
+      end else if (rptr_wrap) begin
+         rptr_o <= rptr_wrap_cnt;
+      end else if (incr_rptr_i) begin
+         rptr_o <= rptr_o + {{(Width-1){1'b0}},1'b1};
+      end
+    end
+
+    assign err_o = '0;
+  end
+
+
+
+endmodule // prim_fifo_sync_cnt