0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

进行RTL代码设计需要考虑时序收敛的问题

454398 ? 来源:AI加速 ? 作者:AI加速 ? 2020-11-20 15:51 ? 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

引言

硬件描述语言(verilog,systemVerilog,VHDL等)不同于软件语言(C,C++等)的一点就是,代码对应于硬件实现,不同的代码风格影响硬件的实现效果。好的代码风格能让硬件“跑得更快”,而一个坏的代码风格则给后续时序收敛造成很大负担。你可能要花费很长时间去优化时序,保证时序收敛。拆解你的代码,添加寄存器,修改走线,最后让你原来的代码“遍体鳞伤”。这一篇基于赛灵思的器件来介绍一下如何在开始码代码的时候就考虑时序收敛的问题,写出一手良好的代码。

1. Counter结构

计数器是在FPGA设计中经常要用到的结构,比如在AXI总线中对接收数据量的计算,用计数器来产生地址和last等信号。在计数器中需要用到进位链,进位链是影响时序的主要因素。如果进位链越长,那么组合逻辑的级数就越高,组合逻辑延迟越大,能够支持的最大时钟频率就会越低。在一个CLB中通常会含有一个进位链结构,比如在ultrascale中是CARRY8,在zynq7系列中是CARRY4,CARRY4可以实现4bit进位。如果是一个48bit计数器就需要12个这样的进位结构。一个CARRY4输出有两种CO和O,CO是进位bit,用于级联到下一级的CARRY4的CI,O是结果输出。因此我们可以看到在计数器中最下的进位结构是CARRY4,如果直接让多个进位结构级联,那么组合逻辑就会变大,时序延迟就会增大。如果可以将计数器拆分成小的计数器,那么时序就可以得到改善。


比如一个48bit计数器拆分成3个16bit计数器,那么CARRY4的级联级别就从原来的12个降低到4个。每4个之间增加了FF来进行时序改善。

always @(posedge clk)begin
         if(rst)
                   cnt_o <= 0;
         else 
                   cnt_o <= cnt_o + 1;
end  

拆分后代码为:

