Вы находитесь на странице: 1из 28

ABSTRACT

An improved technique for fifo design is to perform asynchronous


comparisons between the fifo write and read pointers that are generated in clock
domains and asynchronous to each other. The asynchronous fifo pointer
comparison technique uses fewer synchronization flip-flops to build the fifo.
This method requires additional techniques to correctly synthesize and analyze
the design, which are detailed in this paper. To increase the speed of the fifo,
this design uses combined binary/Gray counters that take advantage of the builtin binary ripple carry logic. This fifo design is used to implement the AMBA
AHB Compliant Memory Controller. This means, Advanced Microcontroller
Bus Architecture compliant Microcontroller .The MC is designed for system
memory control with the main memory consisting of SRAM and ROM.

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

are synchronized into the opposite clock domain before generating


synchronous fifo full or empty status signals. An interesting and different
approach to fifo full and empty generation is to do an asynchronous
comparison of the pointers and then asynchronously set the full or empty
status bits.

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:

FIGURE:FIFO partitioning with asynchronous pointer comparison


logic

1.3Asynchronous FIFO pointers:


In order to understand fifo design, one needs to understand how the fifo pointers
work. There are mainly two pointers.

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.

1.4Gray Code Counter:


One Gray code counter style uses a single set of flip-flops as the Gray code
register with accompanyingGray-to binary conversion, binary increment, and
binary-to-Gray conversion. A second Gray code counter style, the one described
in this paper, uses two sets of registers, one a binary counter and a second to
capture a binary to-Gray converted value. The intent of this Gray code counter
is to utilize the binary carry structure, simplify the Gray-to-binary conversion;
reduce combinational logic, and increase the upper frequency limit of the Gray
code counter. The binary counter conditionally increments the binary value,
which is passed to both the inputs of the binary counter as the next-binary-count
value, and is also passed to the simple binary-to-Gray conversion logic,
consisting of one 2-input XOR gate per bit position. The converted binary value
is the next Gray-count value and drives the Gray code register inputs.
FIGURE:Dual n-bit Gray code counter style

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

combinational logic frequently

translates into significant

improvements in speed. The ptroutput of the block diagram is an n-bit Gray


code pointer.
The binary-value incremental is conditioned with either an if not full or if
not empty test as shown isto insure that the appropriate fifo pointer will not
increment during fifo-full or fifo-empty conditions that could lead to overflow
or underflow of the fifo buffer .If the logic block that sends data to the fifo
reliably stops sending data when a fifo full condition is asserted, the fifo design
might be streamlined by removing the full-testing logic from the fifo write
pointer. The fifo pointer itself does not protect the fifo buffer from being
overwritten, but additional conditioning logic could be added to the fifo
memory buffer to insure that a write_ enable signal could not be activated
during a fifo full condition .An additional sticky status bit, either ovf
(overflow) or unf (underflow), could be added to the pointer design to indicate
that an additional fifo write operation occurred during full or an additional fifo
read operation occurred during empty to indicate error conditions that could
only be cleared during reset. A safe, general purpose fifo design will include the
6

above safeguards at the expense of a slightly larger and perhaps slower


implementation. This is a good idea since a future co-worker might try to copy
and reuse the code in another design without understanding all of the important
details that were considered for the current design.

1.4Use of Gray Counter:


A common approach to fifo counter-pointers, is to use Gray code counters. Gray
codes only allow one bit to change for each clock transition, eliminating the
problem associated with trying to synchronize multiple changing signals on the
same clock edge .The first fact to remember about a Gray code is that the code
distance between any two adjacent words is just 1 (only one bit can change from
one Gray count to the next). The second fact to remember about a Gray code
counter is that most useful Gray code counters must have power-of-2 counts in
the sequence. It is possible to make a Gray code counter that counts an even
number of sequences but conversions to and from these sequences is generally
not as simple to do as the standard Gray code. Also note that there are no oddcount-length Gray code sequences so one cannot make a 23-deep Gray code.

CHAPTER-2
FULL AND EMPTY DETECTION

2.1Full & Empty Detection:


As with any fifo design, correct implementation of full and empty is the most
difficult part of the design.
There are two problems with the generation of full and empty:
First, both full and empty are indicated by the fact that the read and write
pointers are identical. Therefore, something else has to distinguish between full
and empty. One known solution to this problem appends an extra bit to both
pointers and then compares the extra bit for equality (for FIFO empty) or
inequality (for FIFO full), along with equality of the other read and write
pointer bits.
Another solution, the one described is that divides the address space into four
quadrants and decodes the two MSBs of the two counters to determine whether

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.

