Design of Asynchronous FIFO Using Verilog HDL
Design of Asynchronous FIFO Using Verilog HDL
CHAPTER-1
INTRODUCTION
1.1
INTRODUCTION:
An asynchronous fifo refers to a fifo design where data values are written
sequentially into a fifo buffer using one clock domain, and the data values
are sequentially read from the same fifo buffer using another clock domain,
where the two clock domains are asynchronous to each other. One common
technique for designing an asynchronousfifois to use Gray code pointers that
2
There are many ways to do asynchronous fifo design, including many wrong
ways. Most incorrectly implemented fifo designs still function properly 90%
of the time. Most almost-correct fifo designs function properly 99%+ of the
time. Unfortunately, fifos that work properly 99%+ of the time have design
flaws that are usually the most difficult to detect and debug.
1.2
ARCHITECTURE:
1.
Write Pointer:
The write pointer always points to the next word to be written; therefore, on
reset, both pointers are set to zero, which also happens to be the next fifo word
location to be written. On a fifo-write operation, the memory location that is
pointed to by the write pointer is written, and then the write pointer is
incremented to point to the next location to be written.
2.
Read Pointer:
The read pointer always points to the current fifo word to be read. Again on
reset, both pointers are set to zero, the fifo is empty and the read pointer is
pointing to invalid data (because the fifo is empty and the empty flag is
asserted). As soon as the first data word is written to the fifo, the write pointer
increments, the empty flag is cleared, and the read pointer that is still addressing
the contents of the first fifo memory word, immediately drives that first valid
word onto the fifo data output port, to be read by the receiver logic. The fact
that the read pointer is always pointing to the next fifo word to be read means
that the receiver logic does not have to use two clock periods to read the data
word.
This implementation requires twice the number of flip-flops, but reduces the
combinatorial logic and can operate at a higher frequency. In FPGA designs,
availability of extra flip-flops is rarely a problem since FPGAs typically contain
far more flip-flops than any design will ever use. In FPGA designs, reducing the
amount of
CHAPTER-2
FULL AND EMPTY DETECTION
the fifo was going full or going empty at the time the two pointers became
equal.
FIGURE:FIFO is going empty because the rptr trails the wptr by one
quadrant
fifo is going full because the wptr trails the rptr by one quadrant If the write
pointer is one quadrantbehind the read pointer, this indicates a "possibly going
full" situation as shown. When this conditionoccurs, the direction latch is set.
FIGURE:FIFO is going full because the wptr trails the rptr by one
quadrant
If the write pointer is one quadrant ahead of the read pointer, this indicates a
"possibly going empty" situation as shown. When this condition occurs, the
directionlatch is cleared.
resetting the direction latch is not timing-critical, and the direction latch
eliminates the ambiguity of the address identity decoder. The Xilinx FPGA logic
to implement the decoding of the two wptrMSBs and the two rptrMSBs is easily
implemented as two 4-input look-up tables. The second, and more difficult,
problem stems from the asynchronous nature of the write and read clocks.
Comparing two counters that are clocked asynchronously can lead to unreliable
decoding spikes when either or both counters change multiple bits more or less
simultaneously. The solution described in this paper uses a Gray count
sequence, where only one bit changes from any count to the next. Any decoder
or comparator will then switch only from one valid output to the next one, with
no danger of spurious decoding glitches.
fifomem.v:this is the fifo memory buffer that is accessed by both the write
and read clock domains. This buffer is most likely an instantiated, synchronous
dual-port RAM. Other memory styles can be adapted to function as the fifo
buffer.
async_cmp.v:this is an asynchronous pointer-comparison module that is
used to generate signals that control assertion of the asynchronous full and
empty status bits. This module only contains combinational comparison logic.
No sequential logic is included in this module.
2.2
12
13
CHAPTER-3
FIFO-WRITES & FIFO FULL
AND
FIFO-READS & FIFO EMPTY
14
set long before the fifo is full and is not timing-critical to assertion of the
afull_nsignal. The fourth fifo operational event of interest is when the
wptrcatches up to the rptr(and the directionbit is set). When this happens, the
afull_nsignal presets the wfullflip-flops. The afull_nsignal is asserted on a fifowrite operation and is synchronous to the rising edge of the wclk; therefore,
asserting full is synchronous to the wclk. The fifth fifo operational event of
interest is when a fifo-read operation takes place and the rptris incremented. At
this point, the fifo pointers are no longer equal so the afull_nsignal is deasserted, releasing the preset control of the wfullflip-flops. After two rising
edges on wclk, the fifo will de-assert the wfull signal. Because the de-assertion
of afull_nhappens on a rising rclkand because the wfullsignal is clocked by the
wclk, the two-flip-flop synchronizer, shown in Figure 8, is required to remove
metastability that could be generated by the first wfullflip-flop capturing the
inverted and asynchronously generated afull_ndata input.
16
APPENDIX
RTL CODE:
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
17
// Engineer:
//
// Create Date: 12:54:12 09/16/2014
// Design Name:
// Module Name: as_fif0_1
// Project Name:
// Target Devices:
// Tool versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module aFifo
#(parameter
DATA_WIDTH = 8,
ADDRESS_WIDTH = 3,
FIFO_DEPTH = (1 << ADDRESS_WIDTH))
( output reg [DATA_WIDTH-1:0]
Data_out,
output reg
Empty_out,
input wire
R_en,
input wire
RClk,
input wire [DATA_WIDTH-1:0]
Data_in,
output reg
Full_out,w_ack,r_ack,
input wire
W_en,
input wire
WClk,
input wire
Clear);
reg [DATA_WIDTH-1:0]
Memory[FIFO_DEPTH-1:0];
wire [ADDRESS_WIDTH-1:0]
w_addr, r_addr;
wire
E_addr;
wire
Nw_En, Nr_En;
wire
Set, Rst;
reg
Status;
wire
isFull, isEmpty;
wire
cr,cw;
18
19
//=======================================
// Gray Code counter.
//=======================================
module GrayCounter
#(parameter COUNTER_WIDTH = 3)
(output reg [COUNTER_WIDTH-1:0]
input wire
Enable_in,
input wire
Clear_in,
input wire
reg
GrayCount_out,
Clk);
[COUNTER_WIDTH-1:0]
BinaryCount;
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
////////////////////////////////////////////////////////////////////////////////
module a_fifio_test_2;
// Inputs
reg R_en;
reg RClk;
reg [7:0] Data_in;
reg W_en;
reg WClk;
reg Clear;
// Outputs
wire [7:0] Data_out;
wire Empty_out;
wire Full_out;
wire w_ack;
wire r_ack;
// Instantiate the Unit Under Test (UUT)
aFifouut (
.Data_out(Data_out),
.Empty_out(Empty_out),
.R_en(R_en),
.RClk(RClk),
.Data_in(Data_in),
.Full_out(Full_out),
.w_ack(w_ack),
.r_ack(r_ack),
.W_en(W_en),
.WClk(WClk),
.Clear(Clear)
);
initial forever #20 RClk=~RClk;
initial forever #40 WClk=~WClk;
initial begin
@(negedge WClk ) Clear=~Clear;
@(negedge WClk) Clear=~Clear;
22
end
initial begin
// Initialize Inputs
R_en = 0;
RClk = 0;
Data_in = 0;
W_en = 0;
WClk = 0;
Clear = 0;
// Wait 100 ns for global reset to finish
#40
#40{W_en,R_en,Data_in}=10'b1000000000;
#40{W_en,R_en,Data_in}=10'b1010111101;
#40{W_en,R_en,Data_in}=10'b1010101111;
#40{W_en,R_en,Data_in}=10'b0101101101;
#40{W_en,R_en,Data_in}=10'b0111101101;
#40{W_en,R_en,Data_in}=10'b0111101101;
#40{W_en,R_en,Data_in}=10'b1001101101;
#40{W_en,R_en,Data_in}=10'b1010000000;
#40{W_en,R_en,Data_in}=10'b1010111101;
#40{W_en,R_en,Data_in}=10'b1011101111;
#40{W_en,R_en,Data_in}=10'b1001101101;
#40{W_en,R_en,Data_in}=10'b1011101101;
#40{W_en,R_en,Data_in}=10'b1011101101;
#40{W_en,R_en,Data_in}=10'b1001101101;
#40{W_en,R_en,Data_in}=10'b1000111000;
#40{W_en,R_en,Data_in}=10'b1000111101;
#40{W_en,R_en,Data_in}=10'b1001101111;
#40{W_en,R_en,Data_in}=10'b1001101101;
#40{W_en,R_en,Data_in}=10'b1011101101;
#40{W_en,R_en,Data_in}=10'b1010111101;
#40{W_en,R_en,Data_in}=10'b1011101111;
#40{W_en,R_en,Data_in}=10'b1001101101;
#40{W_en,R_en,Data_in}=10'b1011101101;
// Add stimulus here
end
endmodule
23
24
25
CONCLUSION:
Asynchronous Fifo design requires careful attention to details from pointer
generation techniques to full and emptygeneration. Ignorance of important
details will generally result in a design that is easily verified but is also wrong.
finding fifo design errors typically requires simulation of a gate-level fifo
design with backannotation of actual delays and a whole lot of luck!
Synchronization of fifo pointers into the opposite clock domain is safely
accomplished using Gray code pointers Synchronization of fifo pointers into the
opposite clock domain is safely accomplished using Gray code pointers
.Generating the fifo -full status is perhaps the hardest part of a fifo design. Dual
n-bit Gray code counters are valuable to synchronize and n-bit pointer into the
opposite clock domain and to use an (n-1)-bit pointer to do full comparison.
Synchronizing binary fifo pointers using techniques described is another worthy
26
technique to use when doing fifo design .Generating the fifo -empty status is
easily accomplished by comparing-equal the n-bit read pointer to the
synchronized n-bit write pointer. The techniques described in this paper should
work with asynchronous clocks spanning small to large differences.
REFERENCES:
1.
2.
27
3.
28