原创 【转】FPGA为什么跑不快

2015-5-2 16:49 2112 13 15 分类: FPGA/CPLD

  

  1. </pre><p>以Quartus为例(延时数据为Stratix III器件典型延时)</p><p>手动布局:</p><p></p><pre name="code" class="cpp"><span style="font-family: Arial, Helvetica, sans-serif;">module top(input clk,din,output dout);</span>  

</pre><p>以Quartus为例(延时数据为Stratix III器件典型延时)</p><p>手动布局:</p><p></p><pre name="code" class="cpp"><span style="font-family: Arial, Helvetica, sans-serif;">module top(input clk,din,output dout);</span>

[cpp] view plaincopyprint?

  1. reg din_ff,din_ff2;  
  2.   
  3. always@(posedge clk)  
  4.    begin  
  5.              din_ff  <= din;  
  6.              din_ff2 <= din_ff;  
  7.    end  
  8.   
  9. assign dout = din_ff2;  
  10.   
  11. endmodule  

reg din_ff,din_ff2;

 

always@(posedge clk)

   begin

             din_ff  <= din;

             din_ff2 <= din_ff;

   end

 

assign dout = din_ff2;

 

endmodule


忽略IO时序,怎样使这个电路跑到最快?在FPGA中线延时占主导,因此我们首先需要把din_ff和din_ff2两个寄存器邻近摆放。在Assignment Editor中,新增Location规则,目标选择din_ff或din_ff2,位置选择“LAB”,再选择你希望的LAB坐标(在此例中具体坐标在哪不重要)。将这两个寄存器摆到同一个LAB内,就实现了数据路径上的最优化。 这就是所谓的“手动布局”。

一个寄存器的Tsu/Th大概是50ps,Tco大概85ps,同一个LAB的互联延时大概200ps,忽略Minimum Pulse Width约束,是否意味着这个电路的最小周期是335ps即能跑3GHz呢?注意,此时数据路径上已经没有瓶颈了。

****************........我是分割线.......*****************


::基于OCV的fmax计算::
查看Timequest报告,你会发现报出的fmax远小于期望的3GHz,为什么呢?


在Quartus自动PR时,时钟通常会被拉到全局缓冲CLKCTRL(这有时是不可避免的,如PLL输出),再拉到每个DFF。虽然全局时钟到每个DFF的平均Skew较小,但绝对延时是比较大的(ns级)。而Timequest的分析是基于OCV的(简单来说,就是所有延时都有min和max),延时的绝对值越大,min和max的差值也越大。比如,假定CLKCTRL出来的延时如下:

[cpp] view plaincopyprint?

  1. CLKCTRL -> din_ff|clk  平均延时2ns(min 1.5ns,max 2.5ns)  
  2. CLKCTRL -> din_ff2|clk 平均延时2ns(min 1.5ns,max 2.5ns)  
  3.    

CLKCTRL -> din_ff|clk  平均延时2ns(min 1.5ns,max 2.5ns)

CLKCTRL -> din_ff2|clk 平均延时2ns(min 1.5ns,max 2.5ns)

 

工具先修Hold Time,din_ff到din_ff2的最快路径为(我们假定Tco(min)+线延时(min)-Th =250ps):

[cpp] view plaincopyprint?

  1. Data(early):CLKCTRL ----1.5ns----> din_ff|clk ----250ps----> din_ff2|d  
  2.    

Data(early):CLKCTRL ----1.5ns----> din_ff|clk ----250ps----> din_ff2|d

 

din_ff2的最慢时钟路径为:

[cpp] view plaincopyprint?

  1. Clock(late):CLKCTRL ----2.5ns----> din_ff2|clk   
  2.    

Clock(late):CLKCTRL ----2.5ns----> din_ff2|clk

 

(1.5ns+250ps<2.5ns)此时工具发现需要在din_ff后面插750ps(min)的Buffer才能使Hold Time无违规(FPGA中不插Delay Cell,一般是绕线)。插完Buffer后,我们来看看此时能达到的最小周期(计算Setup Time):
din_ff到din_ff2的最慢路径为(我们假定Tco(max)+线延时 (max)+Tsu = 350ps,插的Buffer(max)=950ps):

[cpp] view plaincopyprint?

  1. Data(late): CLKCTRL ----2.5ns----> din_ff|clk ----350ps+950ps=1.3ns----> din_ff2|d   
  2.    

Data(late): CLKCTRL ----2.5ns----> din_ff|clk ----350ps+950ps=1.3ns----> din_ff2|d

 

din_ff2的最快时钟路径为:

[cpp] view plaincopyprint?

  1. Clock(early): CLKCTRL ----1.5ns----> din_ff2|clk  
  2.    

