时序优化中重要的一项就是提高模块的最高工作频率,工作频率由关键路径决定,通常的提高工作频率的步骤是:利用时序分析工具找到关键路径,分析关键路径主要延迟是布线延迟还是逻辑延迟,然后轮番十八般武器,如果是逻辑延迟过大就用逻辑切割,插入D触发器,如果布线延迟太长,则复制触发器,减小负载等等,按部就班后,有时可以明显改善,但很多时候由于设计需求所限不能插入触发器,或是面积受限无法复制触发器,这些程式化的优化方法收效就甚微了,此时,该怎么办呢? 马克思爷爷曾经说过:“世上任何事物都不是孤立的,而是相互联系的,相互制约,相互作用”。受此启发,我们所看到的关键路径,并不是单单由关键路径上的逻辑决定的,而是由工程里所有的逻辑决定的,其中也包括很多和关键路径无关的逻辑。一块FPGA的资源是固定的,如果工程里的一些模块优先占用了风水宝地,剩下的模块只能将就着使用其次的资源,最终很委屈的成为了关键路径。所以,关键路径的形成可能并不是由于自身逻辑的复杂,而是好的资源被其他模块抢走了,我们可以换一换思路,不要局限于关键路径,从系统角度出发,通过简化关键路径之外模块的逻辑,提高工作频率

最有效的简化方法一般都要基于具体的工程而言,从需求,功能,实现等大方向做减法,这些方法需要很强的专业背景,不具备通用性,而我想从更具普遍性的编码风格细节入手,谈一谈好的编码风格是如何简化逻辑,提高工作频率的。本篇先来讲讲大家再熟悉不过,但又很容易被忽视的if  else。

if else在FPGA工程里可以说是无处不在,在时序逻辑里其主要可以归为两类,一类是补全if else的,主要用于选择器,如下所示,当sel_1有效输出0,sel_2有效时输出1,其他情况都输出0。

always @(posedge clk or negedge rset_n)
begin
if(!rset_n)
d <= 0;
else if(sel_1)
d <= 0;
else if(sel_2)
d <= 1;
else
d <= 0;
end

其RTL图如图一所示,很简单,就是一个选择器加一个D触发器。

图一

另一类是没有补全的if else,主要用于锁存数据,如下所示,和上例不同的是,当sel_1和sel_2无效时,输出会保持上一个状态。

always @(posedge clk or negedge rset_n)
begin
if(!rset_n)
d <= 0;
else if(sel_1)
d <= 0;
else if(sel_2)
d <= 1;
end

其RTL图如图二所示,和图一相比,多了一个选择器,并将D触发器的输出反馈到了选择器的输入端,实现锁存的功能。

图二

从上述可知,补全if else实现的逻辑会比if else不全的逻辑少一条反馈路径和一个选择器,如果是更复杂的应用,后者消耗的资源可能还会更多。

至此,如能根据具体的应用,需要选择器时使用补全的if else,需要锁存功能时,使用不全的if else,那就没有任何问题了,但是,我想重点提醒下,很多人在使用时,对这两种编码风格混淆不清,特别是在一段式状态机里,造成了不必要的浪费,拉低了最高工作频率,下面举一个工作中实际的例子。

工程需要跑到200MHz,但在优化前只有174MHz,查看关键路径如图三所示。

图三

oe_width到fast_rd_wait_fifo是当前的速度瓶颈,由于设计所限,无法在这条路径内插入D触发器,开启quartus的寄存器复制优化项,效果也不明显...常用的优化方法都试过一遍了,但都没太多疗效。按照开篇提到的马克思爷爷的"万事万物都有联系"的思路,撇开关键路径,查看工程里其他的模块是否有可以简化之处,寻找了良久,终于找到了一个貌似可以优化的状态机,截取了其中的关键代码如下。

