UPGRADE YOUR BROWSER

We have detected your current browser version is not the latest one. Xilinx.com uses the latest web technologies to bring you the best online experience possible. Please upgrade to a Xilinx.com supported browser:Chrome, Firefox, Internet Explorer 11, Safari. Thank you!

cancel
Showing results for 
Search instead for 
Did you mean: 
Adventurer
Adventurer
628 Views
Registered: ‎05-02-2017

Questions on Asynchronous FIFO

1) As in https://github.com/KastnerRG/riffa/blob/master/fpga/riffa_hdl/async_fifo.v#L76-L79 , could anyone advise on the differences in the context of purpose of the parameters ?

 

wire [C_DEPTH_BITS-1:0] wWrPtr;
wire [C_DEPTH_BITS-1:0] wRdPtr;
wire [C_DEPTH_BITS-1:0] wWrPtrP1;
wire [C_DEPTH_BITS-1:0] wRdPtrP1; 

2) For lines 103 and 114 in the same verilog code, what is the semantic difference between EMPTY in async_cmp and RD_EMPTY in rd_ptr_empty ? Both are indirectly related by the signal wCmpEmpty.

 

.EMPTY(wCmpEmpty),

.RD_EMPTY(RD_EMPTY), 

 

// ----------------------------------------------------------------------
// Copyright (c) 2016, 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:			async_fifo.v
// Version:				1.00.a
// Verilog Standard:	Verilog-2001
// Description:			Asynchronous capable parameterized FIFO. As with all
// traditional FIFOs, the RD_DATA will be valid one cycle following a RD_EN 
// assertion. RD_EMPTY will remain low until the cycle following the last RD_EN 
// assertion. Note, that RD_EMPTY may actually be high on the same cycle that 
// RD_DATA contains valid data.
// Author:				Matt Jacobsen
// History:				@mattj: Version 2.0
// Additional Comments: Based on design by CE Cummings in Simulation and 
// Synthesis Techniques for Asynchronous FIFO Design with Asynchronous Pointer 
// Comparisons
//-----------------------------------------------------------------------------
`timescale 1ns/1ns
module async_fifo #(
	parameter C_WIDTH = 32,	// Data bus width
	parameter C_DEPTH = 1024,	// Depth of the FIFO
	// Local parameters
	parameter C_REAL_DEPTH = 2**clog2(C_DEPTH),
	parameter C_DEPTH_BITS = clog2(C_REAL_DEPTH),
	parameter C_DEPTH_P1_BITS = clog2(C_REAL_DEPTH+1)
)
(
	input RD_CLK,							// Read clock
	input RD_RST,							// Read synchronous reset
	input WR_CLK,						 	// Write clock
	input WR_RST,							// Write synchronous reset
	input [C_WIDTH-1:0] WR_DATA, 			// Write data input (WR_CLK)
	input WR_EN, 							// Write enable, high active (WR_CLK)
	output [C_WIDTH-1:0] RD_DATA, 			// Read data output (RD_CLK)
	input RD_EN,							// Read enable, high active (RD_CLK)
	output WR_FULL, 						// Full condition (WR_CLK)
	output RD_EMPTY 						// Empty condition (RD_CLK)
);

`include "functions.vh"

wire						wCmpEmpty;
wire						wCmpFull;
wire	[C_DEPTH_BITS-1:0]	wWrPtr;
wire	[C_DEPTH_BITS-1:0]	wRdPtr;
wire	[C_DEPTH_BITS-1:0]	wWrPtrP1;
wire	[C_DEPTH_BITS-1:0]	wRdPtrP1;


// Memory block (synthesis attributes applied to this module will
// determine the memory option).
ram_2clk_1w_1r #(.C_RAM_WIDTH(C_WIDTH), .C_RAM_DEPTH(C_REAL_DEPTH)) mem (
	.CLKA(WR_CLK),
	.ADDRA(wWrPtr),
	.WEA(WR_EN & !WR_FULL),
	.DINA(WR_DATA),
	.CLKB(RD_CLK),
	.ADDRB(wRdPtr),
	.DOUTB(RD_DATA)
);


