找回密码
 注册
关于网站域名变更的通知
查看: 400|回复: 2
打印 上一主题 下一主题

编写具有100%可靠性代码的几个技巧

[复制链接]

该用户从未签到

跳转到指定楼层
1#
发表于 2020-9-7 14:38 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

EDA365欢迎您登录!

您需要 登录 才可以下载或查看,没有帐号?注册

x
您编写的代码是不是虽然在仿真器中表现正常,但是在现场却断断续续出错?要不然就是有可能在您使用更高版本的工具链进行编译时,它开始出错。您检查自己的测试平台,并确认测试已经做到100%的完全覆盖,而且所有测试均未出现任何差错,但是问题仍然顽疾难除。( O8 ]; m* s; U" O/ {
虽然设计人员极其重视编码和仿真,但是他们对芯片在FGPA中的内部操作却知之甚少,这是情有可原的。因此,不正确的逻辑综合和时序问题(而非逻辑错误)成为大多数逻辑故障的根源。8 p& F6 Y. m+ Q7 c  l
但是,只要设计人员措施得当,就能轻松编写出能够创建可预测、可靠逻辑的FPGA代码。/ c- B& g  n0 H- q4 J. u
在FPGA设计过程中,需要在编译阶段进行逻辑综合与相关时序收敛。而包括I/O单元结构、异步逻辑和时序约束等众多方面,都会对编译进程产生巨大影响,致使其每一轮都会在工具链中产生不同的结果。为了更好、更快地完成时序收敛,我们来进一步探讨如何消除这些差异。
+ O& ~+ q4 ~( g' L: xI/O 单元结构7 R5 L) l8 n: A. O! N" e3 k. o0 x
所有FPGA都具有可实现高度定制的I/O引脚。定制会影响到时序、驱动强度、终端以及许多其它方面。如果您未明确定义I/O单元结构,则您的工具链往往会采用您预期或者不希望采用的默认结构。如下VHDL代码的目的是采用“sda: inout std_logic;”声明创建一个称为 sda 的双向I/O缓冲器。) G, O0 w$ U0 B$ l/ q' C0 p
tri_state_proc : PROCESS (sys_clk)BEGINif rising_edge(sys_clk) thenif (enable_in = '1') thensda <= data_in;elsedata_out <= sda;sda <= 'Z';end if;end if;END PROCESS tri_state_proc;* w/ L4 L8 l& b" W
当综合工具发现这组代码时,其中缺乏如何实施双向缓冲器的明确指示。因此,工具会做出最合理的猜测。( H5 e6 b6 `; w% x2 `/ L
实现上述任务的一种方法是, 在FPGA的I/O环上采用双向缓冲器(事实上,这是一种理想的实施方式)。另一种选择是采用三态输出缓冲器和输入缓冲器,二者都在查询表 (LUT) 逻辑中实施。最后一种可行方法是,在I/O环上采用三态输出缓冲器,同时在LUT中采用输入缓冲器,这是大多数综合器选用的方法。- g6 e& M: V# P# B1 E5 E
这三种方法都可以生成有效逻辑,但是后两种实施方式会在I/O引脚与LUT之间传输信号时产生更长的路由延迟。此外,它们还需要附加的时序约束,以确保时序收敛。FPGA编辑器清晰表明:在图1中,我们的双向I/O有一部分散布在I/O缓冲器之外。
! P3 X9 r& {6 o, i: R$ F4 p! w/ Q- [! g5 l/ H
教训是切记不要让综合工具猜测如何实施代码的关键部分。即使综合后的逻辑碰巧达到您的预期,在综合工具进入新版本时情况也有可能发生改变。
* E5 C' z8 ^* Q, V2 ?应当明确定义您的I/O逻辑和所有关键逻辑。以下VHDL代码显示了如何采用Xilinx? IOBUF原语对I/O缓冲器进行隐含定义。另外需要注意的是,采用相似方式明确定义缓冲器的所有电气特性。3 x& F2 P0 i! Y& }( w* B
sda_buff: IOBUFg e n e r i c m a p ( I O S TANDARD =>"LVCMOS25",IFD_DELAY_VALUE => "0", DRIVE =>12,SLEW => "SLOW")port map(o=> data_out, io=> sda,i=> data_in, t=> enable_in);
4 t$ N: X3 Q; O" Q  g1 F
/ G2 j3 ]3 @: _' `( v在图2中,FPGA编辑器明确显示,我们已完全在I/O缓冲器内部实施了双向I/O。
1 }1 W% y- X: H8 j2 _- y异步逻辑的劣势异步代码会产生难以约束、仿真及调试的逻辑。异步逻辑往往产生间歇性错误,而且这些错误几乎无法重现。另外,无法生成用于检测异步逻辑所导致的错误的测试平台。
( ?8 p6 `# J( o- A2 R虽然异步逻辑看起来可能容易检测,但是,事实上它经常不经检测;因此,设计人员必须小心异步逻辑在设计中隐藏的许多方面。所有钟控逻辑都需要一个最短建立与保持时间,而且这一点同样适用于触发器的复位输入。以下代码采用异步复位。在此无法为了满足触发器的建立与保持时间需求而应用时序约束。: c% ^8 z: A6 R2 K" V7 a
data_proc : PROCESS (sys_clk,reset)BEGINif (reset = '1') thendata_in <= '0';elsif rising_edge(sys_clk) thendata_in <= serial_in;end if;END PROCESS data_proc;
, V# }; Y4 n: l$ H1 y2 _% [下列代码采用同步复位。但是,大多数系统的复位信号都可能是按键开关,或是与系统时钟无关的其它信号源。尽管复位信号大部分情况是静态的,而且长期处于断言或解除断言状态,不过其水平仍然会有所变化。相当于系统时钟上升沿,复位解除断言可以违反触发器的建立时间要求,而对此无法约束。
" f' A. x9 \# H9 G0 E* T) `data_proc : PROCESS (sys_clk)BEGINif rising_edge(sys_clk) thenif (reset = '1') thendata_in <= '0';elsedata_in <= serial_in;end if;end if;END PROCESS data_proc;* z4 e  i( }/ z: R% A7 f$ N
只要我们明白无法直接将异步信号馈送到我们的同步逻辑中,就很容易解决这个问题。以下代码创建一个称sys_reset 的新复位信号,其已经与我们的系统时钟sys_clk同步化。在异步逻辑采样时会产生亚稳定性问题。我们可以采用与阶梯的前几级进行了‘与’运算的梯形采样降低此问题的发生几率。! Z) M+ i4 b  j' }' m* r
data_proc : PROCESS (sys_clk)BEGINif rising_edge(sys_clk) thenreset_1 <= reset;reset_2 <= reset_1 and reset;sys_reset <= reset_2 and reset_1and reset;end if;if rising_edge(sys_clk) thenif (sys_reset = '1') thendata_in <= '0';elsedata_in <= serial_in;end if;end if;END PROCESS data_proc;, x# x+ k( j9 t
至此,假定您已经慎重实现了所有逻辑的同步化。不过,如果您不小心,则您的逻辑很容易与系统时钟脱节。切勿让您的工具链使用系统时钟所用的本地布线资源。那样做的话您就无法约束自己的逻辑。切记要明确定义所有的重要逻辑。- X8 b7 ]1 @" `6 m3 \6 ^
以下VHDL代码采用赛灵思 BUFG原语强制sys_clk进入驱动低延迟网络(low-skew net) 的专用高扇出缓冲器。
" Y) \: w8 q# O; k, Ggclk1: BUFG port map (I => sys_clk,O=> sys_clk_bufg);data_proc : PROCESS (sys_clk_bufg)BEGINif rising_edge(sys_clk_bufg) thenreset_1 <= reset;reset_2 <= reset_1 and reset;sys_reset <= reset_2 and reset_1and reset;end if;if rising_edge(sys_clk_bufg) thenif (sys_reset = '1') thendata_in <= '0';elsedata_in <= serial_in;end if;end if;END PROCESS data_proc;
: |8 u6 @0 ^! N5 l$ V某些设计采用单个主时钟的分割版本来处理反序列化数据。以下VHDL代码(nibble_proc进程)举例说明了按系统时钟频率的四分之一采集的数据。( \( p% ~1 p6 S2 p. M9 }6 \1 A
data_proc : PROCESS (sys_clk_bufg)BEGINif rising_edge(sys_clk_bufg) thenreset_1 <= reset;reset_2 <= reset_1 and reset;sys_reset <= reset_2 and reset_1and reset;end if;if rising_edge(sys_clk_bufg) thenif (sys_reset = '1') thentwo_bit_counter <= "00";divide_by_4 <= '0';nibble_wide_data <= "0000";elsetwo_bit_counter<= two_bit_counter + 1;divide_by_4 <= two_bit_counter(0) andtwo_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)BEGINif rising_edge(divide_by_4) thenif (sys_reset = '1') thennibble_data_in <= "0000";elsenibble_data_in<= nibble_wide_data;end if;end if;END PROCESS nibble_proc;
( B" q3 m& J9 t& w, _) d1 k看起来好像一切都已经同步化,但是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作为限定符,如下所示。
6 |5 L2 R$ W* E- Jnibble_proc : PROCESS (sys_clk_bufg)BEGINif rising_edge(sys_clk_bufg) thenif (sys_reset = '1') thennibble_data_in <= "0000";elsif (divide_by_4 = '1') thennibble_data_in<= nibble_wide_data;end if;end if;END PROCESS nibble_proc4 C/ f+ B' O# r6 k: \4 C( E/ T* E
时序约束的重要性& F8 N. ^/ N5 f) m, X
如果您希望自己的逻辑正确运行,则必须采用正确的时序约束。如果您已经慎重确保代码全部同步且注册了全部I/O,则这些步骤可以显著简化时序收敛。在采用上述代码并且假定系统时钟为100MHz时,则只需四行代码就可以轻松完成时序约束文件,如下所示:
* ~1 a  V  m3 }# F) M9 qNET sys_clk_bufg TNM_NET =sys_clk_bufg;TIMESPEC TS_sys_clk_bufg = PERIODsys_clk_bufg 10 ns HIGH 50%;OFFSET = IN 6 ns BEFORE sys_clk;OFFSET = OUT 6 ns AFTER sys_clk;( |# @1 F# P! Q0 k( w
请注意:赛灵思FPGA中I/O注册逻辑的建立与保持时间具有很高的固定性,在一个封装中切勿有太大更改。但是,我们仍然采用它们,主要用作可确保设计符合其系统参数的验证步骤。
/ Q. u. Z$ k8 a6 h4 F7 H$ d三步简单操作9 h4 w$ Q1 }- \+ z7 {$ s
仅需遵循以下三步简单操作,设计人员即可轻松实施可靠的代码。# T* z, i1 Y/ p
? 切勿让综合工具猜测您的预期。采用赛灵思原语对所有 I/O 引脚和关键逻辑进行明确定义。确保定义 I/O 引脚的电气特性;? 确保逻辑 100% 同步,并且让所有逻辑参考主时钟域;? 应用时序约束确保时序收敛。
9 g, l- }" T# o9 }( V( B1 D* j只要遵循上述三个步骤,您就能够消除综合与时序导致的差异。扫除这两个主要障碍会让您获得具有100%可靠性的代码。7 X3 c5 T/ e0 w: B2 C6 N

该用户从未签到

2#
发表于 2020-9-7 15:38 | 只看该作者
虽然设计人员极其重视编码和仿真,但是他们对芯片在FGPA中的内部操作却知之甚少,这是情有可原的。因此,不正确的逻辑综合和时序问题(而非逻辑错误)成为大多数逻辑故障的根源。 但是,只要设计人员措施得当,就能轻松编写出能够创建可预测、可靠逻辑的FPGA代码。
  • TA的每日心情
    开心
    2023-6-2 15:15
  • 签到天数: 1 天

    [LV.1]初来乍到

    3#
    发表于 2020-9-7 15:47 | 只看该作者
    异步逻辑的劣势异步代码会产生难以约束、仿真及调试的逻辑
    您需要登录后才可以回帖 登录 | 注册

    本版积分规则

    关闭

    推荐内容上一条 /1 下一条

    EDA365公众号

    关于我们|手机版|EDA365电子论坛网 ( 粤ICP备18020198号-1 )

    GMT+8, 2025-6-23 06:33 , Processed in 0.093750 second(s), 23 queries , Gzip On.

    深圳市墨知创新科技有限公司

    地址:深圳市南山区科技生态园2栋A座805 电话:19926409050

    快速回复 返回顶部 返回列表