## CDC considerations to transfer a pulse

Transfer a pulse from slow to fast clock domain, and from fast to slow clock domain, require separate handling.

Generally speaking, passing a signal from slow clock to fast clock is not a problem, since the loss of a pulse is less likely to happen. Based on Nyquist Theorem, if receiving clock frequency is at least 2x of sending clock frequency, then there will be no sampling loss.

## Design an SRAM based Asynchronous FIFO

The most straightforward way is to have a 2-port SRAM as the memory storage, in which each port can operate under different clocks.

Another way is to take advantage of SRAM based synchronous FIFO. See diagram below.

## Design an asynchronous FIFO with non-power-of-2 even number of entries

Designing a power-of-2-entry async FIFO is straightforward, but how about designing an async FIFO with non-power-of-2 but even number of entries, for example, 6?

The only difficult part is non power of 2 number gray encoding. For power of 2 number is pretty straightforward. Let’s take 8 for example, the gray code can be:

000 -> 001 -> 011 -> 010 -> 110 -> 111 -> 101 -> 100

Notice that it’s mirror symmetric. To get gray encoding for 6, we can take the middle 2 encoding out of the sequence:

000 -> 001 -> 011 -> 111 -> 101 -> 100

It still satisfies gray encoding. Done!

## Design Single-Port SRAM Based Synchronous FIFO

If you’re familiar with SRAM structure, for the same amount storage, dual-port SRAM takes more area than single-port SRAM, since each dual-port SRAM row needs 2 word lines. If we were to use single-port SRAM as FIFO memory storage, the area can be further reduced.

## Design a Dual-Port SRAM Based Synchronous FIFO

If the number of sync FIFO entries is too large, flop based FIFO may take too much area and may have issues closing timing, making it impractical in real design. The most straightforward way to solve this is to replace the memory array with dual-port SRAM.

## Design a non-power-of-2 Synchronous FIFO

If the sync FIFO has non-power-of-2 entries, for example, 3 entries, what can we do? Well, we have at least 2 approaches.

The easiest way is to maintain a counter for FIFO occupied entries, and use it to generate the FIFO empty or full condition.

The second approach is to use the same trick for pointer encoding as what we see in power-of-2-entry FIFO. For example, both read and write pointers have (2 + 1) bits, where 2 is for bits to index 3-entry FIFO, and 1 is to decode FIFO full and empty conditions. Pointer value change shall have the following patterns:

000 -> 001 -> 010 -> 100 -> 101 -> 110 -> 000 -> …

When read pointer is equal to write pointer, the FIFO is empty; When read pointer is the same as write pointer other than MSB, the FIFO is full.