Idelay,Iddr,IOB:
Idelay的输入IDatain由IOB驱动,一般和ibuf输出的信号直接相连。Datain信号不能由IOB驱动,否则会将idelay优化掉,并且vivado还不会报错,直接看device可以看到没有使用idelay。
使用idelay必须使用IOB中的寄存器将输入管脚信号打一拍。打一拍得使用xilinx原语FDRE,并将该原语的加上(*IOB=”true”*)
的属性,该属性保证了将寄存器放在IOB中。如果直接将(*IOB=”true”*)
属性放在输入管脚的定义上,则不会将该寄存器放在IOB中。如果使用idelay而不使用IOB中的寄存器,idelay的输出信号会通过ilogic中的组合逻辑到达FPGA的内部,这样无法保证idelay的延迟效果(因为输入延迟到下一级寄存器之间的延迟不确定,如果使用IOB中的寄存器,这样会保证idelay到下一级寄存器(也就是IOB中的寄存器)的延迟,从而保证延迟效果)。
下面的例子是将寄存器a使用idelay的作用:
module delay(
input wire clk_p,
input wire clk_n,
input wire rst,
input wire a,
(*IOB = "true"*)output reg b
);
wire a_t1;
reg a_t2;
wire clk;
wire a_delay;
wire RDY;
(* IOB = "true" *)
FDRE fdre_data_valid_inst
(.D (a ),
.C (clk),
.CE (1'b1),
.R (1'b0),
.Q (a_t1 )
);
......
endmodule
综上所述,使用idelay的流程是:信号到Ibuf,从ibuf到idelay,再从idelay到IOB的寄存器,并且ibuf信号连接到idelay的idatain端口(当将ibuf信号连接到datain端口时idelay会被优化掉,直接看device可以看到没有使用idelay)。当不使用idelay时,ibuf可以直接通过IOB寄存器然后再到FPGA内部逻辑。
IOB的寄存器在ilogic中,除此之外,ilogic中还可以实现iddr,锁存器和一些组合逻辑。组合逻辑用于不适用任何约束时,使得输入信号直接进去fpga的内部逻辑中。
根据以上可以推出,当使用iddr和idelay信号时还是先通过idelay然后再通过iddr。
Odelay,Oddr,IOB:
对于输出管脚使用IOB中的寄存器时,可以将(IOB=”true”)属性直接使用到输出信号的关键上,例如:(IOB = “true”)output reg b;使用该属性必须保证上一级寄存器输出到IOB寄存器之间没有其他布线,否则将不能使用,详见网址:《vivado xilinx IOB = true的使用》
Oddr和IOB寄存器都为位于Ologic中,除此之外还有ologic中还有latch、用于三态输出的逻辑和一些组合逻辑。组合逻辑用于没有使用原语时,将内部逻辑直接输出到pin脚上。
根据ug471可以知道,odelay的输入odatain是由ologic/oserdese驱动的,而IOB的寄存器存在于ologic中,所以如果同时使用IOB寄存器和odelay时,数据应该先通过IOB的寄存器再通过odelay,之后再通过obuf输出到FPGA的外部。同理Oddr也一样,因为oddr也存在于ologic中。当不使用odelay使oddr的数据可以直接输出到Obuf,然后输出到FPGA外部。目前还没有提到使用odealy时必须使用IOB的寄存器。但是如果不使用IOB的寄存器,内部逻辑会ologic的组合逻辑到达odelay的输入端口,按照这样无法保证odelay延迟的效果(因为内部走线延迟不定,上一个寄存器不知道在什么地方,使用IOB中的寄存器会保证odelay的上一级寄存器到odelay的延迟这样可以保证odelay的延迟效果)。
例子:
module delay(
input wire clk_p,
input wire clk_n,
input wire rst,
input wire a,
output wire b
);
wire a_t1;
reg a_t2;
wire b_int;
wire b_delay;
wire clk;
wire a_delay;
wire RDY;
IBUFDS #(
.DIFF_TERM("FALSE"), // Differential Termination
.IBUF_LOW_PWR("TRUE"), // Low power="TRUE", Highest performance="FALSE"
.IOSTANDARD("DEFAULT") // Specify the input I/O standard
) IBUFDS_inst (
.O(clk), // Buffer output
.I(clk_p), // Diff_p buffer input (connect directly to top-level port)
.IB(clk_n) // Diff_n buffer input (connect directly to top-level port)
);
(* IOB = "true" *)
FDRE a_inst
(.D (a_delay ),
.C (clk),
.CE (1'b1),
.R (1'b0),
.Q (a_t1 )
);
(* IOB = "true" *)
FDRE b_iob
(.D (a_t2 ),
.C (clk),
.CE (1'b1),
.R (1'b0),
.Q (b_int )
);
OBUF #(
.DRIVE(12), // Specify the output drive strength
.IOSTANDARD("DEFAULT"), // Specify the output I/O standard
.SLEW("SLOW") // Specify the output slew rate
) OBUF_inst (
.O(b), // Buffer output (connect directly to top-level port)
.I(b_delay) // Buffer input
);
always @(posedge clk)begin
if(rst)
a_t2 <= 0;
else
a_t2 <= a_t1 + 1'b1;
end
(* IODELAY_GROUP = "idelay_group_name" *) // Specifies group name for associated IDELAYs/ODELAYs and IDELAYCTRL
IDELAYCTRL IDELAYCTRL_inst (
.RDY(RDY), // 1-bit output: Ready output
.REFCLK(clk), // 1-bit input: Reference clock input
.RST(1'b0) // 1-bit input: Active high reset input
);
(* IODELAY_GROUP = "idelay_group_name" *) // Specifies group name for associated IDELAYs/ODELAYs and IDELAYCTRL
IDELAYE2 #(
.CINVCTRL_SEL("FALSE"), // Enable dynamic clock inversion (FALSE, TRUE)
.DELAY_SRC("DATAIN"), // 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(23), // 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(), // 5-bit output: Counter value output
.DATAOUT(a_delay), // 1-bit output: Delayed data output
.C(clk), // 1-bit input: Clock input
.CE(), // 1-bit input: Active high enable increment/decrement input
.CINVCTRL(), // 1-bit input: Dynamic clock inversion input
.CNTVALUEIN(), // 5-bit input: Counter value input
.DATAIN(), // 1-bit input: Internal delay data input
.IDATAIN(a), // 1-bit input: Data input from the I/O
.INC(), // 1-bit input: Increment / Decrement tap delay input
.LD(1'b1), // 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
);
(* IODELAY_GROUP = "idelay_group_name" *) // Specifies group name for associated IDELAYs/ODELAYs and IDELAYCTRL
ODELAYE2 #(
.CINVCTRL_SEL("FALSE"), // Enable dynamic clock inversion (FALSE, TRUE)
.DELAY_SRC("ODATAIN"), // Delay input (ODATAIN, CLKIN)
.HIGH_PERFORMANCE_MODE("FALSE"), // Reduced jitter ("TRUE"), Reduced power ("FALSE")
.ODELAY_TYPE("FIXED"), // FIXED, VARIABLE, VAR_LOAD, VAR_LOAD_PIPE
.ODELAY_VALUE(12), // Output 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
)
ODELAYE2_inst (
.CNTVALUEOUT(), // 5-bit output: Counter value output
.DATAOUT(b_delay), // 1-bit output: Delayed data/clock output
.C(clk), // 1-bit input: Clock input
.CE(), // 1-bit input: Active high enable increment/decrement input
.CINVCTRL(), // 1-bit input: Dynamic clock inversion input
.CLKIN(), // 1-bit input: Clock delay input
.CNTVALUEIN(), // 5-bit input: Counter value input
.INC(), // 1-bit input: Increment / Decrement tap delay input
.LD(1'b1), // 1-bit input: Loads ODELAY_VALUE tap delay in VARIABLE mode, in VAR_LOAD or
// VAR_LOAD_PIPE mode, loads the value of CNTVALUEIN
.LDPIPEEN(1'b0), // 1-bit input: Enables the pipeline register to load data
.ODATAIN(b_int), // 1-bit input: Output delay data input
.REGRST(1'b0) // 1-bit input: Active-high reset tap-delay input
)
endmodule
以上内容是针对于7系列芯片而言。
对于ultrascale系列芯片而言,idelay、odelay、iserdes、oserdes、IOB寄存器都位于bit_slice(ultrascale的新名词)中,在bit_slice中可以实现iddr和oddr。对于7系列芯片,这些都是分开的,只有IOB寄存器和iddr和oddr在iologic中。
很棒! 给你点个赞, 顶一下!