// ---------------------------------------------------------------------- // Copyright (c) 2015, The Regents of the University of California All // rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following // disclaimer in the documentation and/or other materials provided // with the distribution. // // * Neither the name of The Regents of the University of California // nor the names of its contributors may be used to endorse or // promote products derived from this software without specific // prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL REGENTS OF THE // UNIVERSITY OF CALIFORNIA BE LIABLE FOR ANY DIRECT, INDIRECT, // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS // OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR // TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH // DAMAGE. // ---------------------------------------------------------------------- //---------------------------------------------------------------------------- // Filename: sync_fifo.v // Version: 1.00.a // Verilog Standard: Verilog-2001 // Description: A synchronous capable parameterized FIFO. As with all // traditional FIFOs, the RD_DATA will be valid one cycle following a RD_EN // assertion. EMPTY will remain low until the cycle following the last RD_EN // assertion. Note, that EMPTY may actually be high on the same cycle that // RD_DATA contains valid data. // Author: Matt Jacobsen // History: @mattj: Version 2.0 //----------------------------------------------------------------------------- `timescale 1ns/1ns module sync_fifo #( parameter C_WIDTH = 32, // Data bus width parameter C_DEPTH = 1024, // Depth of the FIFO parameter C_PROVIDE_COUNT = 0, // Include code for counts // Local parameters parameter C_REAL_DEPTH = 2**clog2(C_DEPTH), parameter C_DEPTH_BITS = clog2s(C_REAL_DEPTH), parameter C_DEPTH_P1_BITS = clog2s(C_REAL_DEPTH+1) ) ( input CLK, // Clock input RST, // Sync reset, active high input [C_WIDTH-1:0] WR_DATA, // Write data input input WR_EN, // Write enable, high active output [C_WIDTH-1:0] RD_DATA, // Read data output input RD_EN, // Read enable, high active output FULL, // Full condition output EMPTY, // Empty condition output [C_DEPTH_P1_BITS-1:0] COUNT // Data count ); `include "functions.vh" reg [C_DEPTH_BITS:0] rWrPtr=0, _rWrPtr=0; reg [C_DEPTH_BITS:0] rWrPtrPlus1=1, _rWrPtrPlus1=1; reg [C_DEPTH_BITS:0] rRdPtr=0, _rRdPtr=0; reg [C_DEPTH_BITS:0] rRdPtrPlus1=1, _rRdPtrPlus1=1; reg rFull=0, _rFull=0; reg rEmpty=1, _rEmpty=1; // Memory block (synthesis attributes applied to this module will // determine the memory option). ram_1clk_1w_1r #(.C_RAM_WIDTH(C_WIDTH), .C_RAM_DEPTH(C_REAL_DEPTH)) mem ( .CLK(CLK), .ADDRA(rWrPtr[C_DEPTH_BITS-1:0]), .WEA(WR_EN & !rFull), .DINA(WR_DATA), .ADDRB(rRdPtr[C_DEPTH_BITS-1:0]), .DOUTB(RD_DATA) ); // Write pointer logic. always @ (posedge CLK) begin if (RST) begin rWrPtr <= #1 0; rWrPtrPlus1 <= #1 1; end else begin rWrPtr <= #1 _rWrPtr; rWrPtrPlus1 <= #1 _rWrPtrPlus1; end end always @ (*) begin if (WR_EN & !rFull) begin _rWrPtr = rWrPtrPlus1; _rWrPtrPlus1 = rWrPtrPlus1 + 1'd1; end else begin _rWrPtr = rWrPtr; _rWrPtrPlus1 = rWrPtrPlus1; end end // Read pointer logic. always @ (posedge CLK) begin if (RST) begin rRdPtr <= #1 0; rRdPtrPlus1 <= #1 1; end else begin rRdPtr <= #1 _rRdPtr; rRdPtrPlus1 <= #1 _rRdPtrPlus1; end end always @ (*) begin if (RD_EN & !rEmpty) begin _rRdPtr = rRdPtrPlus1; _rRdPtrPlus1 = rRdPtrPlus1 + 1'd1; end else begin _rRdPtr = rRdPtr; _rRdPtrPlus1 = rRdPtrPlus1; end end // Calculate empty assign EMPTY = rEmpty; always @ (posedge CLK) begin rEmpty <= #1 (RST ? 1'd1 : _rEmpty); end always @ (*) begin _rEmpty = (rWrPtr == rRdPtr) || (RD_EN && !rEmpty && (rWrPtr == rRdPtrPlus1)); end // Calculate full assign FULL = rFull; always @ (posedge CLK) begin rFull <= #1 (RST ? 1'd0 : _rFull); end always @ (*) begin _rFull = ((rWrPtr[C_DEPTH_BITS-1:0] == rRdPtr[C_DEPTH_BITS-1:0]) && (rWrPtr[C_DEPTH_BITS] != rRdPtr[C_DEPTH_BITS])) || (WR_EN && (rWrPtrPlus1[C_DEPTH_BITS-1:0] == rRdPtr[C_DEPTH_BITS-1:0]) && (rWrPtrPlus1[C_DEPTH_BITS] != rRdPtr[C_DEPTH_BITS])); end generate if (C_PROVIDE_COUNT) begin: provide_count reg [C_DEPTH_BITS:0] rCount=0, _rCount=0; assign COUNT = (rFull ? C_REAL_DEPTH[C_DEPTH_P1_BITS-1:0] : rCount); // Calculate read count always @ (posedge CLK) begin if (RST) rCount <= #1 0; else rCount <= #1 _rCount; end always @ (*) begin _rCount = (rWrPtr - rRdPtr); end end else begin: provide_no_count assign COUNT = 0; end endgenerate endmodule