....
case(fast_rd_state) fast_rd_st0:
begin
if(executive_cmd)
begin
fast_rd_busy <= 1;
if(!count_en)
begin
fast_rd_ok <= 0;
rdaddr_add <= 1;
fast_rd_state <= fast_rd_st1;
end
else
begin
fast_rd_ok <= 0;
rdaddr_add <= 1;
fast_rd_state <= fast_rd_st2;
end
end
else
begin
fast_rd_busy <= 0;
fast_rd_ok <= 0;
rdaddr_add <= 0;
fast_rd_state <= fast_rd_st0;
end
end fast_rd_st1:
begin
rdaddr_add <= 0;
if(rd_count_almost_full)
begin
if(fifo_wrusedw < fifo_rd_deep)
begin
fast_rd_busy <= 0;
fast_rd_ok <= 1;
fast_rd_state <= fast_rd_st0;
end
else
begin
//fast_rd_busy <= 1; /*注意这句话*/
fast_rd_ok <= 0;
fast_rd_state <= fast_rd_st3;
end
end
else
begin
//fast_rd_busy <= 1; /*注意这句话*/
fast_rd_state <= fast_rd_st1;
end
end
.....

注意红色加粗部分,优化前是没有这两句话的,所以优化前,这是一个没有补全的if else,会综合出锁存器,当初没加这两句话的原因是:从逻辑上感觉没有必要,因为从fast_rd_st0状态跳到fast_rd_st1状态后,fast_rd_busy肯定是1了,没有必要再在fast_rd_st1状态机里加上fast_rd_busy  <= 1,让其保持上一个状态的输出就可以了,而且这样还可以省两行代码,关键是实际的执行的结果完全正常。

但是,实际上根本不需要在fast_rd_st1状态锁存fast_rd_st0状态时fast_rd_busy的输出,在红色加粗处补上 fast_rd_busy  <= 1后,将状态机变成补全的if else类型后,奇迹发生了,综合频率提高到了190MHz,虽然还没达到200MHz,但相比没有补全if else的写法,提高了16MHz,再看关键路径报告如图四,oe_width到fast_rd_wait_fifo的关键路径悄无声息的消失了。

图四

这再一次的证明了马爷爷的思想是多么的神奇和伟大,没有使用任何传统的优化方式,仅仅是改变了其他逻辑的编码风格,就显著的提升了工作频率,虽然从程序上看,fast_rd_busy并不直接属于关键路径的逻辑范畴,但fast_rd_busy牵扯到的逻辑资源和关键路径的逻辑有着紧密的间接相互作用关系,继续查找频率提升的原因,用Technology map viewer查看没有补全if else的fast_rd_busy的源端逻辑资源如图五所示。

图五

再看看补全if else情况下fast_rd_busy的Technology map viewer如图六所示。

图六

比较图五和图六,前者具备锁存功能,将fast_rd_busy的输出经过复杂的判断比较逻辑又反馈到了寄存器的输入端,牵扯到的逻辑要明显多于后者,补全if else后,只有选择功能,省去了输出反馈的逻辑,整体的工作频率自然就得到了改善。

使用if else时,我们常常会因为其简单,而混淆了带锁存器和无锁存器这两种编码风格,更甚,在误用了没有补全的if else的写法后,会因其表面的逻辑功能正常和减少的代码量而觉得不以为然,其实,它都在潜移默化的影响着你工程的关键路径,赶紧看看你的工程里是否存在这些没有必要的锁存器吧,统统去掉,定有惊喜等着你奥。

