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.


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, transferred to the other clock domain and converted back to binary.

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.

In other words, each side sees a monotonically increasing sequence of values from the other side, even if some values are skipped — and more importantly, even if metastability occurs. 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.

  • 2
    \$\begingroup\$ Okay, I think I get it. So multiple bits can change when the counter is crossed over to the slower clock domain, but only 1 bit will pose the risk of being metastable based on the fact that only 1 bit changes in the fast domain gray coding. All the other bits should have held steady for a longer amount of time, and thus the chance of violating the setup/hold time of the slow clock domain registers has reduced. Passing the gray code value through a double-register will clear up the single bit metastable error as it usually does, and you don't have to worry about multi-bit bus deskewing. \$\endgroup\$ Apr 12 '19 at 13:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.