|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
最常用的约束有IO管脚位置约束和电平幅度约束,这个很好理解。另外,就是对时钟网络约束。这个是很重要的。比如你的系统中,驱动的电路的时钟是27M的,那么你需要在约束文件中增加类似如下的约束语句1 J4 ^1 V" t5 a6 f
NET REF_CLK27M TNM_NET = REF_CLK27M_grp;
# ?7 Z" p/ e7 H' ~3 RTIMESPEC TS_REF_CLK27M = PERIOD REF_CLK27M_grp : 37ns HIGH 50 %;6 p* u/ {9 e- N# X U
这样的话,工具在布线的时候,就会知道这个时钟所驱动的所有网络必须满足至少27M速度的要求,占空比为50%。它会任意布线,就有可能出现信号翻转的很慢,或者延时很长,建立时间保持时间不足,在实际中造成timing错误。一般来说,十几兆以上的时钟网络最好都加类似的约束,在时钟上就可以了,工具会帮你把它所驱动的所有网络都加上约束的。7 j7 D) Q G% p% A/ ?% @8 W/ @
另外,常用的约束还有delay,skew等,具体的你可以到Xilinx网站上下载专门有关Constains的文档学习一下。* i3 ~# B: l3 [0 x4 I6 [( N3 ^6 Y1 f
我们将问题分解为2部分,来自同步时钟域信号的处理和来自异步时钟域信号的处理。前者要简单许多,所以先讨论前者,再讨论后者。7 m. s- F4 g3 E7 j+ z
( Q1 Y% t# `& h; ]
1.同步时钟域信号的处理# j( g) c2 Z! m: L! G) z
一般来说,在全同步设计中,如果信号来自同一时钟域,各模块的输入不需要寄存。只要满足建立时间,保持时间的约束,可以保证在时钟上升沿到来时,输入信号已经稳定,可以采样得到正确的值。但是如果模块需要使用输入信号的跳变沿(比如帧同步信号),千万不要直接这样哦。9 Q% i g; X9 j7 H4 t9 [" ?, I
always @ (posedge inputs); w' n8 y1 _- ?6 C9 i2 C
begin% z: y8 |4 B/ f4 R2 N' g
...8 Y. u/ X; R: N4 X) m' c- X% S$ z
end
, x5 h* f3 h; f* A9 c- }因为这个时钟inputs很有问题。如果begin ... end语句段涉及到多个D触发器,你无法保证这些触发器时钟输入的跳变沿到达的时刻处于同一时刻(准确的说是相差在一个很小的可接受的范围)。因此,如果写出这样的语句,EDA工具多半会报clock skew > data delay,造成建立/保持时间的冲突。本人曾经也写出过这样的语句,当时是为了做分频,受大二学的数字电路的影响,直接拿计数器的输出做了后面模块的时钟。当初用的开发工具是max+plusII,编译也通过了,烧到板子上跑倒也能跑起来(估计是因为时钟频率较低,6M ,但后来拿到QuartusII中编译就报clock skew > data delay。大家可能会说分频电路很常见的啊,分频输出该怎么用呢。我一直用的方法是采用边沿检测电路,用HDL语言描述大概是这样:
( P% I3 j( I' ~9 X( L" @0 {always @ (posedge Clk) / L) Q0 W; f$ M7 i4 b
begin: _& W" b% _, R' J. Z
inputs_reg <= inputs;
% f7 E- _' t, Pif (inputs_reg == 1'b0 && inputs == 1'b1)( x9 @1 O- o4 Q2 ?8 f% ]
begin( ~0 Z. W* ~/ r) M
...
% V6 K) ]1 l4 ^% s& tend
' g6 R0 {! w" D% t8 Z...
, t K. H8 ]0 ~2 E, J h' cend
+ J- Z: J" n$ Z3 \" D% Y8 q' i, F这是上跳沿检测的电路,下跳沿电路大家依此类推。6 x, }- v9 o% P* U3 c3 O: `$ @% u/ ]
% Q8 z3 W0 v3 d# b$ r( n% N+ E+ p
2.异步时钟域信号的处理% o/ ~5 B4 c$ a- R3 A
这个问题也得分单一信号和总线信号来讨论。
. a: Z' e: D, q; s" L- e H2 H# C
9 U0 ~+ q! {9 Y2 | l2.1单一信号(如控制信号)的处理3 ~$ [1 e5 }2 b; V
如果这个输入信号来自异步时钟域(比如FPGA芯片外部的输入),一般采用同步器进行同步。最基本的结构是两个紧密相连的触发器,第一拍将输入信号同步化,同步化后的输出可能带来建立/保持时间的冲突,产生亚稳态。需要再寄存一拍,减少(注意是减少)亚稳态带来的影响。这种最基本的结构叫做电平同步器。
# g$ }6 J6 r2 ]* Q8 O6 F
+ T3 r W5 v9 n6 f如果我们需要用跳变沿而不是电平又该怎样处理呢,还记得1里面讲的边沿检测电路么?在电平同步器之后再加一级触发器,用第二级触发器的输出和第三级触发器的输出来进行操作。这种结构叫做边沿同步器。
. P3 [5 Q8 l6 F h2 A7 U+ |always @ (posedge Clk)
- t6 f4 ]0 r5 J" g( sbegin5 |- t7 ^, Z* S* w4 O1 y) ]
inputs_reg1 <= inputs;7 V9 \& V, h( o2 Y |
inputs_reg2 <= inputs_reg1;- C- P1 Q* k% z; n, k( ?+ E7 |# D7 p
inputs_reg3 <= inputs_reg2;
# p0 T/ @" J: i/ Uif (inputs_reg2 == 1'b1 && inputs_reg3 == 1'b0)
( X. Q) }4 r0 X" B8 f) w+ Kbegin
, H5 E* t! e. ?; e$ V...
2 J* N) Z( F8 Z% qend; q9 }+ B1 }4 ^) ~
...
* ^, Y+ } i4 Z" V$ G1 `3 Wend/ N0 M. H" _& x+ T
1 a: B$ ~* _6 Z7 ~3 W" q0 R
以上两种同步器在慢时钟域信号同步入快时钟域时工作的很好,但是反过来的话,可能就工作不正常了。举一个很简单的例子,如果被同步的信号脉冲只有一个快时钟周期宽,且位于慢时钟的两个相邻跳变沿之间,那么是采不到的。这时就需要采用脉冲同步器。这种同步器也是由3个触发器组成,同时需要对发送信号做一些处理,具体结构大家可以在网上搜。
. l( z6 b5 d5 {% B, C: ~( E$ C) n5 z5 Y! y, c. |
2.2总线信号的处理+ k" B# X% y8 `- _% P: z6 I4 s$ s
如果简单的对异步时钟域过来的一组信号分别用同步器的话,那么对这一组信号整体而言,亚稳态出现的几率将大大上升。基于这一观点,对于总线信号的处理可以有两种方式。: G4 @% y& y% Z* d$ N6 J/ j
& k+ [/ C" [( ^4 Y+ P% a: ]
如果这组信号只是顺序变化的话(如存储器的地址),可以将其转换为格雷码后再发送,由于格雷码相邻码字只相差一个比特,上面说的同步器可以很好的发挥作用。! D6 v$ u0 I) _" q
; t& ~9 H2 K4 J+ L但是如果信号的变化是随机的(如存储器的数据),这种方法便失效了,这时可以采用握手的方式或者采用FIFO或DPRAM进行缓存。RAM缓存的方式在突发数据传输中优势比较明显,现在高档一点的FPGA中都有不少的BlockRAM资源,且支持配置为DPRAM或FIFO,这种处理方法在通信电路中非常常用。1 A9 f6 I7 w3 `5 V3 b8 ~6 Q
|
|