Clock(early): CLKCTRL ----1.5ns----> din_ff2|clk

 

数据路径相对于时钟的延时为(2.5ns+1.3ns-1.5ns=2.3ns),所以最小时钟周期2.3ns,对应fmax为435MHz,与一开始预测的3GHz差别巨大。

细心的朋友会发现,这个最小周期值非常接近于CLKCTRL延时(max-min)的两倍。

****************........我是分割线.......*****************

::手动时钟树 -- 创建共同时钟路径::

OCV的计算引擎会对共同时钟路径不计算min/max,因为物理上同一段路径的延时是固定的,这个在Quartus中称为CCPP,在Cadence中称为CPPR,在Synopsys中称为CRPR。。。

既然CLKCTRL延时巨大,那我们可以在CLKCTRL到两个寄存器这段路径上创建共同时钟路径,减小CLKCTRL延时(max-min)对时序的冲击。我们对原代码作以下修改:

[cpp] view plaincopyprint?

  1. module top(input clk,din,output dout);  
  2.   
  3. wire clk_buf/*synthesis keep*/;  
  4. assign clk_buf = clk;  
  5. reg din_ff,din_ff2;  
  6.   
  7. always@(posedge clk_buf)  
  8.    begin  
  9.              din_ff  <= din;  
  10.              din_ff2 <= din_ff;  
  11.    end  
  12.   
  13. assign dout = din_ff2;  
  14.   
  15. endmodule  

module top(input clk,din,output dout);

 

wire clk_buf/*synthesis keep*/;

assign clk_buf = clk;

reg din_ff,din_ff2;

 

always@(posedge clk_buf)

   begin

             din_ff  <= din;

             din_ff2 <= din_ff;

   end

 

assign dout = din_ff2;

 

endmodule

通过Location规则把clk_buf节点放在与两个寄存器同一个LAB内,取得最大的共同时钟路径和最小的分离时钟路径。此时再计算一下Hold Time(假定clk_buf到寄存器时钟端的延时min=300ps,max=400ps):

[cpp] view plaincopyprint?

  1. Data(early):clk_buf ----300ps----> din_ff|clk ----250ps----> din_ff2|d  
  2. Clock(late):clk_buf ----400ps----> din_ff2|clk   

Data(early):clk_buf ----300ps----> din_ff|clk ----250ps----> din_ff2|d

Clock(late):clk_buf ----400ps----> din_ff2|clk

(300ps+250ps>400ps)可见Hold Time无违规,不需要插Buffer。此时计算Setup余量:

[cpp] view plaincopyprint?

  1. Data(late):clk_buf ----400ps----> din_ff|clk ----350ps----> din_ff2|d  
  2. Clock(early):clk_buf ----300ps----> din_ff2|clk   

Data(late):clk_buf ----400ps----> din_ff|clk ----350ps----> din_ff2|d

Clock(early):clk_buf ----300ps----> din_ff2|clk

数据路径相对延时为(400ps+350ps-300ps=450ps),如不考虑Minimum Pulse Width约束,则最小周期450ps,fmax为2.2GHz。这就是手动时钟树 -- 创建共同时钟路径的威力。

****************........我是分割线.......*****************

::手动时钟树 -- 手动Skew调整::

Quartus的Fitter中有很多优化Clock Skew的选项,其实选了根本没有任何效果。。。Quartus自动PR对时钟的优化就是这么弱。


我们还能进一步对时序进行优化,那就是Clock Skew手工调整,平衡(Tco+线延时+Tsu/-Th)那段250ps~350ps的数据延时。代码继续修改如下:

[cpp] view plaincopyprint?

  1. module top(input clk,din,output dout);  
  2.   
  3. wire clk_buf/*synthesis keep*/;  
  4. wire clk_buf2/*synthesis keep*/;  
  5. assign clk_buf = clk;  
  6. assign clk_buf2 = clk_buf;  
  7. reg din_ff,din_ff2;  
  8.   
  9. always@(posedge clk_buf)  
  10.    din_ff  <= din;  
  11.   
  12. always@(posedge clk_buf2)  
  13.    din_ff2 <= din_ff;  
  14.   
  15. assign dout = din_ff2;  
  16.   
  17. endmodule  

module top(input clk,din,output dout);

 

wire clk_buf/*synthesis keep*/;

wire clk_buf2/*synthesis keep*/;

assign clk_buf = clk;

assign clk_buf2 = clk_buf;

reg din_ff,din_ff2;

 

always@(posedge clk_buf)

   din_ff  <= din;

 

always@(posedge clk_buf2)

   din_ff2 <= din_ff;

 

