[Design Application]
Embedded RAM In FPGAs Enables FIFO Applications
Creating A FIFO Memory Solves The Problem Of An Asynchronous Boundary Between Clocks.
The asynchronous boundary between system clocks presents one of the most challenging issues in digital design. A solution to this problem is to use an off-the-shelf FIFO memory. But even though they're a relatively direct answer to a difficult problem, FIFOs themselves can be challenging to implement.
For example, a random pixel pattern on the left vertical column of a cathode-ray-tube (CRT) display is probably the result of a FIFO protocol system bug. This is caused by the fact that some FIFOs deliver data one cycle later than the NOT_EMPTY flag assertion, which signals data available. This protocol may be fortuitous to a semiconductor vendor's data-sheet specs, or be convenient for an IP-core vendor's HDL code. But it can cause grief with a designer's state-machine interface to a FIFO.
Engineers can take control of such issues by creating their own FIFO design, using embedded dual-port RAMs in FPGAs. The dual-port feature is crucial for isolating the write side of the RAM from the read side, both architecturally and in time. Dual-port, as the name implies, means the RAM separates both address and data from write and read operations. Any word in the RAM can be written simultaneously with the read operation of any other word. Simultaneous write and read of the same word, of course, must be avoided.
Designers can configure the width and depth of a FIFO memory to exactly fit an application. Does a communications application require 9-, 18-, 36-, or whatever number bit words to match unique requirements, like parity or error correction? If so, embedded RAMs provide a variety of configurations, such as 512 by 2; 256 by 4; 128 by 9; and 64 by 18. If an application requires unique flags beyond FULL and EMPTY, like HALF_FULL, ALMOST_FULL, or FULL_MINUS_7, the designer can easily customize an IP-core-generated FIFO by editing the HDL code to fit specific needs.
The basic synchronous FIFO design uses dual-port RAM for independent PUSH and POP operations with a common clock. Write data is pushed in the clock period that PUSH is asserted. Read data is popped in the clock period that POP is asserted. The FIFO can be cascaded by connecting the NOT_EMPTY line to PUSH and NOT_FULL to POP of adjacent FIFOs. Custom flags such as FULL_MINUS_7 can be added, simply by adding a comparator and a write-side counter initialized to seven.
When the FIFO isn't FULL and PUSH indicates that write data is present, data will be pushed into the write side of the dual-port RAM at the write address pointer, while incrementing the pointer. When the write pointer catches up with the read pointer, the FULL flag is set. It remains so until POP is asserted.
When the FIFO isn't EMPTY and POP indicates that read data is requested, data will be popped from the read side of the dual-port RAM at the read address pointer while incrementing the pointer. When the read pointer catches up with the write pointer, the EMPTY flag is set and remains set until PUSH is asserted.
This synchronous FIFO can be modified for asynchronous operation. First, separate the single clock into write- and read-side clocks: WCLK and RCLK (Fig. 1). Next, the hold conditions for FULL and EMPTY must be equated to compare the write and read pointers for equality. When these pointers are equal, FULL and EMPTY must stay set (if either were set). Using NOT_POP to hold FULL or NOT_PUSH to hold EMPTY, as in the synchronous design, will not work across the asynchronous boundary.
Since the write-side and read-side state-machine dependencies are purely combinatorial, the MTBF of the asynchronous FIFO is identically equal to the metastable characteristic of a single master-slave flip-flop. Occasional FULL and EMPTY conditions will assert and fall back according to the flip-flop metastable characteristics. The false assertions that occur due to binary rollover decode spikes can be reduced by using Grey-code counters. Even though the Grey-code sequence allows only 1-bit transitions, there still will be occasional metastable events. But these will occur at the minimum rate.
The strategy employed in this FIFO design maximizes MTBF. It isolates the write and read state machines as two separate synchronous systems that communicate over the "asynchronous boundary" with the minimum number of combinatorial signals. A description of the write and read state machines follows.
When the FIFO memory isn't FULL and PUSH indicates that write data is present, data will be pushed into the write side of the dual-port RAM at the write address pointer, while incrementing the pointer. When the write pointer catches up with the read pointer, the FULL flag is set and remains set as long as the read and write addresses are equal.
When the FIFO isn't EMPTY and POP indicates that read data is requested, data will be popped from the read-side of the dual-port RAM at the read address pointer while incrementing the pointer. When the read pointer catches up with the write pointer, the EMPTY flag is set and remains set as long as the read and write addresses are equal.
The write-side and read-side state machines can be modeled as a dual synchronizer. This synchronizer is the key to maximizing MTBF by raising slack time at high clock frequencies. This relationship requires a review of some metastability basics.