genvar i;
generate
for(i=0;i<3;i=i+1)begin: CNT_LOOP
         wire trigger_nxt, trigger_pre;

         if(i == 0)begin
                   always @(posedge clk)begin
                            if(rst)
                                     cnt_o[i*16 +: 16] <= 0;
                            else
                                     cnt_o[i*16 +: 16] <= cnt_o[i*16 +: 16] + 1;
                   end

                   assign trigger_nxt = (cnt_o[i*16 +: 16] == 16'hFFFF) ? 1 : 0;
         end//if
         else begin
                   assign trigger_pre = CNT_LOOP[i-1].trigger_nxt;

                   always @(posedge clk)begin
                            if(rst)
                                     cnt_o[i*16 +: 16] <= 0;
                            else if(trigger_pre)
                                     cnt_o[i*16 +: 16] <= cnt_o[i*16 +: 16] + 1;
                   end 

                   assign trigger_nxt =  CNT_LOOP[i-1].trigger_nxt && (cnt_o[i*16 +: 16] == 16'hFFFF);
         end//else
end//for
endgenerate

综合后我们就可以看到它的schematic每4个CARRY4都被FF隔开了,可以降低逻辑延时。但是代价是增加了LUT的数量,这些LUT是用来判断前一个16bit计数器的数值的,从而驱动后边16bit寄存器计数。


2. 逻辑拆分

在上一节中拆解计数器本质上就是在拆分组合逻辑。当一个组合逻辑过大的时候,延时较大。将其拆解成两个或者两个以上逻辑,中间增加寄存器可以来提高能跑得时钟频率。比如下图有一个较大的组合逻辑,前边有一个FF,后边连续接2个FF。组合逻辑的延时就成为了整体时钟频率的一个关键路径。如果我们可以将其拆分成两个,中间用一级寄存器连接,这样总共的时钟周期还是3个,但是时钟频率明显会好于前一种。


3. 改善扇出

扇出是指某个信号驱动的信号的数量。驱动的信号越多,那么要求其产生的电流越大。学过数字电路就会知道,当一个信号输出连接的越多的时候,其输出负载就会越小,那么输出电压就会减小。所以如果信号扇出过大就会影响到高低电平,最终就会导致时序不收敛。另外一个原因是如果信号扇出过大,那么由于FPGA上走线路径的差异,就可能造成这个信号到达不同地址的延迟不同,造成时序不同步。一种解决办法是复制,将扇出较大的信号复制几份,这样就可以减小扇出。比如一个输入d_i需要和3个数进行求和。那么这个信号扇出就是3.如果将其复制3份,给每个数输送一份,那么扇出就变为1。

always @(posedge clk)begin
         data1_o <= data_i + data1_o;
         data2_o <= data_i + data2_o;
         data3_o <= data_i + data3_o;
end 


如果我们复制输入数据,如下图,从中可以看出输入信号复制了三份,分别接给三个加法器。

(* keep = "true" *)reg data_rp1;
(* keep = "true" *)reg data_rp2;
(* keep = "true" *)reg data_rp3;   


always @(posedge clk)begin
         data_rp1 <= data_i;
         data_rp2 <= data_i;
         data_rp3 <= data_i;
         data1_o <= data_rp1 + data1_o;
         data2_o <= data_rp2 + data2_o;
         data3_o <= data_rp3 + data3_o;
end


4. URAM和BRAM使用

Xilinx器件中BRAM的大小是36Kbit,如果不使用校验位,可以配置成1-32bit位宽的存储。比如32x1K。在RTL代码中使用存储的时候,需要适配BRAM大小,这样可以不浪费BRAM存储空间。比如你需要使用一个FIFO,那么这个FIFO位宽32bit,那么它的深度512和1024配置,都消耗了一个BRAM。

BRAM输出中最好用register,不要直接接组合逻辑,这样会增加延时。BRAM中含有register,如果代码中输出有用到register,那么这个register在综合时会被移到BRAM内部。如果BRAM外要连接组合逻辑,最好在BRAM的register的外部在添加一个register,这样有更好的时序。


当我们需要的存储空间和位宽都超过了一个BRAM的时候,就涉及到多个BRAM的级联问题。如何选择单个BRAM的位宽拼接和级联BRAM的个数呢?比如我们要一个32bit位宽,深度为2**15大小的存储。有两种极限方式来配置BRAM。一种是将每个BRAM配置为1x32K,那么32个拼接组成32x32K的存储。另外一种是将每个BRAM设置为32x1K,那么32个级联形成32K深度。前一种不需要多余逻辑来对不同BRAM进行选择操作,但是32个BRAM同时读写,这样会增加power。而后一种32个BRAM级联在一起造成延时路径较长,同时需要增加组合逻辑来选择不同BRAM。但是每次只读写一个BRAM,power较低。可以选择这两个极限的中间值来即降低power也不会有太长的逻辑延时。可以通过约束条件来进行设置。如下图。级联设置为4,这样每次只有8个BRAM同时使能。

(* ram_style = "block", cascade_height = 4 *)
reg [31:0] mem[2**15-1:0];
reg [14:0] addr_reg;
always @(posedge clk)begin
         addr_reg <= addr;
         dout <= mem[addr_reg];
         if(we)
                   mem[addr_reg] <= din;
end


URAM的使用方式类似,只不过URAM存储空间比BRAM大,其可以配置为72x64K大小。

5. 其它

1) 进行条件判定的时候,如果条件过多,尽量减少if-else语句的使用,尽可能用case替代。因为if-else是有优先级的,而case条件判断的平等的。前者会用掉更多逻辑;

2) 在一个always块中尽量对一个信号赋值,不要对具有不同判断条件的信号同时赋值,这样可以减少不必要的逻辑;

3) 尽量使用时钟同步复位,不要使用异步复位。即要用:

always @(posedge clk)begin

If(rst)

End

而不是

always @(posedge clk or posedge rst)

4) 在使用乘法较多的时候,使用DSP原语是最好的。一个DSP除了有乘法功能外,还有前加法器和后加法器,这两个是经常用到的,可以用来计算很多功能。DSP的具体使用可以参考DSP的手册。

总结

以上总结了几点在进行RTL代码设计时,最需要考虑的几种情况。这些对时序影响很大,需要注意。另外从整体来讲,如何选择一个好的算法,然后设计出一个简洁的架构更加重要。因为这些是从整体让你的设计有更多灵活的空间。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • FPGA
    +关注

    关注

    1646

    文章

    22089

    浏览量

    620335
  • 寄存器
    +关注

    关注

    31

    文章

    5444

    浏览量

    125233
  • RTL
    RTL
    +关注

    关注

    1

    文章

    390

    浏览量

    61337
  • AXI总线
    +关注

    关注

    0

    文章

    66

    浏览量

    14587
