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 +