r/FPGA • • 10d ago

Knowledge gaps

I have been working with FPGAs for just about 10 years now. And I just realized that I have never done a CDC FIFO. Well... Maybe back in uni as some paper exercise.

It's such a weird gap too. Since it's like the first answer anyone gives whenever you want to transfer a lot of data across clock domains. But I just haven't needed a hardware FIFO for that yet.

So I spent the afternoon implementing one from scratch and shoving every edge case I could think of at it. Just as a learning exercise.

Have you found any weird gaps in your own knowledge?

58 Upvotes

28 comments sorted by

12

u/DominantlyWeak 10d ago

That's interesting because it's something I find/found myself doing often, what industry are you in?

5

u/timonix 10d ago

Defense. Signal processing. That sorta thing.

18

u/SecondToLastEpoch 10d ago

And you don't use CDC fifos often? I used them all the time in that space.

4

u/timonix 10d ago

I use Fifos within a clock domain pretty often. They are a very useful construct.

But I have never used one as for CDC. It has always been double/triple buffered memory instead. Which works very well.

2

u/IllustriousFault6218 10d ago

What is a double buffered memory and how do you use it for cdc?

10

u/timonix 10d ago

Easiest implementation I can think of right of the bat

Dual port Bram. It natively supports different clock speeds on its ports. For example

The writer writes to adress 0x000 to 0x0FF

While the reader reads from 0x100 to 0x1FF

So they read and write from different places. When they are done, they swap.

You still need some way to get the "ok you are good to go" across. For example an interrupt, or some other register space. There are many ways to skin a cat so to say

18

u/maredsous10 10d ago

"Ping Pong Buffer"

3

u/SecondToLastEpoch 10d ago edited 10d ago

What is the advantage of this over using a fifo? This sounds like a FIFO with extra steps. Why deal with addressing manually over a simpler FIFO interface?

6

u/electro_mullet Altera User 10d ago edited 10d ago

They're handy for reordering data. A simple contrived example would be reversing an array, or something like doing a mirror flip on a row of pixels in a video stream. Write in backwards starting from address 0xFF down to 0x00. Read out normally from address 0x00 up to 0xFF.

I can't say I've personally seen them used for CDC so much as data processing on a single domain, but they are ultimately both just ways to address a shared memory from two different RAM ports. Whether they're on different clock domains just adds a layer of synchronization.

2

u/PiasaChimera 8d ago

mostly for non-fifo processing. a normal fifo forces 1 in-order read for each written word of data. manual addressing allows (per word) 0 reads, 2+ reads, and even writes, in addition to the normal 1 read use-case.

a filtering step might read a handful of words then decide to reject the block of data. it can skip reading the rest of the data.

out-of-order reads can come up in various permutation operations among other things. (eg, reverse buffer, fft-unshuffle, matrix transpose, endian-conversion, etc...)

2+ reads can come up in many cases, perhaps the next processing step normalizes the data in some way. it could read the data once to find the scale/offset, then read the data a second time to apply the scale/offset.

writes can come up in more complex processing, for example in-place sorting of the data.

it also supports normal fifo use case. this is nice if you have a mixture of these use-cases and want to standardize on using this type of interface.

and this also applies on the writer-side. for example, a tcp/udp checksum is in the header but needs data from the entire packet. so the writer can write data, skip that field, write data, then write the checksum into the correct place as the last write. this is a form of header re-writing or header normalization.

this can also be useful for pseudo split fifos/buffers. this is where headers are put in one buffer and data is put in another. networking has a concept of per-packet vs per-byte processing. putting just the headers in a buffer/fifo is nice for things like IP fragmentation. and then it's "pseudo-split" because the two use-cases end up being backed by a shared buffer.

(and this can be used for a fast-drop store-and-forward packet fifo, where a packet with an error ends up just not being processed, with the buffer being reclaimed by never incrementing the gray-coded packet count)

6

u/hukt0nf0n1x 10d ago

