文章来源:FPGA技术联盟
1、IDDR是什么?
IDDR是Xilinx7系列FPGA的一个底层原语,它的功能就是把输入的双沿信号转换为单沿信号输出给FPGA内部逻辑进行使用,即完成输入的DDR信号到输出的SDR信号的转换。需要注意的是,它只能在IO管脚上使用,不能在FPGA内部逻辑使用,也就是说只能通过管脚(IO Pad)把外部输入到FPGA的双沿信号转换成单沿信号。
在讲解IDDR使用前,最好先了解ILOGICE的结构及功能。
ILOGIC位于IOB(IO BLOCK)旁边,ILOGIC块包含同步元件,用于在数据通过IOB进入FPGA时捕获数据。7系列芯片中ILOGIC可以是ILOGICE2(HP I/O bank)或ILOGICE3(HR I/O bank)。
ILOGICE2和ILOGICE3唯一区别是ILOGICE3有零保持延迟元件(ZHOLD自动与内部时钟分配延迟相匹配,并且在使用时确保焊盘到焊盘的保持时间为零),ILOGICE3模块在输入上支持可选的静态未补偿零保持 (ZHOLD) 延迟线,以补偿时钟插入延迟。ZHOLD默认启用,除非时钟源是MMCM或PLL,或者在Xilinx设计约束 (XDC)中设置了IOBDELAY属性。
因为ILOGIC不是基本元件,所以用户不能通过代码去对ILOGIC进行例化。但ILOGIC包含一些可以被用户实例化的元件,例如布局和布线后的输入触发器或IDDR等。
上面蓝色方框内的器件其实就是IDDR原语了,不过它还可以被配置成:
FF触发器
LATCH锁存器
输入信号D,可以通过红色信号线直接进入FGPA的内部逻辑,代表此时不需要使用ILOGIC这个模块。如果需要使用ILOGIC模块内的功能,则会走绿色的路线。
2、IDDR的使用
IDDR的功能就是将双沿采样的数据转换为单沿数据传输给FPGA内部进行使用。
FPGA内部的D触发器一般都是在时钟上升沿去采集输出数据,这种方式被称为SDR。为了提高数据传输速率,推出了DDR,在时钟的上升沿和下降沿都能传输数据,同样时钟频率下,速率可以提升一倍,这种传输数据的方式就是双沿传输,这种方式一般都只存在接口部分,内部电路采用双沿会比较麻烦,所以会转换为单沿进行处理,FPGA调用IDDR原语即可实现。
下图是IDDR的原语框图:
IDDR原语的输入输出信号如下表所示:
IDDR原语除了输入输出信号端口外,还有几个参数端口需要配置,其使用说明如下:
一般把DDR_CLK_EDGE参数设置为SAME_EDGE_PIPELINED模式,其余参数可以不进行设置,保持默认即可。IDDR 原语支持三种操作模式:
OPPOSITE_EDGE模式
SAME_EDGE模式
SAME_EDGE_PIPELINED模式
2.1、OPPOSITE_EDGE模式
下图是该模式对应的时序图:
输入D是双沿信号,Q1和Q2是单沿的输出数据。
Q1在当前时钟上升沿采样,然后在同一个沿(上升沿)输出;Q2在当前时钟下降沿采样,然后在同一个沿(下降沿)输出。可以看到Q2的数据是要落后Q1半个时钟周期的,所以这种方式一般比较少用。
2.2、SAME_EDGE模式
下图是该模式对应的时序图:
Q1在当前时钟上升沿采样,然后在同一个沿(上升沿)输出;Q2也在当前时钟上升沿采样,然后在同一个沿(上升沿)输出,但是Q2的输出比Q1的输出要晚一拍。同样的,这种方式也比较少用。
2.3、SAME_EDGE_PIPELINED模式
下图是该模式对应的时序图:
Q1和Q2都在当前时钟上升沿采样,然后都在下一个沿(上升沿)输出。二者的输出在同一个周期,但是会落后输入数据一拍,这种方式在实践中比较常用。
3、对IDDR的仿真分析
在vivado中获取原语模板的方法如下图所示,在Tools选项卡下点击Language Templates,然后搜索 IDDR :
把模板复制到自己的工程,然后按要求更改即可,这里我要对IDDR进行测试的一个模块,很简单,就只例化了一个IDDR模块:
接着写个TB来对IDDR的三种模式进行验证,随机生成双沿输入,观察单沿输出是否符合预期:
3.1、OPPOSITE_EDGE模式的仿真结果
把DDR_CLK_EDGE参数设置为 "OPPOSITE_EDGE" ,观察仿真结果:
Q1在当前时钟上升沿采样,然后在同一个沿(上升沿)输出;Q2在当前时钟下降沿采样,然后在同一个沿(下降沿)输出。而且Q2的数据落后Q1半个时钟周期,和预期一致。
3.2、SAME_EDGE模式的仿真结果
把DDR_CLK_EDGE参数设置为 "SAME_EDGE" ,观察仿真结果:
Q1在当前时钟上升沿采样,然后在同一个沿(上升沿)输出;Q2也在当前时钟上升沿采样,然后在同一个沿(上升沿)输出。但是Q2的输出比Q1的输出要晚一拍,和预期一致。
3.3、SAME_EDGE_PIPELINED模式
把DDR_CLK_EDGE参数设置为 "SAME_EDGE_PIPELINED" ,观察仿真结果:
Q1和Q2都在当前时钟上升沿采样,然后都在下一个沿(上升沿)输出。二者的输出在同一个周期,但是会落后输入数据一拍,和预期一致。
4、IDDR在FPGA底层的布局和布线
把工程综合、实现后,打开实现后的网表,然后点击Device界面,可以看到FPGA的硬件资源和布线情况:
先找到输入信号din,它的布线如下,黄框内就是常说的IOB,它由PAD(就是管脚),IBUF(输入缓冲,对于输入管脚会自动添加)和OBUF等组成(输出缓冲,对于输出管脚会自动添加)。右边是ILOGICE,它根据代码被配置成了IDDR。
把这图放大一点,可以看到输入输出的情况:din进入IBUF后直接到IDDR,然后两个输出分别到两个OBUF,然后到管脚输出,即dout1和dout2。
时钟使能信号clk_en进来后只打了一拍,根据前面说的,它会直接从ILOGICE的上方旁路过去,我们看看是不是:
把ILOGICE部分放大,就会发现确实是没有用IDDR,就是直接从ILOGICE内部直接穿过去的,相当于旁路了。
前面说过,ILOGICE内部的器件除了可以被配置成IDDR外,还可以被配置成触发器和锁存器。如果输入信号需要打一拍,那把这个打一拍的触发器用ILOGICE来实现是有很大的好处的,一个是ILOGICE和输入管脚比较近,走线延时短;还有一个就是二者位置固定,这样每次重新布线都不会改变这一段的走线,避免了PAD到内部FF的路径的未知性,对于分析时序是非常有利。
如果想把这个触发器用ILOGICE来实现,应该怎么做呢?这样在触发器的前边加上这么一条综合属性即可:
先来看看触发器不在ILOGICE实现的情况:
因为输入和输出分别在两边,所以这个触发器被安排在了中间的位置,可以看到真的是很远。重新布线看看:
这个触发器被吸收到了ILOGICE内部,和Pad管脚隔得很近。再放大一点,可以看到原本的IDDR变成了一个触发器FF。