assign dout = din_ff2;

 

endmodule

假定clk_buf到clk_buf2的延时为250ps~300ps(如需更大Skew,在SDC中用set_net_delay -min/max对clk_buf到clk_buf2的延时进行约束即可):

[cpp] view plaincopyprint?

  1. Data(early):clk_buf ----300ps----> din_ff|clk ----250ps----> din_ff2|d  
  2. Clock(late):clk_buf ----300ps----> clk_buf2 ----400ps----> din_ff2|clk   

Data(early):clk_buf ----300ps----> din_ff|clk ----250ps----> din_ff2|d

Clock(late):clk_buf ----300ps----> clk_buf2 ----400ps----> din_ff2|clk

(300ps+250ps<300ps+400ps)可见Hold Time违规,工具需要插150ps(min)的Buffer。假设Buffer的延时为150ps~200ps,此时计算Setup余量

[cpp] view plaincopyprint?

  1. Data(late):clk_buf ----400ps----> din_ff|clk ----350ps+200ps----> din_ff2|d  
  2. Clock(early):clk_buf ----250ps----> clk_buf2 ----300ps----> din_ff2|clk   

Data(late):clk_buf ----400ps----> din_ff|clk ----350ps+200ps----> din_ff2|d

Clock(early):clk_buf ----250ps----> clk_buf2 ----300ps----> din_ff2|clk

(400ps+350ps+200ps-250ps-300ps=400ps), 如不考虑Minimum Pulse Width约束, 则最小周期缩短到400ps,fmax可达2.5GHz。

这就是手动时钟树 -- 手动Skew调整,这个手段在优化对外控制器模块时非常有用,用于平衡内部时钟输出到Pad的巨大延时。

****************........我是分割线.......*****************

在顶楼的DDR2-1066控制器实现过程中,大量应用了“手动布局、手动时钟树 -- 创建共同时钟路径、手动时钟树 -- 手动Skew调整”三项PR技术,使得用内部ALUT搭的控制器/PHY电路,最高频率得以赶超片内硬核。

 

PARTNER CONTENT

文章评论2条评论)

登录后参与讨论

用户1777274 2016-2-24 08:33

楼主有没有根据这个实际操作过啊,为什么我根据上面说的还是一样的跑不快。。。求教

用户1668914 2015-5-10 22:53

大神,我想补一补这方面的知识,有什么什么推荐的资料?
相关推荐阅读
sunyzz 2017-08-19 10:38
【博客大赛】AVALON总线介绍
1、AVALON总线简介Avalon总线是一种协议较为简单的片内总线,是ALTERA公司定义的片上互联总线,该总线可以将诸如NIOS II的CPU与其他外设连接起来,进而进行数据交换。AVALON总线...
sunyzz 2017-08-17 21:36
【博客大赛】不要轻易做职场滥好人
小A毕业于国内普通高校,但是他聪明,勤奋,能干,动手能力强,可是即便有这些优点也不能让小A轻轻松松找到一份好工作。这不,去年9月份小A好不容易找到一份工作,然后立马就入职了C公司,生怕C公司过两天不要...
sunyzz 2017-08-16 21:15
【博客大赛】IC设计低功耗技术四
五:工艺层面的降低功耗前面几节都是在讨论设计人员如何在前期阶段,中期阶段降低功耗,涉及到软件层面的,硬件层面的,这些技巧基本都是前辈总结出来的,或者根据理论推论出来的。但是到了后期,想降低功耗基本就要...
sunyzz 2017-08-14 22:35
【博客大赛】IC设计之低功耗技术三
四:RTL(寄存器传输)级的低功耗设计4.1 状态机的设计状态机编码中一般有两种方式,普通的二进制编码,特殊的格雷码,格雷码的特点是两个数据之间的跳变时只会有一个bit在toggle,显然比起多bit...
sunyzz 2017-08-12 16:51
【博客大赛】IC设计之低功耗技术二
三、架构层面的降低功耗系统的实现有很多的方式,每种方式对功耗的影响都不相同,本节主要介绍架构对功耗的影响。3.1 高级门口电路 在同步电路系统中,时钟占据了大部分的动态功耗,因而在一些情况下,如果有些...
sunyzz 2017-08-12 10:37
【博客大赛】IC 设计之低功耗技术一
一、前言随着计算机技术和微电子技术的迅速发展,嵌入式系统应用领域越来越广泛。节能是全球化的热潮,如计算机里的许多芯片过去用5V供电,现在用3.3V,1.8V,甚至更低的电压。目前的低功耗设计主要从芯片...
EE直播间
更多
我要评论
2
13
关闭 站长推荐上一条 /3 下一条