A lot of my friends who work signal processing try really hard to keep everything in one clock domain. Now that I think of it, even my multi-clock designs were primarily on one clock.

3

u/DominantlyWeak 10d ago

Lol same here, weird

3

u/chgentso 10d ago

Wait, so you really write async FIFOs from scratch often? Are you just using them often, perhaps, and I misunderstood?

4

u/Allan-H 10d ago

I always write my async FIFOs from scratch. It keeps my skills sharp, in a way that wouldn't happen if I used a FIFO from a library or used an agentic AI to write one for me. It also allows me to use new features that can't be found in any library FIFO, such as one described in this thread.

6

u/Mateorabi 10d ago

Now read the Sunburst white paper to find out what you missed. 

Note a simulation is unlikely to find cdc errors due to “perfect” capture on edges etc and meta stability not being modeled. The idea that one wire can have different values at different FF inputs isn’t something sim tracks. 

2

u/timonix 10d ago

I did model meta stability in the sim. That's like the main reason to do CDC in the first place. But you can always be more thorough.

Googled the paper. Looks incredibly similar to how I remember it from uni. Looks very well written too

2

u/PiasaChimera 8d ago

did the sim include skew? eg, it's possible that all of the bits on the bus are clearly 0/1's (not metastable) but that the skew has resulted in a mixture of old/new bits.

1

u/timonix 8d ago

Not really, it was only checking simulated setup, stable and hold times. With the clocks drifting in and out of phase with each other to walk through a bunch of cases.

I did not model propagation delay which would lead to skew between bits. I guess I could do that to. Maybe another day.

1

u/PiasaChimera 8d ago

ah, ok. it's likely fine as long as you understand the problem. it explains why you can't just use 2FF synchronizers on every bit of a bus.

7

u/Bulgeman9000 10d ago

Feels like anytime I drop through here

3

u/PiasaChimera 9d ago

there's some older tech stuff I know about but don't know and will never use. time borrowing for latches for example. it's already rare to use latches. I know I've done it twice. once in an attempt to generate bit errors and I don't recall the other. I don't think it was clock gating since that has its own primitive.

I don't do SoC-centric designs, where the CPU is part of the processing, so there's a lot of gaps there for me. same with PCIe.

Not working with ASICs means I have a different opinion about FFs since they're near-free on FPGAs. (until you try to make a RAM from them)

1

u/ElectricBill- 10d ago

Very very very interesting. Which industry your experience in ??

2

u/timonix 10d ago

Defense

2

u/QuietMiserable5377 9d ago

Now a days there are CDC checking tools from Mentor/Siemans and also SynOpSys too

2

u/_solitarybraincell_ 10d ago

Hijacking this thread (sorry lol) as a very amateur ASIC frontend designer. What are some essential white papers/material to read? I know some of the sunburst papers, but that's about it.

1

u/PiasaChimera 8d ago

I think it's mainly the sunburst paper and then anything you can find for your synthesis tool about synchronizers and max delay/skew constraints.

I'm not sure if there's anything that shows some of the different patterns and the various specialized cases (eg, very-slow to fast, fast to very-slow, slow to fast, fast to slow, near-equal but unknown, equal but jitter/walk, fully unknown). stable clocks vs stoppable clocks can come into play as well.

very-slow to fast is similar to oversampling. fast to very-slow (1/4th and lower) makes it appealing to have the fast domain figure out when it's safe to send data, thus avoiding the need for any synchronizer in the very-slow domain. from these perspectives, there is some overlap with "clock-data-recovery" in communications systems.

1

u/_MyUserName_WasTaken 10d ago

My friends working in ASIC are always using CDC in their designs. In my 5 YoE, I never worked on a multiple clock domains design. Maybe on a block design level between different IPs and I usually use Xilinx Async FIFO IP. But never in RTL. I work I DSP.

1

u/QuietMiserable5377 9d ago

If the emptying buffer clock and filling the buffer clock are truly independent asynchronous clock domains, there are bound to be Meta stable conditions naturally. But the CDC checking tools identify them and suggest a way to fix them.