// Compare the pointers.
async_cmp #(.C_DEPTH_BITS(C_DEPTH_BITS)) asyncCompare (
	.WR_RST(WR_RST),
	.WR_CLK(WR_CLK),
	.RD_RST(RD_RST),
	.RD_CLK(RD_CLK),
	.RD_VALID(RD_EN & !RD_EMPTY),
	.WR_VALID(WR_EN & !WR_FULL),
	.EMPTY(wCmpEmpty), 
	.FULL(wCmpFull),
	.WR_PTR(wWrPtr), 
	.WR_PTR_P1(wWrPtrP1), 
	.RD_PTR(wRdPtr), 
	.RD_PTR_P1(wRdPtrP1)
);


// Calculate empty
rd_ptr_empty #(.C_DEPTH_BITS(C_DEPTH_BITS)) rdPtrEmpty (
	.RD_EMPTY(RD_EMPTY), 
	.RD_PTR(wRdPtr),
	.RD_PTR_P1(wRdPtrP1),
	.CMP_EMPTY(wCmpEmpty), 
	.RD_EN(RD_EN),
	.RD_CLK(RD_CLK), 
	.RD_RST(RD_RST)
);


// Calculate full
wr_ptr_full #(.C_DEPTH_BITS(C_DEPTH_BITS)) wrPtrFull (
	.WR_CLK(WR_CLK), 
	.WR_RST(WR_RST),
	.WR_EN(WR_EN),
	.WR_FULL(WR_FULL), 
	.WR_PTR(wWrPtr),
	.WR_PTR_P1(wWrPtrP1),
	.CMP_FULL(wCmpFull)
);
 
endmodule


module async_cmp #(
  parameter C_DEPTH_BITS = 4,
  // Local parameters
  parameter N = C_DEPTH_BITS-1
)
(
	input WR_RST,
	input WR_CLK,
	input RD_RST,
	input RD_CLK,
	input RD_VALID,
	input WR_VALID,
	output EMPTY, 
	output FULL, 
	input [C_DEPTH_BITS-1:0] WR_PTR, 
	input [C_DEPTH_BITS-1:0] RD_PTR, 
	input [C_DEPTH_BITS-1:0] WR_PTR_P1, 
	input [C_DEPTH_BITS-1:0] RD_PTR_P1
);
  
reg				rDir=0;
wire			wDirSet = (  (WR_PTR[N]^RD_PTR[N-1]) & ~(WR_PTR[N-1]^RD_PTR[N]));
wire			wDirClr = ((~(WR_PTR[N]^RD_PTR[N-1]) &  (WR_PTR[N-1]^RD_PTR[N])) | WR_RST);

reg				rRdValid=0;
reg				rEmpty=1;
reg				rFull=0;
wire			wATBEmpty = ((WR_PTR == RD_PTR_P1) && (RD_VALID | rRdValid));
wire			wATBFull = ((WR_PTR_P1 == RD_PTR) && WR_VALID);
wire			wEmpty = ((WR_PTR == RD_PTR) && !rDir);
wire			wFull = ((WR_PTR == RD_PTR) && rDir);

assign EMPTY = wATBEmpty || rEmpty;
assign FULL  = wATBFull || rFull;

always @(posedge wDirSet or posedge wDirClr)
if (wDirClr) 
	rDir <= 1'b0;
else
	rDir <= 1'b1;

