文章内容部分转自:https://blog.csdn.net/angelbosj/article/details/52921563
<https://blog.csdn.net/angelbosj/article/details/52921563> and
http://bbs.21ic.com/forum.php?mod=viewthread&tid=1246732
<http://bbs.21ic.com/forum.php?mod=viewthread&tid=1246732>

为什么要进行管脚约束。
刚做项目的时候,往往会忽略IO口的约束。每次稍微改动一些东西,就会发现 编译的结果不是自己想要的。 这样的现象一般来说,就是时序有问题。 一般
逻辑代码的约束还好做, IO口的约束有些麻烦。

解释一一堆名词。


通常看到的UART,SPI,I2C,PCI,LocalBus。还有一些就专业一些,例如UTOPIA,CPRI,POS-PHY,还有以太网里的各种MII接口。一个接口一出现在我们的脑海里,我们可能就会想这个接口有几根信号线,能跑多高频率,适合于哪种场合。很多人看到自己没搞过的接口就会有些莫名的紧张,担心自己对接口的理解不够,设计时会出差错。在我的理解里,接口从低级到高级,是有一些规律的,掌握了这个规律,你至少会对各种接口大致做到心中有数,新接口来了也不至于慌乱。且不论一个接口的状态机转换有多复杂,单从接口的时钟和数据交互来看,我以为下面的分类方法能让大家更好地理解接口。


第一类是异步接口。最典型的异步接口就是最常用的UART口。接口是用来在两个模块之间传递信号,异步接口最大的特点就是没有互传时钟。举一个通俗的例子来解释,比如我要把很多苹果传给周润发,如果我们之间是异步接口,那就相当于我们都看着自己的手表作动作。每隔一个固定的时间,我就传一个苹果过去,同样每隔相同的时间,周润发把苹果拿走。这就带来了一个问题,就是不能传的太快。因为表都有误差。我每隔1分钟传一个,这肯定没有问题,但要每隔1ns传一个,那肯定崩溃了。所以我们看到UART的频率,9600正常,115200就算快的。现在很多芯片支持USART,就是要突破这个限制。把异步改成同步。


第二类是同步接口。同步接口是数字电路的一个巨大的进步。还是以我和周润发传苹果为例,现在不是两个表了,而是我和周润发都看着墙上的钟,我们参照同一个时钟在传苹果。这样每传一个苹果,我跟发哥的动作都是同步的。同步接口的典型例子就是pci接口,这是一个垄断了高大上接口界好多年的接口。在一个pci-clock的上升沿master把数据打出来,slave在下一个时钟周期把数据收回去,可能有人要问,为什么不是同一个clock呢?我要告诉大家,这是同步接口的一个特点。在一个时钟的上升沿,master在把数据打出来的时候,slave还没有收到,因为数据传输是有延迟的。同步接口的频率可以上的比较高,pci有33M,66M,compact
pci可以上到133M。但同步接口同样也有硬伤,就是slave的发送也要依赖于master的时钟,那slave发出和master接收就会有个时间差,如果slave和master的传输距离太长,时序就很难保证了,这是同步接口无法解决的。其实I2C,SPI等接口,都可以看作同步接口,速度都不会太快。问题提出来了,总有解决之道。解决同步接口问题的招,就是把同步接口变成源同步接口。多了一个源字,问题就引刃而解了。


第三类是源同步接口。源同步接口最大的特点就是数据和时钟是同源的,发出数据的同时总是带着时钟,对端用收到的时钟采样收到的数据。显而易见,如果走线的时候是等长的,那理论上永远也不会有时序的问题了。通俗一点,还是以我和周润发传苹果为例,如果我们是源同步的,那就不用看自己的手表了,也不用两个人同时看墙上的钟,而是我在传苹果的时候叫一声发哥,发哥听到了再接苹果,发哥传给我的时候也叫一声。这样就不会有问题了。

