Create FIFO_v.v
diff --git a/verilog/rtl/FIFO_v.v b/verilog/rtl/FIFO_v.v
new file mode 100644
index 0000000..904db93
--- /dev/null
+++ b/verilog/rtl/FIFO_v.v
@@ -0,0 +1,240 @@
+//////////////////////////// FIFO RAM MEMORY ///////////////////////////////////--
+// ***********************************************************************
+// FileName: FIFO_v.v
+// FPGA: Lattice ECP2-70E
+// IDE: Lattice Diamond ver 2.0.1
+//
+// HDL IS PROVIDED "AS IS." DIGI-KEY EXPRESSLY DISCLAIMS ANY
+// WARRANTY OF ANY KIND, WHETHER EXPRESS OR IMPLIED, INCLUDING BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+// PARTICULAR PURPOSE, OR NON-INFRINGEMENT. IN NO EVENT SHALL DIGI-KEY
+// BE LIABLE FOR ANY INCIDENTAL, SPECIAL, INDIRECT OR CONSEQUENTIAL
+// DAMAGES, LOST PROFITS OR LOST DATA, HARM TO YOUR EQUIPMENT, COST OF
+// PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY OR SERVICES, ANY CLAIMS
+// BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF),
+// ANY CLAIMS FOR INDEMNITY OR CONTRIBUTION, OR OTHER SIMILAR COSTS.
+// DIGI-KEY ALSO DISCLAIMS ANY LIABILITY FOR PATENT OR COPYRIGHT
+// INFRINGEMENT.
+//
+// Version History
+// Version 1.0 28/7/2013 Tony Storey
+// Initial Public Release
+
+`timescale 1ns/ 100 ps
+
+module FIFO_v #(parameter ADDR_W = 5, DATA_W = 8, BUFF_L = 32, ALMST_F = 5, ALMST_E = 5) // buffer length must be less than or equal to address space as in BUFF_L <or= 2^(ADDR_W)-1
+ (
+ input wire clk,
+ input wire n_reset,
+ input wire wr_en,
+ input wire [DATA_W -1 : 0] data_in,
+ input wire rd_en,
+
+ output reg [DATA_W- 1 : 0] data_out,
+ output reg [ADDR_W : 0] data_count,
+ output reg empty,
+ output reg full,
+ output reg almst_empty,
+ output reg almst_full,
+ output reg err
+
+ );
+
+
+////--------------- internal variables ---------------------------------------------------------
+
+ reg [DATA_W-1 : 0] mem_array [0 : (2**ADDR_W)-1];
+ reg [ADDR_W-1 : 0] rd_ptr, wr_ptr;
+ reg [ADDR_W-1 : 0] rd_ptr_nxt, wr_ptr_nxt;
+ reg full_ff, empty_ff;
+ reg full_ff_nxt, empty_ff_nxt;
+ reg almst_f_ff, almst_e_ff;
+ reg almst_f_ff_nxt, almst_e_ff_nxt;
+ reg [ADDR_W : 0] q_reg, q_nxt;
+ reg q_add, q_sub;
+//// ------------------------------------------------------------------------------------------------
+
+
+//// Always block to update the states
+//// ------------------------------------------------------------------------------------------------
+ always @ (posedge clk)
+ begin : reg_update
+ if(n_reset == 1'b 0)
+ begin
+ rd_ptr <= {(ADDR_W-1){1'b 0}};
+ wr_ptr <= {(ADDR_W-1){1'b 0}};
+ full_ff <= 1'b 0;
+ empty_ff <= 1'b 1;
+ almst_f_ff <= 1'b 0;
+ almst_e_ff <= 1'b 1;
+ q_reg <= {(ADDR_W){1'b 0}};
+ end
+ else
+ begin
+ rd_ptr <= rd_ptr_nxt;
+ wr_ptr <= wr_ptr_nxt;
+ full_ff <= full_ff_nxt;
+ empty_ff <= empty_ff_nxt;
+ almst_f_ff <= almst_f_ff_nxt;
+ almst_e_ff <= almst_e_ff_nxt;
+ q_reg <= q_nxt;
+ end
+ end // end of always
+
+//// Control for almost full and almost emptly flags
+//// ------------------------------------------------------------------------------------------------
+ always @ ( almst_e_ff, almst_f_ff, q_reg)
+ begin : Wtr_Mrk_Cont
+ almst_e_ff_nxt = almst_e_ff;
+ almst_f_ff_nxt = almst_f_ff;
+ //// check to see if wr_ptr is ALMST_E away from rd_ptr (aka almost empty)
+ if(q_reg < ALMST_E)
+ almst_e_ff_nxt = 1'b 1;
+ else
+ almst_e_ff_nxt = 1'b 0;
+
+ if(q_reg > BUFF_L-ALMST_F)
+ almst_f_ff_nxt = 1'b 1;
+ else
+ almst_f_ff_nxt = 1'b 0;
+
+ end // end of always
+
+//// Control for read and write pointers and empty/full flip flops
+ always @ (wr_en, rd_en, wr_ptr, rd_ptr, empty_ff, full_ff, q_reg)
+ begin
+
+ wr_ptr_nxt = wr_ptr ; //// no change to pointers
+ rd_ptr_nxt = rd_ptr;
+ full_ff_nxt = full_ff;
+ empty_ff_nxt = empty_ff;
+ q_add = 1'b 0;
+ q_sub = 1'b 0;
+ ////---------- check if fifo is full during a write attempt, after a write increment counter
+ ////----------------------------------------------------
+ if(wr_en == 1'b 1 & rd_en == 1'b 0)
+ begin
+ if(full_ff == 1'b 0)
+ begin
+ if(wr_ptr < BUFF_L-1)
+ begin
+ q_add = 1'b 1;
+ wr_ptr_nxt = wr_ptr + 1;
+ empty_ff_nxt = 1'b 0;
+ end
+ else
+ begin
+ wr_ptr_nxt = {(ADDR_W-1){1'b 0}};
+ empty_ff_nxt = 1'b 0;
+ end
+ //// check if fifo is full
+ if( (wr_ptr+1 == rd_ptr) || ((wr_ptr == BUFF_L-1) && (rd_ptr == 1'b 0)))
+ full_ff_nxt = 1'b 1;
+ end
+ end
+
+ ////---------- check to see if fifo is empty during a read attempt, after a read decrement counter
+ ////---------------------------------------------------------------
+ if( (wr_en == 1'b 0) && (rd_en == 1'b 1))
+ begin
+ if(empty_ff == 1'b 0)
+ begin
+ if(rd_ptr < BUFF_L-1 )
+ begin
+ if(q_reg > 0)
+ q_sub = 1'b 1;
+ else
+ q_sub = 1'b 0;
+ rd_ptr_nxt = rd_ptr + 1;
+ full_ff_nxt = 1'b 0;
+ end
+ else
+ begin
+ rd_ptr_nxt = {(ADDR_W-1){1'b 0}};
+ full_ff_nxt = 1'b 0;
+ end
+
+ //// check if fifo is empty
+ if( (rd_ptr + 1 == wr_ptr) || ((rd_ptr == BUFF_L -1) && (wr_ptr == 1'b 0 )))
+ empty_ff_nxt = 1'b 1;
+ end
+ end
+
+ //// -----------------------------------------------------------------
+ if( (wr_en == 1'b 1) && (rd_en == 1'b 1))
+ begin
+ if(wr_ptr < BUFF_L -1)
+ wr_ptr_nxt = wr_ptr + 1;
+ else
+ wr_ptr_nxt = {(ADDR_W-1){1'b 0}};
+
+ if(rd_ptr < BUFF_L -1)
+ rd_ptr_nxt = rd_ptr + 1;
+ else
+ rd_ptr_nxt = {(ADDR_W-1){1'b 0}};
+ end
+
+ end // end of always
+
+
+//// Control for memory array writing and reading
+//// ----------------------------------------------------------------------
+ always @ (posedge clk)
+ begin : mem_cont
+ if( n_reset == 1'b 0)
+ begin
+ mem_array[rd_ptr] <= {(DATA_W-1){1'b 0}};
+ data_out <= {(DATA_W-1){1'b 0}};
+ err <= 1'b 0;
+ end
+ else
+ begin
+ //// if write enable and not full then latch in data and increment wright pointer
+ if( (wr_en == 1'b 1) && (full_ff == 1'b 0) )
+ begin
+ mem_array[wr_ptr] <= data_in;
+ err <= 1'b 0;
+ end
+ else if( (wr_en == 1'b 1) && (full_ff == 1'b 1)) //// check if full and trying to write
+ err <= 1'b 1;
+
+ //// if read enable and fifo not empty then latch data out and increment read pointer
+ if( (rd_en == 1'b 1) && (empty_ff == 1'b 0))
+ begin
+ data_out <= mem_array[rd_ptr];
+ err <= 1'b 0;
+ end
+ else if( (rd_en == 1'b 1) && (empty_ff == 1'b 1))
+ err <= 1'b 1;
+
+ end // end else
+ end // end always
+
+
+//// Combo Counter with Control Flags
+//// ------------------------------------------------------------------------------------------------
+ always @ ( q_sub, q_add, q_reg)
+ begin : Counter
+ case( {q_sub , q_add} )
+ 2'b 01 :
+ q_nxt = q_reg + 1;
+ 2'b 10 :
+ q_nxt = q_reg - 1;
+ default :
+ q_nxt = q_reg;
+ endcase
+ end // end of always
+
+//// Connect internal regs to ouput ports
+//// ------------------------------------------------------------------------------------------------
+ always @ (full_ff, empty_ff, almst_e_ff, almst_f_ff, q_reg)
+ begin
+ full = full_ff;
+ empty = empty_ff;
+ almst_empty = almst_e_ff;
+ almst_full = almst_f_ff;
+ data_count = q_reg;
+ end
+
+endmodule
+