always @(posedge RD_CLK) begin
	rEmpty <= (RD_RST ? 1'd1 : wEmpty);
	rRdValid <= (RD_RST ? 1'd0 : RD_VALID);
end

always @(posedge WR_CLK) begin
	rFull <= (WR_RST ? 1'd0 : wFull);
end

endmodule 
 
 
module rd_ptr_empty #(
	parameter C_DEPTH_BITS = 4
)
(
	input RD_CLK, 
	input RD_RST,
	input RD_EN, 
	output RD_EMPTY,
	output [C_DEPTH_BITS-1:0] RD_PTR,
	output [C_DEPTH_BITS-1:0] RD_PTR_P1,
	input CMP_EMPTY 
);

reg							rEmpty=1;
reg							rEmpty2=1;
reg		[C_DEPTH_BITS-1:0]	rRdPtr=0;
reg		[C_DEPTH_BITS-1:0]	rRdPtrP1=0;
reg		[C_DEPTH_BITS-1:0]	rBin=0;
reg		[C_DEPTH_BITS-1:0]	rBinP1=1;
wire	[C_DEPTH_BITS-1:0]	wGrayNext;
wire	[C_DEPTH_BITS-1:0]	wGrayNextP1;
wire	[C_DEPTH_BITS-1:0]	wBinNext;
wire	[C_DEPTH_BITS-1:0]	wBinNextP1;

assign RD_EMPTY = rEmpty;
assign RD_PTR = rRdPtr;
assign RD_PTR_P1 = rRdPtrP1;

// Gray coded pointer
always @(posedge RD_CLK or posedge RD_RST) begin
	if (RD_RST) begin
		rBin <= #1 0;
		rBinP1 <= #1 1;
		rRdPtr <= #1 0;
		rRdPtrP1 <= #1 0;
	end
	else begin
		rBin <= #1 wBinNext;
		rBinP1 <= #1 wBinNextP1;
		rRdPtr <= #1 wGrayNext;
		rRdPtrP1 <= #1 wGrayNextP1;
	end
end

// Increment the binary count if not empty
assign wBinNext = (!rEmpty ? rBin + RD_EN : rBin);
assign wBinNextP1 = (!rEmpty ? rBinP1 + RD_EN : rBinP1);
assign wGrayNext = ((wBinNext>>1) ^ wBinNext); // binary-to-gray conversion
assign wGrayNextP1 = ((wBinNextP1>>1) ^ wBinNextP1); // binary-to-gray conversion

always @(posedge RD_CLK) begin
	if (CMP_EMPTY)
		{rEmpty, rEmpty2} <= #1 2'b11;
	else
		{rEmpty, rEmpty2} <= #1 {rEmpty2, CMP_EMPTY};
end

endmodule
 
 
module wr_ptr_full #(
	parameter C_DEPTH_BITS = 4
)
(
	input WR_CLK, 
	input WR_RST,
	input WR_EN,
	output WR_FULL, 
	output [C_DEPTH_BITS-1:0] WR_PTR, 
	output [C_DEPTH_BITS-1:0] WR_PTR_P1, 
	input CMP_FULL
);

reg							rFull=0;
reg							rFull2=0;
reg		[C_DEPTH_BITS-1:0]	rPtr=0;
reg		[C_DEPTH_BITS-1:0]	rPtrP1=0;
reg		[C_DEPTH_BITS-1:0]	rBin=0;
reg		[C_DEPTH_BITS-1:0]	rBinP1=1;
wire	[C_DEPTH_BITS-1:0]	wGrayNext;
wire	[C_DEPTH_BITS-1:0]	wGrayNextP1;
wire	[C_DEPTH_BITS-1:0]	wBinNext;
wire	[C_DEPTH_BITS-1:0]	wBinNextP1;

assign WR_FULL = rFull;
assign WR_PTR = rPtr;
assign WR_PTR_P1 = rPtrP1;

// Gray coded pointer
always @(posedge WR_CLK or posedge WR_RST) begin
	if (WR_RST) begin
		rBin <= #1 0;
		rBinP1 <= #1 1;
		rPtr <= #1 0;
		rPtrP1 <= #1 0;
	end
	else begin
		rBin <= #1 wBinNext;
		rBinP1 <= #1 wBinNextP1;
		rPtr <= #1 wGrayNext;
		rPtrP1 <= #1 wGrayNextP1;
	end
end

// Increment the binary count if not full
assign wBinNext = (!rFull ? rBin + WR_EN : rBin);
assign wBinNextP1 = (!rFull ? rBinP1 + WR_EN : rBinP1);
assign wGrayNext = ((wBinNext>>1) ^ wBinNext); // binary-to-gray conversion
assign wGrayNextP1 = ((wBinNextP1>>1) ^ wBinNextP1); // binary-to-gray conversion

always @(posedge WR_CLK) begin
	if (WR_RST) 
		{rFull, rFull2} <= #1 2'b00;
	else if (CMP_FULL) 
		{rFull, rFull2} <= #1 2'b11;
	else
		{rFull, rFull2} <= #1 {rFull2, CMP_FULL};
end

endmodule

 

3) Besides, does anyone have any clue why 'rCount < 2' as in https://github.com/KastnerRG/riffa/blob/master/fpga/riffa_hdl/async_fifo_fwft.v#L79 ?

 

