I've a bus synchronizer circuit for passing a wide register across clock domains.
I'll provide a simplified description, omitting asynchronous reset logic.
The data is generated on one clock. Updates are many (at least a dozen) clock edges apart:
PROCESS (src_clk)
BEGIN
IF RISING_EDGE(clock) THEN
IF computation_done THEN
data <= computation;
ready_spin <= NOT ready_spin;
END IF;
END IF;
END PROCESS;
The control signal for fresh data, which is NRZI encoded (so a valid word on the bus corresponds to a transition on the control signal). The control signal passes through a DFF chain acting as a synchronizer.
PROCESS (dest_clk)
BEGIN
IF RISING_EDGE(dest_clk) THEN
ready_spin_q3 <= ready_spin_q2;
ready_spin_q2 <= ready_spin_q1;
ready_spin_q1 <= ready_spin;
END IF;
END PROCESS;
The synchronizer circuit introduces a short delay, which provides plenty of time for the data bus to stabilize; the data bus is sampled directly without a risk of metastability:
PROCESS (dest_clk)
BEGIN
IF RISING_EDGE(dest_clk) THEN
IF ready_spin_q3 /= ready_spin_q2 THEN
rx_data <= data;
END IF;
END IF;
END PROCESS;
This compiles, and works well when synthesized into a Cyclone II FPGA. However, TimeQuest reports setup and hold time violations, because it doesn't recognize the synchronizer. Worse, the Quartus manual says
Focus on improving the paths that show the worst slack. The Fitter works hardest on paths with the worst slack. If you fix these paths, the Fitter might be able to improve the other failing timing paths in the design.
So I want to add the right timing constraints to my project so that Quartus will spend its Fitter effort on other areas of the design.
I'm pretty sure that set_multicycle_path
is the proper SDC (Synopsis Design Constraint) command, since the data lines will have multiple cycles of the destination clock to stabilize, but I can't find any complete examples using this command to describe clock domain crossing logic.
I'd really appreciate some guidance on writing SDC timing constraints for synchronizers. If you see a problem with this approach, please also let me know that.
Clock detail:
External clock generator: Two channels, refclk = 20 MHz, refclk2 = refclk/2 (10 MHz, and related).
Altera PLL: src_clk = refclk * 9/5 = 36 MHz
Altera PLL: dest_clk = refclk2 * 10 = 100 MHz
I also have data going the other direction, with 100 MHz src_clk and 36 MHz dest_clk.
TL;DR: What are the correct SDC timing constraints for the above code?