优化时序之补全if else的更多相关文章

  1. VS Code Java 3月更新|代码补全、Maven 以及 Java 插件预览版本新升级!

    Nick Zhu Senior Program Manager, Developer Division at Microsoft 大家好,欢迎来到 Visual Studio Code Java 的 ...

  2. ADT开发中的一些优化设置:代码背景色、代码字体大小、代码自动补全

    初学Android开发,在网上找到一些ADT工具的优化,自己设置好了,截图保存下来.免得以后忘了. 1. 设置背景颜色: 色调85.饱和度90.亮度205 RGB:199.237.204 2. 设置代 ...

  3. eclipse自动补全的设置

    eclipse自动补全的设置   如果你用过Visual Studio的自动补全功能后,再来用eclipse的自动补全功能,相信大家会有些许失望. 但是eclipse其实是非常强大的,eclipse的 ...

  4. eclipse自动补全的设置(自动提示)

      如果你用过Visual Studio的自动补全功能后,再来用eclipse的自动补全功能,相信大家会有些许失望. 但是eclipse其实是非常强大的,eclipse的自动补全没有VS那么好是因为e ...

  5. 仿Google首页搜索自动补全

    仿Google自动补全,实现细节: 后台是简单的servlet(其实就是负责后台处理数据交互的,没必要非跌用个struts...什么的) 传输介质:xml 使用jQuery js框架 功能实现: 如果 ...

  6. IntelliJ IDEA 设置代码提示或自动补全的快捷键 (附IntelliJ IDEA常用快捷键)

    修改方法如下: 点击 文件菜单(File) –> 点击 设置(Settings- Ctrl+Alt+S), –> 打开设置对话框. 在左侧的导航框中点击 KeyMap. 接着在右边的树型框 ...

  7. (转)eclipse自动补全的设置

    如果你用过Visual Studio的自动补全功能后,再来用eclipse的自动补全功能,相信大家会有些许失望. 但是eclipse其实是非常强大的,eclipse的自动补全没有VS那么好是因为ecl ...

  8. jupyter notebook安装/代码补全/支持golang 踩坑记

    安装(不要用root) 安装anaconda3,然后ln -s bin目录下的jupyter命令到/usr/bin目录下 生成密码备用 敲ipython进入交互终端 In [1]: from note ...

  9. ES系列十三、Elasticsearch Suggester API(自动补全)

    1.概念 1.补全api主要分为四类 Term Suggester(纠错补全,输入错误的情况下补全正确的单词) Phrase Suggester(自动补全短语,输入一个单词补全整个短语) Comple ...

随机推荐

  1. pyftpdlib 搭建ftp环境

    环境搭建: pythonwindows/linuxpip install pyftpdlib (安装失败请到这里下载:https://pypi.python.org/pypi/pyftpdlib/)一 ...

  2. GDOI2016酱油记(补发)

    这篇酱油记是前年发在MCHacker一个叫code-hub的博客上的(已崩),现在来补发一下... GDOI2016扯淡(爆零记) 大家好,我是巨弱DCDCBigBig,在五一期间和一群神牛去考GDO ...

  3. Laravel核心解读--ENV的加载和读取

    Laravel在启动时会加载项目中的.env文件.对于应用程序运行的环境来说,不同的环境有不同的配置通常是很有用的. 例如,你可能希望在本地使用测试的Mysql数据库而在上线后希望项目能够自动切换到生 ...

  4. BNUOJ 36005 Chemical Reaction

    Chemical Reaction Time Limit: 3000ms Memory Limit: 65536KB This problem will be judged on OpenJudge. ...

  5. Lucene3.6.2包介绍,第一个Lucene案例介绍,查看索引信息的工具lukeall介绍,Luke查看的索引库内容,索引查找过程

    2.Lucene3.6.2包介绍,第一个Lucene案例介绍,查看索引信息的工具lukeall介绍,Luke查看的索引库内容,索引查找过程 2014-12-07 23:39 2623人阅读 评论(0) ...

  6. SQL的四种语言:DDL、DML、DCL、TCL

    1. DDL(Data Definition Language) 数据库定义语言statements are used to define the database structure or sche ...

  7. Java IO(二) 之 InputStream

    源代码均以JDK1.8作为參考 前言: InputStream实现了两个接口Closeable和AutoCloseable: Closeable:JDK1.5中引入,Closeable接口中仅仅有一个 ...

  8. SDUTOJ 2776 小P的故事——奇妙的分组

    #include<iostream> #include<math.h> #include<memory.h> using namespace std; int dp ...

  9. 验证备份集-使用DBVERIFY工具

    DBVERIFY确认备份集是否存在坏块 验证TEST03.DBF 文件的是否存在坏块 C:\Documents and Settings\Administrator>dbv file=D:\or ...

  10. java 通过httpclient调用https 的webapi

    java如何通过httpclient 调用采用https方式的webapi?如何验证证书.示例:https://devdata.osisoft.com/p...需要通过httpclient调用该接口, ...