Xilinx的Ultrascale系器件指使用Ultrascale架构的Kintex Ultrascale、Kintex Ultrascale+、Virtex Ultrascale、Virtex Ultrascale+这几个系列,上一节讲解7系器件的IDDR原语,本节就讲解Ultrascale器件中同样功能的IDDRE1原语。
IDDRE1原语的功能与7系器件中的IDDR原语相同,但是由于两者FPGA硬件架构的改变,IDDR的实现也有些许改变,反映到Verilog代码编写中就是IDDRE1的端口信号等也发生了改变,后续的其他原语,两个架构的实现使用也会有所不同。
- IDDRE1框图:
原语框图如上图所示,R为复位,7系中的Set置位功能取消。 - IDDRE1例化:
IDDRE1 #(
.DDR_CLK_EDGE(“OPPOSITE_EDGE”), // IDDRE1 mode (OPPOSITE_EDGE, SAME_EDGE, SAME_EDGE_PIPELINED)
.IS_CB_INVERTED(1’b0), // Optional inversion for CB
.IS_C_INVERTED(1’b0) // Optional inversion for C
)
IDDRE1_inst (
.Q1(Q1), // 1-bit output: Registered parallel output 1
.Q2(Q2), // 1-bit output: Registered parallel output 2
.C©, // 1-bit input: High-speed clock
.CB(CB), // 1-bit input: Inversion of High-speed clock C
.D(D), // 1-bit input: Serial Data Input
.R® // 1-bit input: Active High Async Reset
);
例化共3个参数和6个端口,相比7系IDDR变动较大;
-
IDDRE1例化端口:
其中Q1、Q2、C、D端口与7系IDDR相同;
R:7系为R/S复位置位公用,IDDRE1只有异步复位R无置位;
CB:不同电路情况下,与参数一起协同配置,输入一个和C完全同相或是反相的时钟; -
IDDR例化参数:
参数DDR_CLK_EDGE:IDDRE1的操作模式,有OPPOSITE_EDGE、SAME_EDGE_PIPELINED、SAME_EDGE三种值可选,默认OPPOSITE_EDGE模式;
参数IS_C_INVERTED:值为1将反转输入的时钟C,0、1可选,默认0;
参数IS_CB_INVERTED:值为1将反转输入的时钟CB,0、1可选,默认0; -
参数和端口的协同配置:
7系和Ultrascale系架构的不同点在此处就能看出,7系的IDDR原语只用输入一个时钟C即可,用于下降沿采样的反相时钟CB由组件原语内部逻辑生成;
Ultrascale架构则可以选择输入一个主时钟和一个和主时钟C完全反相的时钟CB,此时C和CB的反相由外部硬件或是FPGA内部的全局时钟网络进行实现,且两个控制C和CB极性的参数还能和C和CB端口一起配合提高配置的灵活性,在不改变物理布线的情况下适配不同的时钟网络条件。
其中C和CB端口的输入需要和参数IS_C_INVERTED和IS_CB_INVERTED一起搭配使用;
以下是几种不同的情况:
情况1,IS_C_INVERTED=0, IS_CB_INVERTED=0:
C不反相,CB不反相,原语直接使用外部输入的时钟C、CB,内部无反相;
C直接连接到外部时钟源;
CB为外部与C反相的时钟(C=~CB);
组件内部逻辑最后使用C_inter=C,CB_inter=CB;
这种情况适用与CB在外部直接就与C反相,如硬件输入或者是两个时钟都为全局时钟网络时钟。
情况2,IS_C_INVERTED=0, IS_CB_INVERTED=1:
C不反相,CB反相,原语直接使用外部输入的时钟C,CB则是外部输入后内部先进行反相操作后再使用;
C直接连接到外部时钟源;
CB则要连接到与C同相的时钟(C=CB);
组件内部逻辑最后使用C_inter=C,CB_inter=~CB;
这种情况适用于当外部受限于始终网络资源有限或是由于其他情况无法生成与C反相的时钟时使用,此时C和CB直接复用同一时钟即可。
情况3,IS_C_INVERTED=1, IS_CB_INVERTED=0:
C反相,CB不反相,原语直接使用外部输入的时钟CB,C则是外部输入后内部先进行反相操作后再使用;
C直接连接到外部时钟源;
CB则要连接到与C同相的时钟(C=CB);
组件内部逻辑最后使用C_inter=~C,CB_inter=CB;
这种情况适用于当需要C反相,但是外部受限无法将C反相且CB无法调整时,C和CB直接复用同一时钟,再由组件原语参数,将C反相即可;
情况4,IS_C_INVERTED=1, IS_CB_INVERTED=1:
C反相,CB反相,原语内部对C和CB都执行反相操作;
C直接连接到外部时钟源;
CB为外部与C反相的时钟(C=~CB);
组件内部逻辑最后使用C_inter=C,CB_inter=CB;
这种情况将C和CB都反相,一般用于补偿C和CB的极性错误;例如由于硬件设计的布线失误,导致C和CB极性弄错了,但是数据D又需要按照正确的极性进行采集,所以就可以使用这种情况的配置,将C和CB的极性在内部使用时反转过来。
注意:
C和CB端口的外部输入,和极性控制参数的搭配,要达到的效果必须是内部逻辑使用的C_inter和CB_inter,两者必须反相互补;
如果不按照设计要求去使用,例如在情况2下,IS_C_INVERTED=0, IS_CB_INVERTED=1,原语会对输入的CB进行一次反相后使用,C和CB必须同相,但如果此时输入C和CB(CB=C)反相,那么此时C_inter=C,CB_inter=CB=(C)=C=C_inter,此时C_inter和CB_inter同相,那么原语功能就会失效,此时C_inter和CB_inter的上升沿都在C的上升沿,C的下降沿处没有上升沿的采集时钟,没有双沿的采样时钟就无法触发DDR的双沿采集功能,原语无法工作,且有可能造成亚稳态时序违例等影响系统稳定的错误;
- IDDR三种操作模式:
IDDRE1的这三种模式与IDDR完全相同;
时钟C的上升沿对应7系中的采集时钟的上升沿,时钟CB的上升沿对应7系的采集时钟的下降沿;
且要注意下图中的C和CB都是上述的经过极性调整的C_inter和CB_inter;
OPPOSITE_EDGE模式:
Q1在C上升沿采样更新,Q2在CB上升沿采样更新,Q2的数据落后Q1半个时钟周期;
SAME_EDGE模式:
Q1、Q2都在C上升沿更新,在同一个周期采样的两个数据,Q2比Q1晚一个时钟周期;
SAME_EDGE_PIPELINED模式:
Q1、Q2在一个时钟周期内的C上升沿和CB上升沿采样,然后在第二个时钟周期的C上升沿同时输出,两者输出落后实际输入数据一个时钟周期,该方法比较常用;
7. 仿真代码:
被测试模块:
后续仿真时会修改参数和输入的C和CB的极性搭配查看各情况下的情况;
module top_ultraplus_iddre1(
input wire clk,
input wire clk_b,
input wire rst,
input wire din,
output wire dout1,
output wire dout2
);
IDDRE1 #(
.DDR_CLK_EDGE(“OPPOSITE_EDGE”), // IDDRE1 mode (OPPOSITE_EDGE, SAME_EDGE, SAME_EDGE_PIPELINED)
.IS_CB_INVERTED(1’b0), // Optional inversion for CB
.IS_C_INVERTED(1’b0) // Optional inversion for C
)
IDDRE1_inst (
.Q1(dout1), // 1-bit output: Registered parallel output 1
.Q2(dout2), // 1-bit output: Registered parallel output 2
.C(clk), // 1-bit input: High-speed clock
.CB(clk_b), // 1-bit input: Inversion of High-speed clock C
.D(din), // 1-bit input: Serial Data Input
.R(rst) // 1-bit input: Active High Async Reset
);
endmodule
testbench:
产生40ns的时钟,产生时钟边沿对齐数据中心的双沿随机数据;
后续仿真时再修改输入时钟极性和原语参数配置;
`timescale 1ns / 1ps
module tb;
reg sclk;
reg rst;
wire clk;
wire clk_b;
reg data;
wire dout1;
wire dout2;
initial begin
sclk = 0;
rst = 1;
#200
rst = 0;
end
always #20 sclk = ~sclk;
initial begin
data = 0;
#10
while(1)begin
#20
data = $random();
end
end
assign clk = sclk;
assign clk_b = ~sclk;
top_ultraplus_iddre1 inst_top_ultraplus_iddre1 (
.clk(clk),
.clk_b(clk_b),
.rst(rst),
.din(din),
.dout1(dout1),
.dout2(dout2)
);
endmodule
- 仿真结果:
sclk为tb中生成的源时钟;
OPPOSITE_EDGE模式,IS_C_INVERTED=0, IS_CB_INVERTED=0,clk=sclk,clk_b=~sclk:
该模式下,Q1是C上升沿采样后立即更新输出,Q2是CB上升沿采样后立即更新输出;
可以看到上图箭头,clk上升沿采样din数据后dout1立即输出,clk_b上升沿采样din数据后dout2立即输出;
SAME_EDGE模式,IS_C_INVERTED=0, IS_CB_INVERTED=0,clk=sclk,clk_b=~sclk:
该模式下,Q1在C上升沿采样后立即输出,Q2在C上升沿采样后寄存数据等待下一个C上升沿到来后输出;
可以看到上图中的箭头,dout1在clk上升沿采样din后立即输出,dout2在clk_b上升沿采样din后还要等到下一个clk上升沿才更新输出;
SAME_EDGE_PIPELINED模式,IS_C_INVERTED=0, IS_CB_INVERTED=0,clk=sclk,clk_b=~sclk:
该模式下,Q1在C上升沿采样后寄存,Q2在CB上升沿采样后寄存,Q1、Q2一起寄存等到下一个C上升沿到来后一起输出;
可以看到上图中的箭头,dout1在clk上升沿采样din,dout2在clk_b上升沿采样din,两者的输出则是等到下一个clk上升沿才一起更新输出;
可以看到IDDRE1的这三个模式与上一节的IDDR的时序基本是一样的,接下来就用比较常用的SAME_EDGE_PIPELINED模式做基准,更改其他几种参数配置和时钟输入,查看仿真情况:
SAME_EDGE_PIPELINED模式,IS_C_INVERTED=0, IS_CB_INVERTED=1,clk=sclk,clk_b=sclk:
在这种情况下,C_inter=clk=sclk,CB_inter=clk_b=sclk,符合C_inter和CB_inter互补情况,此时仿真图中clk和C_inter同相,clk_b和CB_inter反相,
clk上升沿(C_inter上升沿)采集din到下一个clk上升沿时刻dout1输出,
clk_b下降沿(CB_inter上升沿)采集din到下一个clk上升沿时刻dout2输出,
符合图上仿真波形;
SAME_EDGE_PIPELINED模式,IS_C_INVERTED=1, IS_CB_INVERTED=0,clk=sclk,clk_b=sclk:
在这种情况下,C_inter=clk=sclk,CB_inter=clk_b=sclk,符合C_inter和CB_inter互补情况,此时仿真图中clk和C_inter反相,clk_b和CB_inter同相,
clk下降沿(C_inter上升沿)采集din到下一个clk下降沿时刻dout1输出,
clk_b上升沿(CB_inter上升沿)采集din到下一个clk下降沿时刻dout2输出,
符合图上仿真波形;
SAME_EDGE_PIPELINED模式,IS_C_INVERTED=1, IS_CB_INVERTED=1,clk=sclk,clk_b=~sclk:
在这种情况下,C_inter=clk=sclk,CB_inter=clk_b=(~sclk)=sclk,符合C_inter和CB_inter互补情况,此时仿真图中clk和C_inter反相,clk_b和CB_inter反相,
clk下降沿(C_inter上升沿)采集din到下一个clk下降沿时刻dout1输出,
clk_b下降沿(CB_inter上升沿)采集din到下一个clk下降沿时刻dout2输出,
符合图上仿真波形;
仿真一下前述的配置违规的情况:
SAME_EDGE_PIPELINED模式,IS_C_INVERTED=0, IS_CB_INVERTED=0,clk=sclk,clk_b=sclk:
在IS_C_INVERTED=0, IS_CB_INVERTED=0的参数配置下,C和CB必须反相,但是这里给了同相时钟clk进行测试;
此时组件中,
C_inter=clk=sclk,CB_inter=clk_b=sclk,不符合C_inter和CB_inter互补情况;
可以看到上图中,clk和clk_b相同,
第一个黄圈中,包裹了一个clk的上升下降沿正好一个时钟周期,此时如果组件正常,那么此时应该是clk上升沿位置采集1,下降沿位置采集0,然后下一个clk上升沿dout1输出1,dout2输出0,
但是图中可以看到,dout1和dout2输出相同的数据1,这个数据应该来自clk上升沿采集数据,如果不规范一点想,此时输出这种情况,应该就是组件中C_inter上升沿(sclk上升沿)采集1输出到dout1,CB_inter上升沿(sclk上升沿)采集1输出到dout2,此时C_inter和CB_inter同相,用于采集的上升沿也重叠到一起,所以也做不到采样双沿数据。
本文章由北京威三学社出品
对课程感兴趣可以私信联系我们