diff --git a/hdl/src/primatives/vr_fifo.sv b/hdl/src/primatives/vr_fifo.sv new file mode 100644 index 0000000000000000000000000000000000000000..c5d73b7d390a27c58057140c1e383f1778e5ecf2 --- /dev/null +++ b/hdl/src/primatives/vr_fifo.sv @@ -0,0 +1,149 @@ +//----------------------------------------------------------------------------- +// 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 vr_fifo + #( + parameter DEPTH = 4, // FIFO Row Depth + parameter DATA_W = 32, // FIFO Row Width + parameter PTR_W = $clog2(DEPTH) + 1 // Read/Write Pointer Width + )( + input logic clk, + input logic nrst, + input logic en, + + // In (Write) Control + input logic [DATA_W-1:0] in_data, + input logic in_valid, + output logic in_ready, + + // Out (Read) Control + output logic [DATA_W-1:0] out_data, + input logic out_ready, + output logic out_valid + ); + + logic [DATA_W-1: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; + + logic in_shake; // Successful Write Handshake + logic out_shake; // Successful Read Handshake + + assign in_shake = (in_valid == 1'b1) && (in_ready == 1'b1); + assign out_shake = (out_valid == 1'b1) && (out_ready == 1'b1); + + // 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 out_data = fifo [read_ptr[PTR_W-2:0]]; // Out Data is dereferenced value of the Read Pointer + + always_ff @(posedge clk, negedge nrst) begin + if (!nrst) 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; + in_ready <= 1'b0; + out_valid <= 1'b0; + 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 (in_shake) begin + // Successful Handshake store data in FIFO and increment Write Pointer + fifo [write_ptr[PTR_W-2:0]] <= in_data; + write_ptr <= write_ptr + 1; + if ((ptr_dif + (1 - 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) + in_ready <= 1'b1; + end else begin + // FIFO is now full + 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) + in_ready <= 1'b1; + end + end else begin + if ((ptr_dif - 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) + in_ready <= 1'b1; + end else begin + // FIFO still Full + 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 (out_shake) begin + // Successful Handshake Increment Read Pointer + read_ptr <= read_ptr + 1; + if (((ptr_dif - 1) + (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) + out_valid <= 1'b1; + end else begin + // FIFO empty after latest Read + 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) + out_valid <= 1'b1; + end + end else begin + if (((ptr_dif - 1) + 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) + out_valid <= 1'b1; + end else begin + // FIFO still empty + out_valid <= 1'b0; + end + end + end else begin + // If Enable is Low, set Control Low + in_ready <= 1'b0; + 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