Electronic – gray code clock domain crossing FIFO fast to slow


I'm trying to understand how clock crossing FIFOs are implemented, and the usual answer I see to convert the read/write address pointers to gray code and then pass through synchronizer circuits into each others clock domain to determine if there's data in contained in the FIFO. The idea of using gray code is so the other clock domain can detect metastability on the other end by the fact that only one bit should change per address increment…and it can safely ignore the address pointer until it looks valid.

What about the scenario where the write clock domain is much faster than the slow clock domain? If the write address pointer can increment many times per read clock cycle, at some point there will be more than 1 bit flipped in the gray code value, and that wouldn't necessarily be a mistake. How is this situation usually handled?

I know there's a similar question on SE, but the answer seems to show an example of the write clock being only 2x faster than the read clock, so maybe this situation is never experienced.

Best Answer

In an asynchronous FIFO, one clock domain is associated with the write port, and the "head" pointer (the next write address) is kept in that clock domain. Similarly, the other clock domain is associated with the read port, and the "tail" pointer is kept there.

The problem is that both clock domains need to be able to keep track of the number of words in the FIFO, and the way to do this is to subtract the value of the tail pointer from the value of the head pointer, modulo the size of the RAM. Therefore, each pointer is encoded as Gray code and transferred to the other clock domain.

It doesn't matter if more than one write happens during a read clock period, or vice-versa. The point is, with Gray code encoding, only one bit changes between any pair of values. If one clock happens to catch a transition in the other clock domain, at most only one bit can be metastable, and the ambiguity is between two adjacent states of the counter.

Therefore, it isn't possible for either clock domain to calculate an erroneous value for the number of words in the FIFO — it simply becomes a question of whether it gets the update one clock sooner or later than it otherwise might have.

So, on the write side, the head pointer increments directly, increasing the depth of the FIFO, but the updated tail pointer coming from the other side may be delayed. This can only cause the write side to overestimate the number of words in the FIFO, and therefore, the FIFO will never overflow.

Similarly, on the read side, the tail pointer increments directly, decreasing the depth of the FIFO, but the updated head pointer may be delayed. This can only cause the read side to underestimate the number of words in the FIFO, and as a result, it will never underflow.

In fact, you can put any number of synchronizing stages in the path of the Gray code transfers, and the only effect this will have is to increase the latency through the FIFO. This is even a configurable parameter in the Xilinx dual-clock FIFO generator.