我举一个的例子,大家可能就更明白了。大家都用过DRAM芯片,在SDR
SDRAM时代,全部接口都靠CLK信号,这其实是一个同步接口,不管控制器还是DRAM颗粒,都以CLK为准。所以我们看到SDR
SDRAM的频率也一般也只到133M。到了DDR
SDRAM时代,我们发现这个接口多出来一个DQS信号,这与我们通常的理解不符合,为什么非但不精简,还越搞越复杂了呢?这个信号是干嘛的呢?这个信号是采样数据用的。而且写的时候由DRAM控制器发出,读的时候由DRAM颗粒发出,讲到这大家明白了吧。有了DQS信号,DRAM的接口已经由同步接口转变成了源同步接口,速度大幅度提升,DDR3,DDR4的时钟频率已经可以上到1G以上了。

其实从硬件设计的角度看接口,我们总是在头疼两样东西,一个是时序,另一个就是信号质量。刚才说了源同步可以解决时序的问题,那搞好信号质量靠什么法宝呢?搞过仿真的朋友可能知道,一对多的仿真,即使拿到的模型基本是准确的,我们也会花很多时间去搞拓扑结构,星型?Y型?stub多长?搞得浑身不自在。啥时候就不用搞这些呢?答案就是点对点的时候,点对点就是搞好信号质量的法宝。

还是以DRAM为例,从DDR2升到DDR3的时候,由于速率上去了,信号质量成了当务之急,特别是一对多的Clock信号。JEDEC推荐了一种方式叫Fly-By,
这种方式其实就是一种伪点对点的拓扑,保证了stub最短。说到这,我们自然会想,有没有一个接口方式,它即是源同步,又是点对点呢?答案是有的,它就是Serdes。


第四类就是Serdes,也就是接口物理层的串行化。它既是源同步,同时也是点对点。Serdes的发送端把数据和时钟编在一起,在一对差分线上发送出去,到对端再依赖CDR把两者分开,用CDR恢复出的时钟采样恢复出的数据。目前商用的Serdes已经有25G基带波特率,传输的带宽大幅度提升。其实接口Serdes化已经悄然在我们身边发生了很多年,只是有的人没有注意而已。
以前我们用IDE硬盘,现在都是SATA硬盘。以前我们用VGA,DVI,现在是HDMI。USB3.0也增加了serdes链路。包括信号数目超级多的TCAM接口,现在也慢慢变成了Interlaken,Serdes化了。哪天Serdes价钱便宜了,DRAM搞个串行化也说不定呢。

那么源同步接口怎么在Vivado里进行约束呢?

input_delay.


在我们的设计中 setup 为2.5ns. hold on为 2.0ns,时钟周期是 13.468ns. 在不考虑 时钟
有jitter跟skew的存在,那么 在 vivado 里面应该这么设置。



那么 在xdc 文件中会出现 这样的Input delay 约束。
set_input_delay -clock [get_clocks clk_mstar] -min -add_delay 2.000 [get_ports
{din_mstar[*]}] set_input_delay -clock [get_clocks clk_mstar] -max -add_delay 10
.968 [get_ports {din_mstar[*]}] set_input_delay -clock [get_clocks clk_mstar]
-min -add_delay 2.000 [get_ports de_mstar] set_input_delay -clock [get_clocks
clk_mstar] -max -add_delay 10.968 [get_ports de_mstar] set_input_delay -clock
[get_clocks clk_mstar] -min -add_delay 2.000 [get_ports vsync] set_input_delay
-clock [get_clocks clk_mstar] -max -add_delay 10.968 [get_ports vsync]
关于 Output delays 设置。

在 vivado 中, 关于 时钟的输出,一定要用 ODDR 。这样才会出现 Forwarded Clocks.
ODDR #( .DDR_CLK_EDGE("SAME_EDGE"), .INIT(1'b0), .SRTYPE("SYNC") )
ODDR_inst_a ( .Q(IDCK_OUTA), .C(clk_out_a), .CE(1'b1), .D2(1'b1), .D1(1'b0),
.R(1'b0), .S(1'b0));
时钟周期 是 6.734ns. 下游芯片的 setup 是 1.5ns , hold on 是 1ns. 假如 数据 和 时钟的 pcb 布线是 严格等长的。



这时候 xdc文件中会出现这样的约束。
set_output_delay -clock [get_clocks IDCK_2_OUTA] -min -add_delay -1.000
[get_ports {D_OUTE[*]}] set_output_delay -clock [get_clocks IDCK_2_OUTA] -max
-add_delay 1.500 [get_ports {D_OUTE[*]}]
这样 input 和 output 的时序约束,基本上就做好了!!!!