FIGURE:FIFO direction quadrant detection circuitry


When the fifo is reset the directionlatch is also cleared to indicate that the fifo
is going empty (actually, it is empty when both pointers are reset). Setting and
10

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.

fifo2.v:this is the top-level wrapper-module that includes all clock domains.


The top module is only used as a wrapper to instantiate all of the
otherfifomodules used in the design. If this fifo is used as part of a larger ASIC
or FPGA design, this top-level wrapper would probably be discarded to permit
grouping of the other fifo modules into their respective clock domains for
improved synthesis and static timing analysis.

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.

rptr_empty.v:this module is mostly synchronous to the read-clock domain


and contains the FIFO read pointer and empty-flag logic. Assertion of the
11

aempty_n signal (an input to this module) is synchronous to the rclk-domain,


since aempty_n can only be asserted when the rptrincremented, but de-assertion
of the aempty_n signal happens when the wptr increments, which is
asynchronous to rclk.

wptr_full.v:this module is mostly synchronous to the write-clock domain and


contains the FIFO write pointer and full-flag logic. Assertion of the
afull_nsignal (an input to this module) is synchronous to the wclk-domain, since
afull_ncan only be asserted when the wptrincremented (and wrst_n), but deassertion of the afull_nsignal happens when the rptrincrements, which is
asynchronous to wclk.

2.2

Asynchronous generation of full and empty

In the async_cmp shown is aempty_n and afull_n are the asynchronously


decoded signals. The aempty_n signal is asserted on the rising edge of an rclk,
but is de-asserted on the rising edge of a wclk. Similarly, the afull_n signal is
asserted on a wclk and removed on an rclk. The empty signal will be used to
stop the next read operation, and the leading edge of aempty_n is properly
synchronous with the read clock, but the railing edge needs to be synchronized
to the read clock. This is done in a two-stage synchronizer that generates
r _empty. The w_full signal is generated in the symmetrically equivalent way.

12

FIGURE:Asynchronous pointer comparison to assert full and empty

2.3Resetting the FIFO:


The first FIFO event of interest takes place on a fifo-reset operation. When the
fifo is reset, four important things happen within the async_cmp module and
accompanying full and empty synchronizers of the wptr_full and rptr_empty
modules (the connections between the async_cmp, wptr_full and rptr_empty
modules are shown .
1. The reset signal directly clears the wfullflag. The remptyflag is not cleared by
a reset.
2. The reset signal clears both fifo pointers, so the pointer comparator asserts
that the pointers are equal.
3. The reset clears the directionbit.
4. With the pointers equal and the directionbit cleared, the aempty_n bit is
asserted, which presets the remptyflag.

13

CHAPTER-3
FIFO-WRITES & FIFO FULL
AND
FIFO-READS & FIFO EMPTY

14

3.1 FIFO-writes & FIFO full:


The second fifo operational event of interest takes place when a fifo-write
operation takes place and the wptris incremented. At this point, the fifo pointers
are no longer equal so the aempty_n signal is de-asserted, releasing the preset
control of the remptyflip-flops. After two rising edges on rclk, the fifo will deassert the remptysignal. Because the de-assertion of aempty_n happens on a
rising wclkand because the remptysignal is clocked by the rclk, the two-flip-flop
synchronizer as shown in Figure 8 is required to removementastability that
could be generated by the first remptyflip-flop. The second fifo operational
event of interest takes place when the wptrincrements into the next Gray code
quadrant beyond the rptr. The direction bit iscleared (but it was already clear).

FIGURE:async_cmp module connection to rptr_empty and wptr_full


modules
The third fifo operational event of interest occurs when the wptris within one
quadrant of catching up to therptras described. When this happens, the bit of is
asserted low, which sets the directionbit high. This means that the directionbit is
15

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.

FIGURE:Asynchronous empty and full generation


During operation, wfullis generated synchronous to the write clock, in a similar
way that remptyis generated synchronous to the read clock. The afull_nsignal is
asserted as a result of a write clock, and the leading (falling) edge is thus
naturally synchronous to the write clock. The trailing (rising) edge is, however
caused by the read clock, and must, therefore be synchronized to the write
clock. The same timing issues related to the setting of the full flag also apply to
the setting of the empty flag

16

3.2 FIFO-reads & FIFO empty:


when the rptr increments into the next Gray code quadrant beyond the wptr. The
direction bit is again set (but it was already set).when the rptr is within one
quadrant of catching up to the wptr. At this instant, the dirrst bit is asserted high,
which clears the direction bit. This means that the direction bit is cleared long
before the fifo is empty and is not timing critical to assertion of the aempty_n
signal. When the rptr catches up to the wptr (and the direction bit is zero). The
aempty_n signal presets the rempty flip-flops. The aempty_n signal is asserted
on afifo-read operation and is synchronous to the rising edge of the rclk.
therefore, asserting empty is synchronous to the rclk.Finally, when a fifo-write
operation takes place and the wptr is incremented. At this point, the fifopointers
are no longer equal so the aempty_n signal is de-asserted, releasing the preset
control of the remptyflip-flops. After two rising edges on rclk, the fifo will deassert the rempty signal. Because the de-assertion ofaempty_n happens on a
rising wclk and because the rempty signal is clocked by the rclk, the two-flipflopsynchronizer.

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

always @ (posedge RClk)


if (R_en & ! Empty_out) begin
Data_out <= Memory[r_addr];
r_ack<=1'b1;
end
else
r_ack<=1'b0;

always @ (posedge WClk)


if (W_en & ! Full_out) begin
Memory[w_addr] <= Data_in;
w_ack<=1'b1;
end
else
w_ack<=1'b0;
assign Nw_En = W_en & ~Full_out;
assign Nr_En = R_en & ~Empty_out;
//Addreses (Gray counters) logic:
GrayCounterGrayCounter_pWr(.GrayCount_out(w_addr),.Enable_in(Nw_En),.
Clear_in(Clear),.Clk(WClk));
GrayCounterGrayCounter_pRd(.GrayCount_out(r_addr),.Enable_in(Nr_En),.Cl
ear_in(Clear),.Clk(RClk));
assign E_addr = (w_addr == r_addr);
assign Set = (w_addr[ADDRESS_WIDTH-2] ~^ r_addr[ADDRESS_WIDTH1]) & (w_addr[ADDRESS_WIDTH-1] ^ r_addr[ADDRESS_WIDTH-2]);
assign Rst = (w_addr[ADDRESS_WIDTH-2] ^ r_addr[ADDRESS_WIDTH1]) & (w_addr[ADDRESS_WIDTH-1] ~^ r_addr[ADDRESS_WIDTH-2]);
always @ (Set,Rst,Clear)
if (Rst|Clear)
Status = 0; //Going 'Empty'.
elseif(Set)
Status = 1; //Going 'Full'.

19

assign isFull = Status & E_addr; //'Full' Fifo.

always @ (posedge WClk, posedge isFull)


if (isFull)
Full_out <= 1;
else
Full_out <= 0;
assign isEmpty = ~Status & E_addr;
always @ (posedge RClk, posedge isEmpty)
if (isEmpty)
Empty_out <= 1;
else
Empty_out <= 0;
endmodule

//=======================================
// 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;

always @ (posedge Clk)


if (Clear_in) begin
BinaryCount <= {COUNTER_WIDTH{1'b 0}} + 1'b1;
{GrayCount_out }<= {COUNTER_WIDTH{1'b 0}};
end
else if (Enable_in) begin
20

BinaryCount <= BinaryCount + 1'b1;


GrayCount_out <= {BinaryCount[COUNTER_WIDTH-1],
BinaryCount[COUNTER_WIDTH-2:0] ^
BinaryCount[COUNTER_WIDTH1:1]};
end
endmodule

TEST BENCH CODE:


timescale 1ns / 1ps
////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 16:51:13 09/16/2014
// Design Name: aFifo
// Module Name:
/home/cdac/Desktop/kiran_asif_3sept/Sept_5/cdac_project/a_fifio_test_2.v
// Project Name: cdac_project
// Target Device:
// Tool versions:
// Description:
//
// Verilog Test Fixture created by ISE for module: aFifo
//
21

// 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

SIMULATION & RESULTS:

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.

Clifford E. Cummings and Peter Alfke, Simulation and Synthesis


Techniques for Asynchronous FIFO Design with Asynchronous Pointer
Comparisons, SNUG 2002 (Synopsys Users Group Conference, San
Jose, CA, 2002) User Papers,March 2002, Section TB2, 3rd paper. Also
available at www.sunburst-design.com/papers.

2.

Designing Asynchronous FIFO BYDadhania Prashant C,Department of


Electronics Engineering,Gujarat Technological University, Gandhinagar,
Gujarat, India.

27

3.

Clifford E. Cummings, Synthesis and Scripting Techniques for


Designing Multi-Asynchronous Clock Designs, SNUG 2001(Synopsys
Users Group Conference, San Jose, CA, 2001) User Papers, March 2001,
Section MC1, 3rd paper.
Also available atwww.sunburst-design.com/papers.

28

Вам также может понравиться