[prim] SRAM Async FIFO
In this commit, SRAM Asynchronous FIFO primitive lib is added. It
follows same principle in the prim_fifo_async but the logic uses
Dual-port SRAM to store the data.
Signed-off-by: Eunchan Kim <eunchan@opentitan.org>
diff --git a/hw/formal/tools/jaspergold/fpv.tcl b/hw/formal/tools/jaspergold/fpv.tcl
index e993d52..a268b5b 100644
--- a/hw/formal/tools/jaspergold/fpv.tcl
+++ b/hw/formal/tools/jaspergold/fpv.tcl
@@ -69,6 +69,12 @@
# clock clk_main_i -both_edges
# reset -expr {!rst_main_ni}
+} elseif {$env(DUT_TOP) == "prim_fifo_async_sram_adapter_fpv"} {
+ clock clk_wr_i -factor 2
+ clock -rate {wvalid_i, wready_o, wdata_i} clk_wr_i
+ clock clk_rd_i -factor 3
+ clock -rate {rvalid_o, rready_i, rdata_o} clk_rd_i
+ reset -expr {!rst_ni}
} else {
clock clk_i -both_edges
reset -expr {!rst_ni}
diff --git a/hw/ip/prim/fpv/prim_fifo_async_sram_adapter_fpv.core b/hw/ip/prim/fpv/prim_fifo_async_sram_adapter_fpv.core
new file mode 100644
index 0000000..1b546d8
--- /dev/null
+++ b/hw/ip/prim/fpv/prim_fifo_async_sram_adapter_fpv.core
@@ -0,0 +1,27 @@
+CAPI=2:
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+name: "lowrisc:fpv:prim_fifo_async_sram_adapter_fpv:0.1"
+description: "prim_fifo_async_sram_adapter FPV target"
+filesets:
+ files_formal:
+ depend:
+ - lowrisc:prim:all
+ - lowrisc:prim:ram_2p_async_adv
+ files:
+ - tb/prim_fifo_async_sram_adapter_fpv.sv
+ file_type: systemVerilogSource
+
+targets:
+ default: &default_target
+ default_tool: icarus
+ filesets:
+ - files_formal
+ toplevel: prim_fifo_async_sram_adapter_fpv
+
+ formal:
+ <<: *default_target
+
+ lint:
+ <<: *default_target
diff --git a/hw/ip/prim/fpv/tb/prim_fifo_async_sram_adapter_fpv.sv b/hw/ip/prim/fpv/tb/prim_fifo_async_sram_adapter_fpv.sv
new file mode 100644
index 0000000..fb3dda9
--- /dev/null
+++ b/hw/ip/prim/fpv/tb/prim_fifo_async_sram_adapter_fpv.sv
@@ -0,0 +1,204 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+// Testbench module for prim_fifo_sram_async
+
+module prim_fifo_async_sram_adapter_fpv #(
+ parameter int unsigned Width = 32,
+ parameter int unsigned Depth = 16,
+
+ parameter int unsigned FpgaSram = 0 // Use FF based
+) (
+ input clk_wr_i,
+ input clk_rd_i,
+
+ input rst_ni,
+
+ input wvalid_i,
+ output logic wready_o,
+ input [Width-1:0] wdata_i,
+
+ output logic rvalid_o,
+ input rready_i,
+ output logic [Width-1:0] rdata_o
+);
+
+ localparam int unsigned SramAw = 7;
+ localparam int unsigned SramDw = 32;
+ localparam logic [SramAw-1:0] SramBaseAddr = 'h 30;
+
+ logic w_sram_req;
+ logic w_sram_gnt;
+ logic w_sram_write;
+ logic [SramAw-1:0] w_sram_addr;
+ logic [SramDw-1:0] w_sram_wdata;
+ logic [SramDw-1:0] w_sram_wmask;
+ logic w_sram_rvalid; // not used
+ logic [SramDw-1:0] w_sram_rdata; // not used
+ logic [1:0] w_sram_rerror; // not used
+
+ logic r_sram_req;
+ logic r_sram_gnt;
+ logic r_sram_write;
+ logic [SramAw-1:0] r_sram_addr;
+ logic [SramDw-1:0] r_sram_wdata; // not used
+ logic [SramDw-1:0] r_sram_wmask; // not used
+ logic r_sram_rvalid;
+ logic [SramDw-1:0] r_sram_rdata;
+ logic [1:0] r_sram_rerror;
+
+ prim_fifo_async_sram_adapter #(
+ .Width (Width),
+ .Depth (Depth),
+
+ .SramAw (SramAw), // TODO: random with constraint
+ .SramDw (SramDw), // TODO: random with constraint
+
+ .SramBaseAddr(SramBaseAddr) // TODO: random?
+ ) dut (
+ .clk_wr_i,
+ .rst_wr_ni (rst_ni),
+ .clk_rd_i,
+ .rst_rd_ni (rst_ni),
+
+ .wvalid_i,
+ .wready_o,
+ .wdata_i,
+
+ .wdepth_o (),
+
+ .rvalid_o,
+ .rready_i,
+ .rdata_o,
+
+ .rdepth_o (),
+
+ // Sram Interface
+ .w_sram_req_o (w_sram_req ),
+ .w_sram_gnt_i (w_sram_gnt ),
+ .w_sram_write_o (w_sram_write ),
+ .w_sram_addr_o (w_sram_addr ),
+ .w_sram_wdata_o (w_sram_wdata ),
+ .w_sram_wmask_o (w_sram_wmask ),
+ .w_sram_rvalid_i(w_sram_rvalid), // not used
+ .w_sram_rdata_i (w_sram_rdata ), // not used
+ .w_sram_rerror_i(w_sram_rerror), // not used
+
+ // Read SRAM port
+ .r_sram_req_o (r_sram_req ),
+ .r_sram_gnt_i (r_sram_gnt ),
+ .r_sram_write_o (r_sram_write ),
+ .r_sram_addr_o (r_sram_addr ),
+ .r_sram_wdata_o (r_sram_wdata ), // not used
+ .r_sram_wmask_o (r_sram_wmask ), // not used
+ .r_sram_rvalid_i(r_sram_rvalid),
+ .r_sram_rdata_i (r_sram_rdata ),
+ .r_sram_rerror_i(r_sram_rerror),
+
+ .r_full_o(),
+
+ .r_notempty_o(),
+
+ .w_full_o()
+ );
+
+if (FpgaSram == 1) begin : g_sram_fpga
+ // FPV looks like does not like the style of ram_2p.
+ prim_ram_2p #(
+ .Depth (2**SramAw),
+ .Width (SramDw),
+ .DataBitsPerMask (1)
+ ) u_sram (
+ .clk_a_i (clk_wr_i),
+ .clk_b_i (clk_rd_i),
+
+ .a_req_i (w_sram_req ),
+ .a_write_i (w_sram_write ),
+ .a_addr_i (w_sram_addr ),
+ .a_wdata_i (w_sram_wdata ),
+ .a_wmask_i (w_sram_wmask ),
+ .a_rdata_o (w_sram_rdata ),
+
+ .b_req_i (r_sram_req ),
+ .b_write_i (r_sram_write ),
+ .b_addr_i (r_sram_addr ),
+ .b_wdata_i (r_sram_wdata ),
+ .b_wmask_i (r_sram_wmask ),
+ .b_rdata_o (r_sram_rdata ),
+
+ .cfg_i ('0)
+ );
+end else begin : g_sram_ff
+ logic [SramDw-1:0] mem [2**SramAw];
+
+ always_ff @(posedge clk_wr_i) begin
+ if (w_sram_req && w_sram_write) begin
+ for (int unsigned i = 0; i < SramDw ; i++) begin
+ if (w_sram_wmask[i]) mem[w_sram_addr][i] <= w_sram_wdata[i];
+ end // for
+ end // if
+ end
+
+ always_ff @(posedge clk_rd_i) begin
+ if (r_sram_req && !r_sram_write) begin
+ r_sram_rdata <= mem[r_sram_addr];
+ end
+ end
+end // !FpgaSram
+
+ assign w_sram_gnt = w_sram_req;
+
+ always_ff @(posedge clk_wr_i) begin
+ w_sram_rvalid <= w_sram_req && !w_sram_write;
+ end
+
+ assign w_sram_rerror = '0;
+
+ assign r_sram_gnt = r_sram_req;
+
+ always_ff @(posedge clk_rd_i) begin
+ r_sram_rvalid <= r_sram_req && !r_sram_write;
+ end
+
+ assign r_sram_rerror = '0;
+
+ `ASSUME_FPV(WdataBins_M,
+ wvalid_i |-> wdata_i inside {
+ 32'h DEAD_BEEF, 32'h5A5A_A5A5, 32'h 1234_5678
+ },
+ clk_wr_i, !rst_ni)
+
+`ifdef FPV_ON
+ logic [Width-1:0] storage [Depth];
+ logic [Width-1:0] rdata;
+ logic [$clog2(Depth)-1:0] wptr, rptr;
+ logic wack, rack;
+
+ assign wack = wvalid_i && wready_o;
+ assign rack = rvalid_o && rready_i;
+
+ always_ff @(posedge clk_wr_i or negedge rst_ni) begin
+ if (!rst_ni) wptr <= '0;
+ else if (wack) wptr <= wptr+1;
+ end
+ always_ff @(posedge clk_rd_i or negedge rst_ni) begin
+ if (!rst_ni) rptr <= '0;
+ else if (rack) rptr <= rptr+1;
+ end
+
+ always_ff @(posedge clk_wr_i or negedge rst_ni) begin
+ if (!rst_ni) storage <= '{default:'0};
+ else if (wack) begin
+ storage[wptr] <= wdata_i;
+ end
+ end
+
+ assign rdata = storage[rptr];
+
+ `ASSERT(DataIntegrityCheck_A,
+ rack |-> rdata_o == rdata,
+ clk_rd_i, !rst_ni)
+`endif // FPV_ON
+
+endmodule : prim_fifo_async_sram_adapter_fpv
diff --git a/hw/ip/prim/prim_fifo.core b/hw/ip/prim/prim_fifo.core
index 169e247..8f2b077 100644
--- a/hw/ip/prim/prim_fifo.core
+++ b/hw/ip/prim/prim_fifo.core
@@ -12,6 +12,7 @@
- lowrisc:prim:util
- lowrisc:prim:flop_2sync
files:
+ - rtl/prim_fifo_async_sram_adapter.sv
- rtl/prim_fifo_async.sv
- rtl/prim_fifo_sync.sv
file_type: systemVerilogSource
diff --git a/hw/ip/prim/rtl/prim_fifo_async_sram_adapter.sv b/hw/ip/prim/rtl/prim_fifo_async_sram_adapter.sv
new file mode 100644
index 0000000..1cebd53
--- /dev/null
+++ b/hw/ip/prim/rtl/prim_fifo_async_sram_adapter.sv
@@ -0,0 +1,411 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+// Generic Asynchronous SRAM FIFO (Dual port SRAM)
+
+`include "prim_assert.sv"
+
+module prim_fifo_async_sram_adapter #(
+ parameter int unsigned Width = 32,
+ parameter int unsigned Depth = 16,
+
+ // SRAM parameters
+ parameter int unsigned SramAw = 16,
+
+ // If SramDw > Width, upper data bits are 0.
+ parameter int unsigned SramDw = 32,
+ parameter logic [SramAw-1:0] SramBaseAddr = 'h 0,
+
+ // derived
+ localparam int unsigned DepthW = $clog2(Depth+1)
+) (
+ // Write port
+ input clk_wr_i,
+ input rst_wr_ni,
+ input wvalid_i,
+ output logic wready_o,
+ input [Width-1:0] wdata_i,
+ output logic [DepthW-1:0] wdepth_o,
+
+ // Read port
+ input clk_rd_i,
+ input rst_rd_ni,
+ output logic rvalid_o,
+ input rready_i,
+ output logic [Width-1:0] rdata_o,
+ output logic [DepthW-1:0] rdepth_o,
+
+ output logic r_full_o,
+ output logic r_notempty_o,
+
+ output logic w_full_o,
+
+ // TODO: watermark(threshold) ?
+
+ // SRAM interface
+ // Write SRAM port
+ output logic w_sram_req_o,
+ input w_sram_gnt_i,
+ output logic w_sram_write_o,
+ output logic [SramAw-1:0] w_sram_addr_o,
+ output logic [SramDw-1:0] w_sram_wdata_o,
+ output logic [SramDw-1:0] w_sram_wmask_o,
+ input w_sram_rvalid_i, // not used
+ input [SramDw-1:0] w_sram_rdata_i, // not used
+ input [1:0] w_sram_rerror_i, // not used
+
+ // Read SRAM port
+ output logic r_sram_req_o,
+ input r_sram_gnt_i,
+ output logic r_sram_write_o,
+ output logic [SramAw-1:0] r_sram_addr_o,
+ output logic [SramDw-1:0] r_sram_wdata_o, // not used
+ output logic [SramDw-1:0] r_sram_wmask_o, // not used
+ input r_sram_rvalid_i,
+ input [SramDw-1:0] r_sram_rdata_i,
+ input [1:0] r_sram_rerror_i
+);
+
+ ////////////////
+ // Definition //
+ ////////////////
+ // w_: write clock domain signals
+ // r_: read clock domain signals
+
+ // PtrVW: Pointer Value (without msb, flip) width
+ localparam int unsigned PtrVW = $clog2(Depth);
+ // PtrW: Read/Write pointer with flip bit
+ localparam int unsigned PtrW = PtrVW+1;
+
+ ////////////
+ // Signal //
+ ////////////
+
+ logic [PtrW-1:0] w_wptr_q, w_wptr_d, w_wptr_gray_d, w_wptr_gray_q;
+ logic [PtrW-1:0] r_wptr_gray, r_wptr;
+ logic [PtrVW-1:0] w_wptr_v, r_wptr_v;
+ logic w_wptr_p, r_wptr_p; // phase
+
+ logic [PtrW-1:0] r_rptr_q, r_rptr_d, r_rptr_gray_d, r_rptr_gray_q;
+ logic [PtrW-1:0] w_rptr_gray, w_rptr;
+ logic [PtrVW-1:0] r_rptr_v, w_rptr_v;
+ logic r_rptr_p, w_rptr_p; // phase
+
+ logic w_wptr_inc, r_rptr_inc;
+
+ logic w_full, r_full, r_empty;
+
+ // SRAM response one clock delayed. So store the value into read clock
+ // domain
+ logic stored;
+ logic [Width-1:0] rdata_q, rdata_d;
+
+ // SRAM has another read pointer (for address of SRAM req)
+ // It is -1 of r_rptr if stored, else same to r_rptr
+ logic r_sram_rptr_inc;
+ logic [PtrW-1:0] r_sram_rptr;
+
+ // r_sram_rptr == r_wptr
+ // Used to determine r_sram_req
+ logic r_sramrptr_empty;
+
+ logic rfifo_ack; // Used to check if FIFO read interface consumes a data
+ logic rsram_ack;
+
+ //////////////
+ // Datapath //
+ //////////////
+
+ // Begin: Write pointer sync to read clock ========================
+ assign w_wptr_inc = wvalid_i & wready_o;
+
+ assign w_wptr_d = w_wptr_q + PtrW'(1);
+
+ always_ff @(posedge clk_wr_i or negedge rst_wr_ni) begin
+ if (!rst_wr_ni) begin
+ w_wptr_q <= PtrW'(0);
+ w_wptr_gray_q <= PtrW'(0);
+ end else if (w_wptr_inc) begin
+ w_wptr_q <= w_wptr_d;
+ w_wptr_gray_q <= w_wptr_gray_d;
+ end
+ end
+
+ assign w_wptr_v = w_wptr_q[0+:PtrVW];
+ assign w_wptr_p = w_wptr_q[PtrW-1];
+
+ assign w_wptr_gray_d = dec2gray(w_wptr_d);
+
+ prim_flop_2sync #(
+ .Width (PtrW)
+ ) u_sync_wptr_gray (
+ .clk_i (clk_rd_i),
+ .rst_ni (rst_rd_ni),
+ .d_i (w_wptr_gray_q),
+ .q_o (r_wptr_gray)
+ );
+
+ assign r_wptr = gray2dec(r_wptr_gray);
+ assign r_wptr_p = r_wptr[PtrW-1];
+ assign r_wptr_v = r_wptr[0+:PtrVW];
+
+ assign wdepth_o = (w_wptr_p == w_rptr_p)
+ ? DepthW'(w_wptr_v - w_rptr_v)
+ : DepthW'({1'b1, w_wptr_v} - {1'b 0, w_rptr_v});
+ // End: Write pointer sync to read clock ------------------------
+
+ // Begin: Read pointer sync to write clock ========================
+ //assign r_rptr_inc = rvalid_o & rready_i;
+ //assign r_rptr_inc = r_sram_req_o && r_sram_gnt_i;
+ // Increase the read pointer (crossing the clock domain) only when the
+ // reader acked.
+ assign r_rptr_inc = rfifo_ack;
+
+ assign r_rptr_d = r_rptr_q + PtrW'(1);
+
+ always_ff @(posedge clk_rd_i or negedge rst_rd_ni) begin
+ if (!rst_rd_ni) begin
+ r_rptr_q <= PtrW'(0);
+ r_rptr_gray_q <= PtrW'(0);
+ end else if (r_rptr_inc) begin
+ r_rptr_q <= r_rptr_d;
+ r_rptr_gray_q <= r_rptr_gray_d;
+ end
+ end
+
+ assign r_rptr_v = r_rptr_q[0+:PtrVW];
+ assign r_rptr_p = r_rptr_q[PtrW-1];
+
+ assign r_rptr_gray_d = dec2gray(r_rptr_d);
+
+ prim_flop_2sync #(
+ .Width (PtrW)
+ ) u_sync_rptr_gray (
+ .clk_i (clk_wr_i),
+ .rst_ni (rst_wr_ni),
+ .d_i (r_rptr_gray_q),
+ .q_o (w_rptr_gray)
+ );
+
+ assign w_rptr = gray2dec(w_rptr_gray);
+ assign w_rptr_p = w_rptr[PtrW-1];
+ assign w_rptr_v = w_rptr[0+:PtrVW];
+
+ assign rdepth_o = (r_wptr_p == r_rptr_p)
+ ? DepthW'(r_wptr_v - r_rptr_v)
+ : DepthW'({1'b1, r_wptr_v} - {1'b 0, r_rptr_v});
+ // End: Read pointer sync to write clock ------------------------
+
+ // Begin: SRAM Read pointer
+ assign r_sram_rptr_inc = rsram_ack;
+
+ always_ff @(posedge clk_rd_i or negedge rst_rd_ni) begin
+ if (!rst_rd_ni) begin
+ r_sram_rptr <= PtrW'(0);
+ end else if (r_sram_rptr_inc) begin
+ r_sram_rptr <= r_sram_rptr + PtrW'(1);
+ end
+ end
+
+ assign r_sramrptr_empty = (r_wptr == r_sram_rptr);
+ // End: SRAM Read pointer
+
+ // Full/ Empty
+ localparam logic [PtrW-1:0] XorMask = PtrW'(1) << (PtrW-1);
+ assign w_full = (w_wptr_q == (w_rptr ^ XorMask));
+ assign r_full = (r_wptr == (r_rptr_q ^ XorMask));
+ assign r_empty = (r_wptr == r_rptr_q);
+
+ assign r_full_o = r_full;
+ assign r_notempty_o = !r_empty;
+ assign w_full_o = w_full;
+
+ assign rsram_ack = r_sram_req_o && r_sram_gnt_i;
+ assign rfifo_ack = rvalid_o && rready_i;
+
+ // SRAM Write Request
+ assign w_sram_req_o = wvalid_i && !w_full;
+ assign wready_o = !w_full && w_sram_gnt_i;
+ assign w_sram_write_o = 1'b 1; // Always write
+ assign w_sram_addr_o = SramBaseAddr + SramAw'(w_wptr_v);
+
+ assign w_sram_wdata_o = SramDw'(wdata_i);
+ assign w_sram_wmask_o = SramDw'(2**Width-1);
+
+ logic w_unused_sram;
+ assign w_unused_sram = ^{w_sram_rvalid_i, w_sram_rdata_i, w_sram_rerror_i};
+
+ // SRAM Read Request
+ // Request Scenario (!r_empty):
+ // - storage empty: Send request if
+ // !r_sram_rvalid_i || (rfifo_ack && r_sram_rvalid_i);
+ // - storage !empty: depends on the rfifo_ack:
+ // - r_rptr_inc: Can request more
+ // - !r_rptr_inc: Can't request
+ always_comb begin : r_sram_req
+ r_sram_req_o = 1'b 0;
+ // Karnough Map (!empty): sram_req
+ // {sram_rv, rfifo_ack} | 00 | 01 | 11 | 10
+ // ----------------------------------------------------------
+ // stored | 0 | 1 | impossible | 1 | 0
+ // | 1 | 0 | 1 | X | impossible
+ //
+ // req_o = r_ptr_inc || (!stored && !r_sram_rvalid_i)
+
+ if (stored) begin
+ // storage has data. depends on rfifo_ack
+ // rfifo_ack can be replaced to rready_i as `rvalid_o` is 1
+ r_sram_req_o = !r_sramrptr_empty && rfifo_ack;
+ end else begin
+ // storage has no data.
+ // Can send request only when the reader accept the request or no
+ // previous request sent out.
+ r_sram_req_o = !r_sramrptr_empty && !(r_sram_rvalid_i ^ rfifo_ack);
+ end
+ end : r_sram_req
+
+ assign rvalid_o = stored || r_sram_rvalid_i;
+ assign r_sram_write_o = 1'b 0; // always read
+ assign r_sram_wdata_o = '0;
+ assign r_sram_wmask_o = '0;
+
+ // Send SRAM request with sram read pointer.
+ assign r_sram_addr_o = SramBaseAddr + SramAw'(r_sram_rptr[0+:PtrVW]);
+
+ assign rdata_d = r_sram_rdata_i[0+:Width];
+
+ assign rdata_o = (stored) ? rdata_q : rdata_d;
+
+ logic unused_rsram;
+ assign unused_rsram = ^{r_sram_rerror_i};
+
+ // read clock domain rdata storage
+ logic store;
+
+ // Karnough Map (r_sram_rvalid_i):
+ // rfifo_ack | 0 | 1 |
+ // ---------------------
+ // stored 0 | 1 | 0 |
+ // 1 | 0 | 1 |
+ //
+ // stored = s.r.v && XNOR(stored, rptr_inc)
+ assign store = r_sram_rvalid_i && !(stored ^ rfifo_ack);
+
+ always_ff @(posedge clk_rd_i or negedge rst_rd_ni) begin
+ if (!rst_rd_ni) begin
+ stored <= 1'b 0;
+ rdata_q <= Width'(0);
+ end else if (store) begin
+ stored <= 1'b 1;
+ rdata_q <= rdata_d;
+ end else if (!r_sram_rvalid_i && rfifo_ack) begin
+ // No request sent, host reads the data
+ stored <= 1'b 0;
+ rdata_q <= Width'(0);
+ end
+ end
+
+ //////////////
+ // Function //
+ //////////////
+
+ // dec2gray / gray2dec copied from prim_fifo_async.sv
+ function automatic [PtrW-1:0] dec2gray(input logic [PtrW-1:0] decval);
+ logic [PtrW-1:0] decval_sub;
+ logic [PtrW-1:0] decval_in;
+ logic unused_decval_msb;
+
+ decval_sub = (PtrW)'(Depth) - {1'b0, decval[PtrW-2:0]} - 1'b1;
+
+ decval_in = decval[PtrW-1] ? decval_sub : decval;
+
+ // We do not care about the MSB, hence we mask it out
+ unused_decval_msb = decval_in[PtrW-1];
+ decval_in[PtrW-1] = 1'b0;
+
+ // Perform the XOR conversion
+ dec2gray = decval_in;
+ dec2gray ^= (decval_in >> 1);
+
+ // Override the MSB
+ dec2gray[PtrW-1] = decval[PtrW-1];
+ endfunction
+
+ // Algorithm walks up from 0..N-1 then flips the upper bit and walks down from N-1 to 0.
+ function automatic [PtrW-1:0] gray2dec(input logic [PtrW-1:0] grayval);
+ logic [PtrW-1:0] dec_tmp, dec_tmp_sub;
+ logic unused_decsub_msb;
+
+ dec_tmp = '0;
+ for (int i = PtrW-2; i >= 0; i--) begin
+ dec_tmp[i] = dec_tmp[i+1] ^ grayval[i];
+ end
+ dec_tmp_sub = (PtrW)'(Depth) - dec_tmp - 1'b1;
+ if (grayval[PtrW-1]) begin
+ gray2dec = dec_tmp_sub;
+ // Override MSB
+ gray2dec[PtrW-1] = 1'b1;
+ unused_decsub_msb = dec_tmp_sub[PtrW-1];
+ end else begin
+ gray2dec = dec_tmp;
+ end
+ endfunction
+
+ ///////////////
+ // Assertion //
+ ///////////////
+
+ `ASSERT_INIT(ParamCheckDepth_A, (Depth == 2**$clog2(Depth)))
+
+ // Use FF if less than 4.
+ `ASSERT_INIT(MinDepth_A, Depth >= 4)
+
+ // SramDw greather than or equal to Width
+ `ASSERT_INIT(WidthMatch_A, SramDw >= Width)
+
+ // Not stored, Not read valid, but rptr_inc case is impossible
+ `ASSERT(RptrIncDataValid_A,
+ r_rptr_inc |-> stored || r_sram_rvalid_i,
+ clk_rd_i, !rst_rd_ni)
+ `ASSERT(SramRvalid_A,
+ r_sram_rvalid_i |-> !stored || r_rptr_inc,
+ clk_rd_i, !rst_rd_ni)
+
+ // FIFO interface
+ `ASSERT(NoWAckInFull_A, w_wptr_inc |-> !w_full,
+ clk_wr_i, !rst_wr_ni)
+
+ `ASSERT(WptrIncrease_A,
+ w_wptr_inc |=> w_wptr_v == PtrVW'($past(w_wptr_v) + 1),
+ clk_wr_i, !rst_wr_ni)
+ `ASSERT(WptrGrayOneBitAtATime_A,
+ w_wptr_inc |=> $countones(w_wptr_gray_q ^ $past(w_wptr_gray_q)) == 1,
+ clk_wr_i, !rst_wr_ni)
+
+ `ASSERT(NoRAckInEmpty_A, r_rptr_inc |-> !r_empty,
+ clk_rd_i, !rst_rd_ni)
+
+ `ASSERT(RptrIncrease_A,
+ r_rptr_inc |=> PtrVW'($past(r_rptr_v) + 1) == r_rptr_v,
+ clk_rd_i, !rst_rd_ni)
+ `ASSERT(RptrGrayOneBitAtATime_A,
+ r_rptr_inc |=> $countones(r_rptr_gray_q ^ $past(r_rptr_gray_q)) == 1,
+ clk_rd_i, !rst_rd_ni)
+
+ // SRAM interface
+ `ASSERT(WSramRvalid_A, !w_sram_rvalid_i, clk_wr_i, !rst_wr_ni)
+ `ASSUME_FPV(WSramRdataError_M, w_sram_rdata_i == '0 && w_sram_rerror_i == '0,
+ clk_wr_i, !rst_wr_ni)
+
+ `ASSUME(RSramRvalidOneCycle_M,
+ r_sram_req_o && r_sram_gnt_i |=> r_sram_rvalid_i,
+ clk_rd_i, !rst_rd_ni)
+ `ASSUME_FPV(RErrorTied_M, r_sram_rerror_i == '0,
+ clk_rd_i, !rst_rd_ni)
+
+
+ // FPV coverage
+ `COVER_FPV(WFull_C, w_full, clk_wr_i, !rst_wr_ni)
+
+endmodule : prim_fifo_async_sram_adapter