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
+