作者:FPGA技术联盟
1、ODDR是什么?
在此之前,强烈建议你先看看这篇关于IDDR的文章:FPGA实现LVDS接口(2)--IDDR原语的介绍及使用(仿真/源码)
ODDR也是Xilinx7系列FPGA的一个底层原语,它的功能就是把FPAG内部的单沿信号转换为双沿信号输出给外部设备进行使用,即完成输入的SDR信号到输出的DDR信号的转换。需要注意的是,它只能在IO管脚上使用,不能在FPGA内部逻辑使用,也就是说只能通过管脚(IO Pad)把FPGA内部双沿信号转换成单沿信号。
OLOGIC块位于IOB的内侧,FPGA内部信号想要输出到管脚,都必须经过OLOGIC。OLOGIC资源的类型为OLOGICE2(HP I/O Bank)和OLOGICE3(HR I/O Bank),两者在功能和结构上是相同的。
下图是OLOGIC的结构示意图,分为上下两部分,下半部分用于配置输出数据路径,上半部分用于配置三态控制路径,分别实现对数据、三态信号进行单沿转双沿的功能,两部分具有共同的时钟 (CLK),但是使能信号不同(OCE和TCE)。
如果输出的信号不使用OLOGIC中的ODDR功能,那么此时信号从图1中红线路径进行传输,从组合逻辑电路直接输出到IOB模块;如果要使用OLOGIC的ODDR功能,把单沿传输的信号转换为双沿传输的信号,此时需要两个输入信号D1、D2沿蓝色路径进行传输。
因为OLOGIC不是基本元件,所以用户不能通过代码去对OLOGIC进行例化。但OLOGIC包含一些可以被用户实例化的元件,例如:
ODDR
FF触发器
LATCH锁存器
2、ODDR的使用
下图是ODDR原语框图,与IDDR一样不支持同时复位和置位。ODDR端口信号如下表所示,表2描述了ODDR原语的可用参数。
ODDR原语的输入输出信号如下表所示:
ODDR原语除了输入输出信号端口外,还有几个参数端口需要配置,其使用说明如下:
ODDR原语只支持两种操作模式:
OPPOSITE_EDGE模式
SAME_EDGE模式
2.1、OPPOSITE_EDGE模式
下图是该模式对应的时序图:
输入D1和D2是单沿信号,Q是双的输出数据。
D1在当前时钟上升沿采样,然后在同一个沿(上升沿)被输出到Q端;Q2在当前时钟下降沿采样,然后在同一个沿(下降沿)被输出到Q端。这种模式需要用下降沿来对D2进行操作,而用上升沿对D1进行操作,同时使用两个边沿来采样在设计中不是特变方便,所以这种方式一般比较少用。
2.2、SAME_EDGE模式
下图是该模式对应的时序图:
Q1和Q2都在在当前时钟上升沿采样,然后Q1在同一个沿(上升沿)输出,Q2则在当前的下降沿输出,这种方式的好处就是D1和D2这两个来自FPGA内部的信号都可以在同一个上升沿变化,非常方便简单,属于常用的模式。
3、对ODDR的仿真分析
在vivado中通过原语模板搜索 ODDR ,接着把模板复制到自己的工程,然后按要求更改即可,这里我要对ODDR进行测试的一个模块,很简单,就只例化了一个ODDR模块:
接着写个TB来对ODDR的2种模式进行验证,随机生成两个单沿输入,观察双沿输出是否符合预期:
3.1、OPPOSITE_EDGE模式的仿真结果
把DDR_CLK_EDGE参数设置为 "OPPOSITE_EDGE" ,观察仿真结果:
D1在当前时钟上升沿采样,然后在同一个沿(上升沿)被输出到Q端;Q2在当前时钟下降沿采样,然后在同一个沿(下降沿)被输出到Q端。和预期结果一致。
3.2、SAME_EDGE模式的仿真结果
把DDR_CLK_EDGE参数设置为 "SAME_EDGE" ,观察仿真结果:
Q1和Q2都在在当前时钟上升沿采样,然后Q1在同一个沿(上升沿)输出,Q2则在当前的下降沿输出,和预期结果一致。
4、ODDR在FPGA底层的布局和布线
把工程综合、实现后,打开实现后的网表,然后点击Device界面,可以看到FPGA的硬件资源和布线情况:
先找到输出信号dout,它的布线如下,灰色方框内就是常说的IOB,它由PAD(就是管脚),IBUF(输入缓冲,对于输入管脚会自动添加)和OBUF等组成(输出缓冲,对于输出管脚会自动添加)。右边是OLOGIC,它根据代码被配置成了ODDR。
把ODDR放大一点:
前面说过,如果不用ODDR,是会从OLOGIC的上方直接穿过去的,代码中设计了一个dout_iob就是直接打拍后的信号,观察它是不是直接穿过了OLOGIC:
把OLOGIC部分放大,可以发现,确实是直接穿过了这个部分:
输入信号din_iob只打了一拍就输出到管脚了,它的布线是这样的,很长很绕:
前面说过,OLOGIC内部的器件除了可以被配置成ODDR外,还可以被配置成触发器和锁存器。如果输出信号需要打一拍,那把这个打一拍的触发器用OLOGIC来实现是有很大好处的。一个是OLOGIC和输出管脚比较近,走线延时短;还有一个就是二者位置固定,这样每次重新布线都不会改变这一段的走线,避免了从内部FF到PAD的路径的未知性,对于分析时序非常有利。
如果想把这个触发器用OLOGIC来实现,应该怎么做呢?很简单,只要在触发器的前边加上这么一条综合属性即可:
接下来重新布线
这个触发器被吸收到了OLOGICE内部,和Pad管脚隔得很近。再放大一点,可以看到原本的ODDR变成了一个触发器FF。