FPGA 时序收敛
阶梯的前几级进行了’与’运算的梯形采样降低此问题的发生几率。 data_proc : PROCESS (sys_clk) BEGIN if rising_edge(sys_clk) then reset_1 = reset; reset_2 = reset_1 and reset; sys_reset = reset_2 and reset_1 and reset; end if; if rising_edge(sys_clk) then if (sys_reset = ‘1’) then data_in = ‘0’; else data_in = serial_in; end if; end if; END PROCESS data_proc; 至此,假定您已经慎重实现了所有逻辑的同步化。不过,如果您不小心,则您的逻辑很容易与系统时钟脱节。切勿让您的工具链使用系统时钟所用的本地布线资源。那样做的话您就无法约束自己的逻辑。切记要明确定义所有的重要逻辑。 以下 VHDL 代码采用赛灵思 BUFG 原语强制 sys_clk 进入驱动低延迟网络 (low-skew net) 的专用高扇出缓冲器。 gclk1: BUFG port map (I => sys_clk,O => sys_clk_bufg); data_proc : PROCESS (sys_clk_bufg) BEGIN if rising_edge(sys_clk_bufg) then reset_1 = reset; reset_2 = reset_1 and reset; sys_reset = reset_2 and reset_1 and reset; end if; if rising_edge(sys_clk_bufg) then if (sys_reset = ‘1’) then data_in = ‘0’; else data_in = serial_in; end if; end if; END PROCESS data_proc; 某些设计采用单个主时钟的分割版本来处理反序列化数据。以下 VHDL 代码(nibble_proc进程)举例说明了按系统时钟频率的四分之一采集的数据。 data_proc : PROCESS (sys_clk_bufg) BEGIN if rising_edge(sys_clk_bufg) then reset_1 = reset; reset_2 = reset_1 and reset; sys_reset = reset_2 and reset_1 and reset; end if; if rising_edge(sys_clk_bufg) then if (sys_reset = ‘1’) then two_bit_counter = "00"; divide_by_4 = ‘0’; nibble_wide_data = "0000"; else two_bit_counter = two_bit_counter + 1; divide_by_4 = two_bit_counter(0) and two_bit_counter(1); nibble_wide_data(0) = serial_in; nibble_wide_data(1) = nibble_wide_data(0); nibble_wide_data(2) = nibble_wide_data(1); nibble_wide_data(3) = nibble_wide_data(2); end if; end if; END PROCESS data_proc; nibble_proc : PROCESS (divide_by_4) BEGIN if rising_edge(divide_by_4) then if (sys_reset = ‘1’) then nibble_data_in = "0000"; else nibble_data_in = nibble_wide_data; end if; end if; END PROCESS nibble_proc; 看起来好像一切都已经同步化,但是 nibble_proc 采用乘积项 divide_by_4 对来自时钟域sys_clk_bufg 的 nibble_wide_data 进行采样。由于路由延迟,divde_by_4 与 sys_clk_bufg 之间并无明确的相位关系。将 divide_by_4 转移到 BUFG 也于事无补,因为此进程会产生路由延迟。解决方法是将 nibble_proc 保持在 sys_clk_bufg 域,并且采用 divide_by_4 作为限定符,如下所示。 nibble_proc : PROCESS (sys_clk_bufg) BEGIN if rising_edge(sys_clk_bufg) then if (sys_reset = ‘1’) then nibble_data_in = "0000"; elsif (divide_by_4 = ‘1’) then nibble_data_in = nibble_wide_data; end if; end if; END PROCESS nibble_proc 时序约束的重要性 如果您希望自己的逻辑正确运行,则必须采用正确的时序约束。如果您已经慎重确保代码全部同步且注册了全部 I/O,则这些步骤可以显著简化时序收敛。在采用上述代码并且假定系统时钟为100MHz 时,则只需四行代码就可以轻松完成时序约束文件,如下所示: NET sys_clk_bufg TNM_NET = sys_clk_bufg; TIMESPEC TS_sys_clk_bufg = PERIOD sys_clk_bufg 10 ns HIGH 50%; FFSET = IN 6 ns BEFORE sys_clk; FFSET = OUT 6 ns AFTER sys_clk; 请注意:赛灵思 FPGA 中 I/O 注册逻辑的建立与保持时间具有很高的固定性,在一个封装中切勿有太大更改。但是,我们仍然采用它们,主要用作可确保设计符合其系统参数的验证步骤。 三步简单操作 仅需遵循以下三步简单操作,设计人员即可轻松实施可靠的代码。 ? 切勿让综合工具猜测您的预期。采用赛灵思原语对所有 I/O 引脚和关键逻辑进行明确定义。确保定义 I/O 引脚的电气特性; ? 确保逻辑 100% 同步,并且让所有逻辑参考主时钟域; ? 应用时序约束确保时序收敛。 只要遵循上述三个步骤,您就能够消除综合与时序导致的差异。扫除这两个主要障碍会让您获得具有 100% 可靠性的代码。
FPGA 相关文章:
- 在采用FPGA设计DSP系统中仿真的重要性 (06-21)
- 基于 DSP Builder的FIR滤波器的设计与实现(06-21)
- 基于FPGA的快速并行FFT及其在空间太阳望远镜图像锁定系统中的应用(06-21)
- 3DES算法的FPGA高速实现(06-21)
- 用FPGA实现FFT算法(06-21)
- FPGA的DSP性能揭秘(06-16)