收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    ADC和FPGA之间LVDS接口设计需要考虑的因素

    本文描述了ADC和FPGA之间LVDS接口设计需要考虑的因素,包括LVDS数据标准、LVDS接口数据时序违例解决方法以及硬件设计要点。
    的头像 发表于 07-29 10:01 ?2112次阅读
    ADC和FPGA之间LVDS接口设计<b class='flag-5'>需要</b><b class='flag-5'>考虑</b>的因素

    利用AMD VERSAL自适应SoC的设计基线策略

    您是否准备将设计迁移到 AMD Versal 自适应 SoC?设计基线是一种行之有效的时序收敛方法,可在深入研究复杂的布局布线策略之前,帮您的 RTL 设计奠定坚实的基础。跳过这些步骤可能会导致
    的头像 发表于 06-04 11:40 ?327次阅读

    TDengine 发布时序数据分析 AI 智能体 TDgpt,核心代码开源

    2025 年 3 月 26 日,涛思数据通过线上直播形式正式发布了其新一代时序数据分析 AI 智能体——TDgpt,并同步开源其核心代码。这一创新功能作为 TDengine 3.3.6.0 的重要
    的头像 发表于 03-27 10:30 ?361次阅读
    TDengine 发布<b class='flag-5'>时序</b>数据分析 AI 智能体 TDgpt,核心<b class='flag-5'>代码</b>开源

    一文详解Vivado时序约束

    Vivado的时序约束是保存在xdc文件中,添加或创建设计的工程源文件后,需要创建xdc文件设置时序约束。时序约束文件可以直接创建或添加已存在的约束文件,创建约束文件有两种方式:Con
    的头像 发表于 03-24 09:44 ?3616次阅读
    一文详解Vivado<b class='flag-5'>时序</b>约束

    ADS1675进行高速采集的程序,看时序图应该会使用PLL进行3倍频,但是这个PLL需要配置吗?

    我现在写ADS1675进行高速采集的程序,看时序图应该会使用PLL进行3倍频,但是这个PLL需要配置吗?一直达不到我想要的结果。谢谢大哥们,帮帮小弟呀
    发表于 12-10 08:15

    选择贴片电感型号时需要考虑什么参数?

    在选择贴片电感型号时,需要综合考虑多个参数以确保电感能够满足电路的需求并保证其可靠性。以下是一些关键参数及其考虑因素: 1. 电感值(Inductance, L) 定义:电感值是电感的标称感值,反映
    的头像 发表于 12-02 15:29 ?723次阅读
    选择贴片电感型号时<b class='flag-5'>需要</b><b class='flag-5'>考虑</b>什么参数?

    ASIC集成电路设计中的常见问题

    标准单元门的方式编码,因为这可能降低代码的可读性,并在采用新的单元库或新工艺时需要反复修改代码。 在定义时序块时,需要注意哪些信号
    的头像 发表于 11-20 15:46 ?1270次阅读

    如何创建虚拟时钟

    通常RTL设计要求对芯片/module的输入信号进行reg_in打拍处理,对芯片/module的输出也要求做reg_out打拍处理,这是良好的代码习惯,为时序
    的头像 发表于 10-23 09:40 ?888次阅读
    如何创建虚拟时钟

    使用IBIS模型进行时序分析

    电子发烧友网站提供《使用IBIS模型进行时序分析.pdf》资料免费下载
    发表于 10-21 10:00 ?1次下载
    使用IBIS模型<b class='flag-5'>进行时序</b>分析

    高速ADC与FPGA的LVDS数据接口中避免时序误差的设计考虑

    电子发烧友网站提供《高速ADC与FPGA的LVDS数据接口中避免时序误差的设计考虑.pdf》资料免费下载
    发表于 10-15 09:50 ?6次下载
    高速ADC与FPGA的LVDS数据接口中避免<b class='flag-5'>时序</b>误差的设计<b class='flag-5'>考虑</b>

    更新红外热像仪需要考虑什么

    对于需要每天定时或长时间持续使用热像仪的用户,提高热像仪的电池寿命至关重要。对于早期购买热像仪或使用前忘记给设备充电的用户来说,升级电池用量更大的热像仪是一个不错的选择。用户也可以考虑一个专用的红外热像仪,它提供了更换电池的能力,进一步避免了不必要的停机时间。
    的头像 发表于 10-14 09:45 ?620次阅读

    使用MXO58示波器轻松进行电源时序分析

    当今复杂的电路必须集成多个在不同功率等级下运行的组件。要确保这些组件的互操作性,电路需要精心设计,具备干净且稳定的电源分配网络来进行电源时序管理。在较低的电压水平下,容差以百分比表示,这可能会给精确
    的头像 发表于 10-13 08:07 ?671次阅读
    使用MXO58示波器轻松<b class='flag-5'>进行</b>电源<b class='flag-5'>时序</b>分析

    锁存器的基本输出时序

    在深入探讨锁存器的输出时序时,我们需要详细分析锁存器在不同控制信号下的行为表现,特别是控制信号(如使能信号E)的电平变化如何影响数据输入(D)到输出(Q)的传输过程。以下是对锁存器输出时序的详细描述,旨在全面覆盖其工作原理和
    的头像 发表于 08-30 10:43 ?1252次阅读

    RTL8187L和802.11n

    连接的弱信号,从而确保大多数检测到的信号都能成功连接。这种特性使得它在需要稳定连接的环境下非常实用。 软件兼容性:RTL8187L对破解软件的兼容性几乎完美,这意味着使用该芯片的设备在执行网络破解
    发表于 08-24 14:23

    优化 FPGA HLS 设计

    RTL代码进行任何更改即可实现的。 更高水平的性能 要达到更高的性能水平,需要在所有方面进行优化——架构设计、
    发表于 08-16 19:56