wire wRen = RD_EN || (rCount < 2'd2); 
// ----------------------------------------------------------------------
// Copyright (c) 2016, 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:			async_fifo_fwft.v
// Version:				1.00.a
// Verilog Standard:	Verilog-2001
// Description:			An asynchronous capable parameterized FIFO. As with all
// first word fall through FIFOs, the RD_DATA will be valid when RD_EMPTY is 
// low. Asserting RD_EN will consume the current RD_DATA value and cause the 
// next value (if it exists) to appear on RD_DATA on the following cycle. Be sure 
// to check if RD_EMPTY is low each cycle to determine if RD_DATA is valid.
// Author:				Matt Jacobsen
// History:				@mattj: Version 2.0
//-----------------------------------------------------------------------------
`timescale 1ns/1ns
module async_fifo_fwft #(
	parameter C_WIDTH = 32,	// Data bus width
	parameter C_DEPTH = 1024,	// Depth of the FIFO
	// 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 RD_CLK,							// Read clock
	input RD_RST,							// Read synchronous reset
	input WR_CLK,						 	// Write clock
	input WR_RST,							// Write synchronous reset
	input [C_WIDTH-1:0] WR_DATA, 			// Write data input (WR_CLK)
	input WR_EN, 							// Write enable, high active (WR_CLK)
	output [C_WIDTH-1:0] RD_DATA, 			// Read data output (RD_CLK)
	input RD_EN,							// Read enable, high active (RD_CLK)
	output WR_FULL, 						// Full condition (WR_CLK)
	output RD_EMPTY 						// Empty condition (RD_CLK)
);

`include "functions.vh"

reg		[C_WIDTH-1:0]			rData=0;
reg		[C_WIDTH-1:0]			rCache=0;
reg		[1:0]					rCount=0;
reg								rFifoDataValid=0;
reg								rDataValid=0;
reg								rCacheValid=0;
wire	[C_WIDTH-1:0]			wData;
wire							wEmpty;
wire							wRen = RD_EN || (rCount < 2'd2);


assign RD_DATA = rData;
assign RD_EMPTY = !rDataValid;


// Wrapped non-FWFT FIFO (synthesis attributes applied to this module will
// determine the memory option).
async_fifo #(.C_WIDTH(C_WIDTH), .C_DEPTH(C_DEPTH)) fifo (
	.WR_CLK(WR_CLK),
	.WR_RST(WR_RST),
	.RD_CLK(RD_CLK),
	.RD_RST(RD_RST),
	.WR_EN(WR_EN),
	.WR_DATA(WR_DATA),
	.WR_FULL(WR_FULL),
	.RD_EN(wRen),
	.RD_DATA(wData),
	.RD_EMPTY(wEmpty)
);

always @ (posedge RD_CLK) begin
	if (RD_RST) begin
		rCount <= #1 0;
		rDataValid <= #1 0;
		rCacheValid <= #1 0;
		rFifoDataValid <= #1 0;
	end
	else begin
		// Keep track of the count
		rCount <= #1 rCount + (wRen & !wEmpty) - (!RD_EMPTY & RD_EN);

		// Signals when wData from FIFO is valid
		rFifoDataValid <= #1 (wRen & !wEmpty);

		// Keep rData up to date
		if (rFifoDataValid) begin
			if (RD_EN | !rDataValid) begin
				rData <= #1 wData;
				rDataValid <= #1 1'd1;
				rCacheValid <= #1 1'd0;
			end
			else begin
				rCacheValid <= #1 1'd1;
			end
			rCache  <= #1 wData;
		end
		else begin
			if (RD_EN | !rDataValid) begin
				rData <= #1 rCache;
				rDataValid <= #1 rCacheValid;
				rCacheValid <= #1 1'd0;
			end
		end
	end
end
 
endmodule

 

0 Kudos
1 Reply
Scholar austin
Scholar
538 Views
Registered: ‎02-27-2008

Re: Questions on Asynchronous FIFO

Xilinx devices already contain hardened FIFO's (BRAM/FIFO),

 

So there is no reason to try to add a 'FIFO' to your design in its raw, ASIC form as you show us.

 

So, no one here is really going to be interested in helping you design ASIC FIFO, as there is really zero need for that in the real world any longer.  Everyone just uses the existing FIFO's in the Xilinx devices.  If you are designing an ASIC (or SoC), most just license what they need from Cadence or ARM.  Why risk designing something and having it not work?

Austin Lesea
Principal Engineer
Xilinx San Jose
0 Kudos