From ce27da6f556a7dd20bcce213278e6f29b8d66332 Mon Sep 17 00:00:00 2001
From: dam1n19 <dam1n19@soton.ac.uk>
Date: Thu, 4 May 2023 12:04:41 +0100
Subject: [PATCH] SOC1-171: Add primitives to primitives repo

---
 src/sv/fifo_vr.sv | 162 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 162 insertions(+)
 create mode 100644 src/sv/fifo_vr.sv

diff --git a/src/sv/fifo_vr.sv b/src/sv/fifo_vr.sv
new file mode 100644
index 0000000..b86b9d4
--- /dev/null
+++ b/src/sv/fifo_vr.sv
@@ -0,0 +1,162 @@
+//-----------------------------------------------------------------------------
+// SoC Labs Basic Parameterisable Valid-Ready FIFO
+// A joint work commissioned on behalf of SoC Labs, under Arm Academic Access license.
+//
+// Contributors
+//
+// David Mapstone (d.a.mapstone@soton.ac.uk)
+//
+// Copyright  2022, SoC Labs (www.soclabs.org)
+//-----------------------------------------------------------------------------
+module fifo_vr #(
+    parameter  DEPTH  = 4,                 // FIFO Row Depth
+    parameter  DATA_W = 32,                // FIFO Row Width
+    localparam PTR_W  = $clog2(DEPTH) + 1  // Read/Write Pointer Width
+)(
+    input logic clk,
+    input logic nrst,
+    input logic en,
+    
+    // Synchronous, localised reset
+    input logic sync_rst,
+    
+    // In (Write) Control
+    input  logic [DATA_W-1:0] data_in,
+    input  logic data_in_last,
+    input  logic data_in_valid,
+    output logic data_in_ready,
+    
+    // Out (Read) Control
+    output logic [DATA_W-1:0] data_out,
+    output logic data_out_last,
+    input  logic data_out_ready,
+    output logic data_out_valid,
+
+    // Status 
+    output logic [PTR_W-1:0] status_ptr_dif
+);
+
+    logic data_in_shake;    // Successful Write Handshake
+    logic data_out_shake;   // Successful Read Handshake
+    
+    assign data_in_shake  = (data_in_valid  == 1'b1) && (data_in_ready  == 1'b1);
+    assign data_out_shake = (data_out_valid == 1'b1) && (data_out_ready == 1'b1);
+    
+    logic [DATA_W:0]   fifo [DEPTH-1:0]; // FIFO Memory Structure
+    logic [PTR_W-1:0]  write_ptr;        // FIFO Write Pointer
+    logic [PTR_W-1:0]  read_ptr;         // FIFO Read Pointer
+    logic [PTR_W-1:0]  ptr_dif;          // Difference between Write and Read Pointers
+    
+    assign ptr_dif = write_ptr - read_ptr;
+    
+    assign status_ptr_dif = ptr_dif;
+    
+    // EXAMPLE: Conditions to write and read from FIFO's
+    // Write Ptr  | Read Ptr  | Ptr_Dif | Valid Write | Valid Read
+    //    000     -    000    =   000   |      Y      |     N
+    //    001     -    000    =   001   |      Y      |     Y
+    //    010     -    000    =   010   |      Y      |     Y
+    //    011     -    000    =   011   |      Y      |     Y
+    //    100     -    000    =   100   |      N      |     Y
+    //    101     -    000    =   101   |      N      |     N
+    //    110     -    000    =   110   |      N      |     N
+    //    111     -    000    =   111   |      N      |     N
+    // WriteValid: WritePtr - ReadPtr < 3'd4
+    // ReadValid:  WritePtr - ReadPtr - 1 < 3'd4
+    
+    assign {data_out,data_out_last} = fifo [read_ptr[PTR_W-2:0]]; // Output Data is dereferenced value of the Read Pointer
+    
+    always_ff @(posedge clk, negedge nrst) begin
+        if ((!nrst) || sync_rst) begin
+            // Under Reset
+            // - Pointers reset to 0 (FIFO is empty without needing to reset the memories)
+            // - Control taken low
+            write_ptr    <= 0;
+            read_ptr     <= 0;
+            data_in_ready     <= 1'b0;
+            data_out_valid    <= 1'b0;
+            // Ensure FIFO Values are Known
+            for (int i = 0; i < DEPTH; i++) begin
+                fifo[i] <= 'b0;
+            end
+        end else if (en == 1'b1) begin
+            // Enable signal is High
+            // Write Logic
+            if (ptr_dif < DEPTH) begin 
+                // Empty Rows in FIFO in FIFO
+                if (data_in_shake) begin 
+                    // Successful Handshake store data in FIFO and increment Write Pointer 
+                    fifo [write_ptr[PTR_W-2:0]] <= {data_in,data_in_last};
+                    write_ptr                   <= write_ptr + 1;
+                    if ((ptr_dif + {{(PTR_W-1){1'b0}},(1'b1 - data_out_shake)}) < DEPTH) begin 
+                        // Still space in FIFO after latest write
+                        // If theres a successful read on this clock cycle, 
+                        // there will be an additional space in the FIFO next clock cycle
+                        // (number of pieces of data in the FIFO won't have changed)
+                        data_in_ready <= 1'b1;
+                    end else begin 
+                        // FIFO is now full
+                        data_in_ready <= 1'b0;
+                    end
+                end else begin 
+                    // Unsuccessful handshake but space in FIFO
+                    // If there's write space now, next cc it will be the same or more 
+                    // (more if a succesful read has been carried out in this cc)
+                    data_in_ready <= 1'b1;
+                end
+            end else begin
+                if ((ptr_dif - {{(PTR_W-1){1'b0}}, data_out_shake}) < DEPTH) begin 
+                    // If there is a successful read this clock cycle, 
+                    // there will be space for another piece of data in the FIFO 
+                    // (number of pieces of data in FIFO will have decremented by 1) 
+                    data_in_ready <= 1'b1;
+                end else begin 
+                    // FIFO still Full
+                    data_in_ready <= 1'b0;
+                end
+            end
+            // Read Logic
+            if ((ptr_dif - 1) < DEPTH) begin 
+                // Data in FIFO - atleast one Piece of Data in FIFO
+                // -> the  "-1" causes dif of 0 to wrap where (dif - 1) becomes > DEPTH
+                if (data_out_shake) begin 
+                    // Successful Handshake Increment Read Pointer
+                    read_ptr       <= read_ptr + 1;
+                    if (((ptr_dif - 1) + {{(PTR_W-1){1'b0}},data_in_shake}) - 1 < DEPTH) begin
+                        // Still Data in FIFO after latest Read
+                        // If there is a successful write this clock cycle, 
+                        // there will be one more piece of data in the FIFO 
+                        // (number of pieces of data in FIFO wont have changed) 
+                        data_out_valid <= 1'b1;
+                    end else begin 
+                        // FIFO empty after latest Read
+                        data_out_valid <= 1'b0;
+                    end
+                end else begin 
+                    // Unsuccessful handshake but Data in FIFO
+                    // If there's read data now, next cc it will be the same or more 
+                    // (more if a succesful write has been carried out in this cc)
+                    data_out_valid <= 1'b1;
+                end
+            end else begin
+                if (((ptr_dif - 1) + {{(PTR_W-1){1'b0}},data_in_shake}) < DEPTH) begin 
+                    // If there is a successful write this clock cycle, 
+                    // there will be one more piece of data in the FIFO 
+                    // (number of pieces of data in FIFO will have incremented by 1) 
+                    data_out_valid <= 1'b1;
+                end else begin 
+                    // FIFO still empty
+                    data_out_valid <= 1'b0;
+                end
+            end
+        end else begin
+            // If Enable is Low, set Control Low
+            data_in_ready  <= 1'b0;
+            data_out_valid <= 1'b0;
+        end
+    end
+    
+    // Verif Notes to Check behaiour:
+    // 1) Fill FIFO up with Data
+    // 2) Read & Write in same clock cycle 
+endmodule
-- 
GitLab