5

I have been designing a few projects on different FPGA's in VHDL, and it seems my most common source of "hard to find errors" is when I forget to synchronize an async signal, or forgets to resync a signal crossing clock domains.

My best weapon so far, has been to draw block schematic of the components.

So my questions is, what is the best design practice to prevent these errors?

Damien
  • 1,504
  • 1
  • 17
  • 30
JakobJ
  • 2,298
  • 1
  • 21
  • 42

3 Answers3

6

Today even FPGA designs can have extremely complex clocking architectures and many async inputs, resulting in many potential CDC issues.

I'd say that the following points constitute a minimal set of "rules of thumb" for avoiding CDC bugs:

  1. Keep track of all signals which cross clock domains (diagrams, lists, spreadsheets - whatever you find more convenient). Async input signals should be included too.
  2. All signals from the above list must be synchronized, unless there is a clear reason why not.
  3. Never ever synchronize multi-bit signals bit-by-bit! Use special synchronization schemes for buses instead (sync FIFO, two way handshake, etc.).
  4. If there is an async reset in the system, and this reset does not apply to all the flip-flops - all the signals originating in this reset domain and passed to non-reset logic should be treated as async (and included in the list from #1)

I'm sure that the above list of practices is incomplete, and can be easily extended.

I also suggest considering CDC verification tools (like Questa CDC from Mentor) - these tools use formal techniques to automatically detect CDC issues in your design.

Vasiliy
  • 7,323
  • 2
  • 21
  • 38
2

Some naming practises can be handy:

  • Any signal which crosses a clock domain should have the domain it is synchronised to appended to it. So if you have count in the clock domain driven by signal clk (and it needs to go to another clock domain driven by other_clk), call it count_clk and count_other_clk.

  • Keep all the synchronisation code from one clock domain to another in one place. Maybe encapsulate it, depending on how much there is. Put clear comments around it (eg. above here is clk, this is the domain crossing from clk to other_clk, below here is other_clk)

  • Truly asynchronous signals can have _async appended to the end.

This at least makes code-review a little easier to deal with, but if you have many domains and many crossings, it will benefit you to invest in some tools to help (like Spyglass for example - which does vastly more than just checking clock domains)

Martin Thompson
  • 8,439
  • 1
  • 23
  • 44
1

In addition to the previous answers:

Report Timing

Use your timing analysis tool in your FPGA toolchain to find any signals you've forgotten to handle correctly.

You can easily generate a list of unconstrained clock transfers, all of which should be synchronised and an appropriate false-path added. Ideally embed this into your build system so that it fails with an error if there are any unconstrained clock transfers, then you can't forget about them!

Re-use code

Have a single entity/module for doing your single bit synchronisation, use a generic/parameter to control the number of registers in the resync chain. You might want a separate synchroniser for resets.

Embed constraints

The advantage of re-using code - embed the false path constraints in the RTL. That way you don't have to remember to add timing constraints for every signal.

A note about placement

Registers in synchroniser chains need to be placed close together to ensure maximum timing window is provided. Altera claim to automatically detect synchroniser chains so they shouldn't need placement constraints. If you're paranoid on Xilinx you can use RLOC constraints to ensure your synchroniser registers are placed close together (unfortunately Altera don't support relative location constraints).

Chiggs
  • 670
  • 4
  • 5