0

xilinx 7系列FPGA 芯片I/O delay,I/O ddr和IOB之间的关系

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中。

编辑 重设标签(回车键确认) 标为违禁 关闭 合并 删除
匿名用户

匿名

0

很棒! 给你点个赞, 顶一下!

编辑 标为违禁 删除 链接 更多选项...

回答 2021-10-02 17:13:34 +0800

这个帖子被标记为一个社区wiki

这个帖子是一个wiki(维基). 任何一个积分 >500的人都可以完善它

登录/注册后进行回答