我有一个总线同步器电路,用于跨时钟域传递宽寄存器。
我将提供简化的描述,省略异步重置逻辑。
数据在一个时钟上生成。更新间隔了许多(至少一打)时钟沿:
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;
用于新鲜数据的控制信号,该信号经过NRZI编码(因此,总线上的有效字对应于控制信号上的转换)。控制信号通过充当同步器的DFF链。
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;
同步器电路引入了短暂的延迟,这为数据总线稳定提供了足够的时间。数据总线直接采样,没有亚稳态风险:
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;
编译成Cyclone II FPGA后,它可以很好地工作。但是,TimeQuest报告设置和保持时间违规,因为它无法识别同步器。更糟糕的是,Quartus手册说
专注于改善显示最差松弛的路径。钳工在松弛最差的路径上最努力地工作。如果您修复了这些路径,则钳工可能能够改善设计中其他失败的时序路径。
因此,我想在项目中添加正确的时序约束,以便Quartus将Fitter的精力用于设计的其他领域。
我非常确定这set_multicycle_path
是正确的SDC(摘要设计约束)命令,因为数据线将具有多个稳定的目标时钟周期,但是我找不到使用此命令描述时钟域交叉逻辑的完整示例。 。
我真的很感谢为同步器编写SDC时序约束的一些指导。如果您发现此方法有问题,也请告知我。
时钟细节:
外部时钟发生器:两个通道,refclk = 20 MHz,refclk2 = refclk / 2(10 MHz,及相关)。
Altera PLL:src_clk = refclk * 9/5 = 36 MHz
Altera PLL:dest_clk = refclk2 * 10 = 100 MHz
我还有另一个方向的数据,分别是100 MHz src_clk和36 MHz dest_clk。
TL; DR:以上代码的正确SDC时序约束是什么?