tag 标签: fpga,时序优化

相关博文
  • 热度 15
    2012-6-2 20:07
    2118 次阅读|
    6 个评论
      时序优化中重要的一项就是提高模块的最高工作频率,工作频率由关键路径决定,通常的提高工作频率的步骤是:利用时序分析工具找到关键路径,分析关键路径主要延迟是布线延迟还是逻辑延迟,然后再轮番十八般武器,如果是逻辑延迟过大就用逻辑切割,插入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_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的写法后,会因其表面的逻辑功能正常和减少的代码量而觉得不以为然,其实,它都在潜移默化的影响着你工程的关键路径,赶紧看看你的工程里是否存在这些没有必要的锁存器吧,统统去掉,定有惊喜等着你奥。