关注、星标公众号,精彩内容每日送达
来源:网络素材
1. 7系列IO资源HR bank
在7系列FPGA中,其HR bank的IO结构如下图所示。其中在HR bank的IO都会有如下的结构部分,分别是信号输入输出的pad,然后会经过IOB,在HR bank中有用于输入延时的资源 IDELAYE2 这个结构。在HR bank中,没有用于输出的延时结构。最后是输入输出的逻辑或者串并转换的Serdes。
2. IDELAY 原语
2.1 IDELAY 的延时值
首先看一下手册上是怎么来描述这个原语的。每个I/O都包含一个IDELAYE2的可编程的原语。IDELAY可以连接到后续的模块。
IDLEAYE2可以根据抽头系数来调整延时。这个抽头系数对应的最小分辨率可以根据7系列的手册上来看。
从手册上来看,抽头系数的分辨率是和用于IO delay的这个参考时钟有关系。计算公式就是上面那个写着的。可以看到根据参考时钟的不同,具体delay的分辨率不同。对于200M的参考时钟其抽头系数的分辨率为78ps。参考时钟为300M的时候,分辨率为52ps。参考时钟为400M的时候,分辨率为39ps。
从参考手册上来看,还需要有个参考时钟。其实在实际使用中IDELAY这个原语的时候,还需要一个IDELAYCTRL这个原语配合使用。
2.2 IDELAYCTRL 原语
这个原语比较简单,一般都是配合着I/ODELAY原语来使用的。手册上写着,如果使用了IDELAYE2或者ODELAYE2原语,那么IDELAYCTRL原语必须被例化。IDLAYCTRL使用用户提供的REFCLK来校准IDELAY和ODELAY。也就是前面说的,具体的延时的值,是根据输入到IDELAYCTRL的参考时钟来确定的。
这个原语的使用也比较简单,只需给一个参考时钟和复位信号。如下面的时序图所示:
2.3 IDELAY 原语的使用
IDELAY原语的结构如下所示:
例化模板如下:
IDELAYE2 #(
.CINVCTRL_SEL("FALSE"), // Enable dynamic clock inversion (FALSE, TRUE)
.DELAY_SRC("IDATAIN"), // Delay input (IDATAIN, DATAIN)
.HIGH_PERFORMANCE_MODE("FALSE"), // Reduced jitter ("TRUE"), Reduced power ("FALSE")
.IDELAY_TYPE("FIXED"), // FIXED, VARIABLE, VAR_LOAD, VAR_LOAD_PIPE
.IDELAY_VALUE(0), // Input delay tap setting (0-31)
.PIPE_SEL("FALSE"), // Select pipelined mode, FALSE, TRUE
.REFCLK_FREQUENCY(200.0), // IDELAYCTRL clock input frequency in MHz (190.0-210.0, 290.0-310.0).
.SIGNAL_PATTERN("DATA") // DATA, CLOCK input signal
)
IDELAYE2_inst (
.CNTVALUEOUT(CNTVALUEOUT), // 5-bit output: Counter value output
.DATAOUT(DATAOUT), // 1-bit output: Delayed data output
.C(C), // 1-bit input: Clock input
.CE(CE), // 1-bit input: Active high enable increment/decrement input
.CINVCTRL(CINVCTRL), // 1-bit input: Dynamic clock inversion input
.CNTVALUEIN(CNTVALUEIN), // 5-bit input: Counter value input
.DATAIN(DATAIN), // 1-bit input: Internal delay data input
.IDATAIN(IDATAIN), // 1-bit input: Data input from the I/O
.INC(INC), // 1-bit input: Increment / Decrement tap delay input
.LD(LD), // 1-bit input: Load IDELAY_VALUE input
.LDPIPEEN(LDPIPEEN), // 1-bit input: Enable PIPELINE register to load data input
.REGRST(REGRST) // 1-bit input: Active-high reset tap-delay input
);
2.3.1 原语属性
属性 | 描述 |
---|---|
CINVCTRL_SEL | 该属性是来选择是否动态地反转时钟信号C的极性 |
DELAY_SRC | 要延时的信号的来源,可以是内部的 信号(DATAIN),也可以是来自管脚的 信号(IDATAIN) |
HIGH_PERFORMANCE_MODE | 是否使用高性能模式,使用高性能模式能够减小抖动 |
IDELAY_TYPE | 原语延时的类型,可以是固定的延时值,当选择固定的延时的时候,和下面的 IDELAY_VALUE 一起决定了延时的时间 也可以是动态更改的。当想染IO的延时可以动态更改的时候,一般选择VAR_LOAD的模式,也就是加载延时抽头系数的模式 |
IDELAY_VALUE | 延时的值,在fixed模式下有用,在其他模式下,当没有新的延时值得时候,默认为这个延时值,当外部输入新的值得时候,将会改变延时值 |
PIPE_SEL | 当使用 VAR_LOAD_PIPE 模式的时候,才选择这个选项 |
REFCLK_FREQUENCY | 参考时钟,200M 300M这种 |
SIGNAL_PATTERN | 确定延时的是时钟还是数据,以确定不同路径上的抖动 |
2.3.2 原语端口
端口 | 描述 |
---|---|
CNTVALUEOUT | 延时系数的输出,输入的延时系数,可以通过这个端口来观察,可以表示当前原语的工作状态 |
DATAIN , IDATAIN | 需要延时的数据,DATAIN是内部的数据, IDATAIN是来自IO的数据 |
DATAOUT | 经过延时后的数据 |
C | 时钟,当不是fixed模式的时候,必须要提供时钟,来更新延时的抽头系数值 |
CINVCTRL | 允许更改时钟的极性,也就是时钟极性反转 |
CNTVALUEIN | 动态更改延时抽头系数的时候,使用这个值来进行更改,5bit,最大为31,也就是最大的延时值就是32*分辨率, 对于200M的参考时钟,最大的参考时钟是2.5ns左右 |
LDPIPEEN | 将输入的延时值加载到流水线当中 |
REGRST | 复位,只在 VAR_LOAD_PIPE 模式下有效 |
CE, INC, LD | 这三个信号来控制抽头系数的变化。放在一起考虑,看几个时序图一下就i明白了各自的作用了 |
2.3.4 端口的工作模式
Fixed 模式
就是固定的延时值。VARIABLE 模式
当时钟上升沿有效的时候,在LD为高电平的时候TAP值写入,如果LD为低,且使能了CE信号和INC,那么TAP值就会加1,如果CE为1且INC为0,那么Tap值就会减1。
VAR_LOAD模式
load模式下可以多次的加载延时的系数,从而动态的修改延时的值。
3. 验证一下
`timescale 1ns / 1ps
module tb_idelay();
// Test signals
reg ref_clk ;
reg rst ;
wire rdy ;
reg [11:0] rx_data_buf ;
reg rx_frame_buf ;
wire [11:0] rx_data_delay ;
wire rx_frame_delay ;
reg [4:0] delay_value ;
reg [12:0] delay_load_en ;
wire [4:0] mon_delay_frame ;
wire [4:0] mon_delay_data ;
//generate clock 200M
initial begin
ref_clk = 0;
forever #(2.5) ref_clk = ~ref_clk;
end
// generate source data and frame
initial begin
rst = 1;
rx_frame_buf = 0;
rx_data_buf = 0;
repeat(50)@(posedge ref_clk);
rst = 0;
repeat(100)@(posedge ref_clk);
gen_test_data;
end
// generate delay value and load signal
initial begin
delay_load_en = 1'b0;
delay_value = 5'd0;
@(negedge rx_frame_buf);
@(negedge ref_clk);
delay_value = 5'd16;
delay_load_en = {13{1'b1}};
@(negedge ref_clk);
delay_load_en = {13{1'b0}};
delay_value = 5'd0;
@(negedge rx_frame_buf);
@(negedge ref_clk);
delay_value = 5'd31;
delay_load_en = {13{1'b1}};
@(negedge ref_clk);
delay_load_en = {13{1'b1}};
delay_value = 5'd31;
end
task gen_test_data();
integer k,j; begin
for (k = 0; k < 3; k = k + 1) begin
rx_frame_buf = 1'b1;
for (j = 0; j < 512; j = j + 1) begin
rx_data_buf = j[11:0];
@(posedge ref_clk);
end
rx_frame_buf = 1'b0;
repeat(50)@(posedge ref_clk);
end
end
endtask
genvar i;
// IDELAYCTRL module
IDELAYCTRL IDELAYCTRL_inst (
.RDY(rdy), // 1-bit output: Ready output
.REFCLK(ref_clk),// 1-bit input: Reference clock input
.RST(rst) // 1-bit input: Active high reset input
);
// delay frame
IDELAYE2 #(
.CINVCTRL_SEL("FALSE"), // Enable dynamic clock inversion (FALSE, TRUE)
.DELAY_SRC("IDATAIN"), // Delay input (IDATAIN, DATAIN)
.HIGH_PERFORMANCE_MODE("FALSE"), // Reduced jitter ("TRUE"), Reduced power ("FALSE")
.IDELAY_TYPE("VAR_LOAD"), // FIXED, VARIABLE, VAR_LOAD, VAR_LOAD_PIPE
.IDELAY_VALUE(0), // Input delay tap setting (0-31)
.PIPE_SEL("FALSE"), // Select pipelined mode, FALSE, TRUE
.REFCLK_FREQUENCY(200.0), // IDELAYCTRL clock input frequency in MHz (190.0-210.0, 290.0-310.0).
.SIGNAL_PATTERN("DATA") // DATA, CLOCK input signal
)
IDELAYE2_inst_frame_delay (
.CNTVALUEOUT(mon_delay_frame),// 5-bit output: Counter value output
.DATAOUT(rx_frame_delay), // 1-bit output: Delayed data output
.C(ref_clk), // 1-bit input: Clock input
.CE(1'b0), // 1-bit input: Active high enable increment/decrement input
.CINVCTRL(1'b0), // 1-bit input: Dynamic clock inversion input
.CNTVALUEIN(delay_value), // 5-bit input: Counter value input
.DATAIN(1'b0), // 1-bit input: Internal delay data input
.IDATAIN(rx_frame_buf), // 1-bit input: Data input from the I/O
.INC(1'b0), // 1-bit input: Increment / Decrement tap delay input
.LD(delay_load_en[12]), // 1-bit input: Load IDELAY_VALUE input
.LDPIPEEN(1'b0), // 1-bit input: Enable PIPELINE register to load data input
.REGRST(1'b0) // 1-bit input: Active-high reset tap-delay input
);
//delay data
generate
for (i = 0; i < 12; i = i + 1)
begin:data_delay
IDELAYE2 #(
.CINVCTRL_SEL("FALSE"), // Enable dynamic clock inversion (FALSE, TRUE)
.DELAY_SRC("IDATAIN"), // Delay input (IDATAIN, DATAIN)
.HIGH_PERFORMANCE_MODE("FALSE"), // Reduced jitter ("TRUE"), Reduced power ("FALSE")
.IDELAY_TYPE("VAR_LOAD"), // FIXED, VARIABLE, VAR_LOAD, VAR_LOAD_PIPE
.IDELAY_VALUE(0), // Input delay tap setting (0-31)
.PIPE_SEL("FALSE"), // Select pipelined mode, FALSE, TRUE
.REFCLK_FREQUENCY(200.0), // IDELAYCTRL clock input frequency in MHz (190.0-210.0, 290.0-310.0).
.SIGNAL_PATTERN("DATA") // DATA, CLOCK input signal
)
IDELAYE2_inst_data_delay (
.CNTVALUEOUT(mon_delay_data),// 5-bit output: Counter value output
.DATAOUT(rx_data_delay[i]), // 1-bit output: Delayed data output
.C(ref_clk), // 1-bit input: Clock input
.CE(1'b0), // 1-bit input: Active high enable increment/decrement input
.CINVCTRL(1'b0), // 1-bit input: Dynamic clock inversion input
.CNTVALUEIN(delay_value), // 5-bit input: Counter value input
.DATAIN(1'b0), // 1-bit input: Internal delay data input
.IDATAIN(rx_data_buf[i]), // 1-bit input: Data input from the I/O
.INC(1'b0), // 1-bit input: Increment / Decrement tap delay input
.LD(delay_load_en[i]), // 1-bit input: Load IDELAY_VALUE input
.LDPIPEEN(1'b0), // 1-bit input: Enable PIPELINE register to load data input
.REGRST(1'b0) // 1-bit input: Active-high reset tap-delay input
);
end
endgenerate
endmodule
测试结果
测试发现一个有意思的事情,只要通过了idelay这个原语,都会先增加一个0.6ns的延时。如下图所示,可以看到此时没有添加延时值,并且初始的抽头系数的值也是0。但是当数据经过IDELAY原语后,增加了一个0.6ns的延时。
然后在导入延时系数之后,可以看到此时原语的检测抽头系数的值发生了变化。延时抽头系数的值,编程了通过在load信号为有效的时候,加载的值。
此时可以看到延时值已经变成了1.848ns。计算一下抽头系数,乘上分辨率为:16 x 0.078 = 1.248ns。再加上Idelay本身的延时,刚好就是本次的延时值,1.848ns。
最后一次加载的抽头系数是31,可以看到当前的延时的值,已经变成了3.018ns。31 x 0.078+0.6 = 3,018ns;
想要了解FPGA吗?这里有实例分享,ZYNQ设计,关注我们的公众号,探索