xilinx原语介绍及仿真——IDDR

  IDDR的主要功能就是将输入的双沿信号转换为单沿信号输出给FPGA内部逻辑进行使用,IDDR位于通1中的ILOGICE部分,在讲解IDDR使用前,需要了解ILOGICE的结构及功能。

在这里插入图片描述

图1 7系列IO模块(左侧HP bank,右侧HR bank)

1、ILOGICE

  ILOGICE位于IOB旁边,ILOGICE块包含同步元件,用于在数据通过IOB进入FPGA时捕获数据。7系列芯片中ILOGICE可能是ILOGICE2(HP I/O bank)或ILOGICE3(HR I/O bank)。

  对比图2、图3知,ILOGICE2和ILOGICE3唯一区别是ILOGICE3有零保持延迟元件(ZHOLD自动与内部时钟分配延迟相匹配,并且在使用时确保焊盘到焊盘的保持时间为零),ILOGICE3模块在输入上支持可选的静态未补偿零保持 (ZHOLD) 延迟线,以补偿时钟插入延迟。

xilinx原语介绍及仿真——IDDR_第1张图片

图2 ILOGICE2 框图

xilinx原语介绍及仿真——IDDR_第2张图片

图3 ILOGICE3框图

  ZHOLD默认启用,除非时钟源是MMCM或PLL,或者在Xilinx设计约束 (XDC)中设置了IOBDELAY属性。

  其他功能相同,所以本文将ILOGICE2和ILOGICE3统一称为ILOGICE。

  注意ILOGICE不是基本元件,用户不能通过代码去对ILOGICE进行例化。但ILOGICE包含用户实例化的元件,例如布局和布线后的输入触发器 (IFD) 或输入DDR元件(IDDR)。

  如图4所示,输入信号D,可以通过红色信号线进行传输,然后直接输出该模块, 就是当FPGA没有调用IDDR、IFD这些原语时,FPGA外部信号通过管脚进入后,需要通过ILOGICE单元,但是又不使用IDDR这些功能器件,那就会通过红色路径直接穿过ILOGICE单元,到达FPGA内部逻辑。

xilinx原语介绍及仿真——IDDR_第3张图片

图4 ILOGICE2 框图

  当需要使用IDDR这些转换功能时,通过绿色的信号传输到下面器件的输入端D,这个器件可以配置为锁存器(latch)、触发器(FF)、双沿转单沿器件(DDR),而CE1是时钟使能信号,高电平有效,不连接时默认为高电平。

  当不使用IDDR功能时,在使用IDDR原语后,只需要添加(IOB == “TRUE”)原语,就可以使用ILOGICE中的触发器(FF)的功能。 这个触发器相比FPGA内部触发器更靠近FPGA管脚,使得建立时间余量更大,更有利于时序。

  Q1和Q2是输出端口,S/R是复位、置位端口,在调用原语是可以对同步、异步触发进行设置。此框图中S/R的是一根线,但IDDR的原语将S和R分开为两个端口,使用时不能让S、R同时有效。

2、IDDR模式

  IDDR的功能就是将双沿采样的数据转换为单沿数据传输给FPGA内部进行使用。 FPGA内部的D触发器一般都是在时钟上升沿去采集输出数据,这种方式被称为SDR,与SDRAM传输数据类似。在SDRAM之后,为了提高数据传输速率,推出了DDR,在时钟的上升沿和下降沿都能传输数据,同样时钟频率下,速率可以提升一倍,这种传输数据的方式就是双沿传输,这种方式一般都只存在接口部分,内部电路采用双沿会比较麻烦,所以会转换为单沿进行处理,FPGA调用IDDR原语即可实现。

  如图5是IDDR的原语框图,将图3中的控制信号引出。

xilinx原语介绍及仿真——IDDR_第4张图片

图5 IDDR原语框图

  IDDR原语的输入输出信号的含义如表1所示。

表1 IDDR原语的端口信号
端口名 含义
Q1、Q2 IDDR输出寄存器
C 时钟输入引脚
CE 必须为高电平才能将新数据加载到DDR触发器中,低电平时,时钟转换被忽略,新数据不会加载到DDR触发器中。
D IDDR寄存器从IOB输入
S/R 同步/异步设置/复位引脚,高电平有效。

  IDDR 原语支持三种操作模式:OPPOSITE_EDGE模式、SAME_EDGE模式、SAME_EDGE_PIPELINED模式。

2.1、OPPOSITE_EDGE模式

如图6是该模式对应的时序图,C是时钟信号,CE是时钟使能信号,D是输入数据,有图可知D在C的上升沿和下降沿都有数据变化的,即双沿传输。

xilinx原语介绍及仿真——IDDR_第5张图片

图6 OPPOSITE_EDGE模式下的IDDR时序

  Q1和Q2是输出数据,Q1在时钟上升沿输出在时钟上升沿采集到的数据,而Q2在时钟下降沿数据发生变化,用于输出在时钟下降沿时采集到的数据,后续逻辑只需要在时钟上升沿同时采集Q1和Q2的数据进行拼接就可以得到D在上升沿和下降沿传输的数据了。

2.2、SAME_EDGE模式

  如图7所示,输入信号与上个模式时序图一致,SAME_EDGE模式与OPPOSITE_EDGE模式的区别在于,SAME_EDGE模式的Q1和Q2只会在时钟C的上升沿输出数据。

xilinx原语介绍及仿真——IDDR_第6张图片

图7 SAME_EDGE模式下的IDDR时序

  图6中在第一个时钟上升沿之后,Q1输出采集到的D0A,由于此时还没有经过下降沿,Q1输出无效数据。在第一个下降沿,Q2采集D的数据,在第二个时钟上升沿之后,Q1输出采集第二个时钟上升沿采集的数据D2A,Q2输出第一个时钟下降沿采集的数据D1A。

  上述两种方式都不是最常用的模式,最常用的数据采集模式是SAME_EDGE_PIPELINED模式,与SAME_EDGE模式类似,只是将Q1输出数据延迟一个时钟周期,让Q1和Q2的第一个数据至最后一个数据进行对齐,方便后续操作,代价是Q1输出数据延迟了一个是时钟周期。

2.3、SAME_EDGE_PIPELINED模式

  图8显示了使用SAME_EDGE_PIPELINED模式的IDDR的时序图,Q1和Q2同时提供给FPGA逻辑,更方便用户使用。

xilinx原语介绍及仿真——IDDR_第7张图片

图8 SAME_EDGE_PIPELINED模式下的IDDR时序

3、IDDR原语

  IDDR原语的几个参数如表2所示,

表2 IDDR原语的参数含义
参数名 描述 参数值
DDR_CLK_EDGE 设置相对于时钟沿的IDDR操作模式 OPPOSITE_EDGE (默认),
SAME_EDGE,
SAME_EDGE_PIPELINED
INIT_Q1 设置Q1默认初始值 0(默认),1
INIT_Q2 设置Q2默认初始值 0(默认),1
SRTYPE 相对于时钟的置位/复位类型 异步(默认),同步

  一般把DDR_CLK_EDGE参数设置为SAME_EDGE_PIPELINED模式即可,其余参数可以不进行设置,保持默认即可。

  在vivado中获取原语模板的方法如图9所示,在Tools选项卡下点击Language Templates。

xilinx原语介绍及仿真——IDDR_第8张图片

图9 vivado获取原语模板

  然后如图10所示操作,再搜索框搜索想要的原语模块名,此处为IDDR,然后选择对应器件下的对应原语,此处使用zynq7020,即A7。5处就是IDDR原语对应的例化模板,赋值到代码中使用即可。

xilinx原语介绍及仿真——IDDR_第9张图片

图10 IDDR原语模板

  通过下面一段代码SAME_EDGE_PIPELINED模式进行仿真,TestBench文件也放在下面,再Vivado中创建工程进行仿真。
原语模板如下:

IDDR #(
      .DDR_CLK_EDGE("OPPOSITE_EDGE"), // "OPPOSITE_EDGE", "SAME_EDGE" 
                                      //    or "SAME_EDGE_PIPELINED" 
      .INIT_Q1(1'b0), // Initial value of Q1: 1'b0 or 1'b1
      .INIT_Q2(1'b0), // Initial value of Q2: 1'b0 or 1'b1
      .SRTYPE("SYNC") // Set/Reset type: "SYNC" or "ASYNC" 
   ) IDDR_inst (
      .Q1(Q1), // 1-bit output for positive edge of clock
      .Q2(Q2), // 1-bit output for negative edge of clock
      .C(C),   // 1-bit clock input
      .CE(CE), // 1-bit clock enable input
      .D(D),   // 1-bit DDR data input
      .R(R),   // 1-bit reset
      .S(S)    // 1-bit set
   );

  设计文件代码:

module iddr_ctrl(
   input       clk      ,//系统时钟信号;
   input       rst      ,//系统复位信号,高电平有效;

   input       clk_en   ,//时钟使能信号;
   input       din      ,//输入数据;
   output      dout1    ,//输出数据
   output      dout2    
); 
   reg         clk_en_r ;
   //(* IOB = "TRUE" *)reg clk_en_r ;//将clk_en_r放在ILOGICE中;

   //将clk_en打拍,用于验证IOB原语是否有效;
   always@(posedge clk)begin
      clk_en_r <= clk_en;
   end

   //例化IDDR原语
   IDDR #(
      .DDR_CLK_EDGE  ("SAME_EDGE_PIPELINED"  ),// "OPPOSITE_EDGE", "SAME_EDGE" or "SAME_EDGE_PIPELINED" 
      .INIT_Q1       (1'b0                   ),// Initial value of Q1: 1'b0 or 1'b1
      .INIT_Q2       (1'b0                   ),// Initial value of Q2: 1'b0 or 1'b1
      .SRTYPE        ("SYNC"                 ) // Set/Reset type: "SYNC" or "ASYNC" 
   ) 
   IDDR_inst (
      .Q1   (dout1   ),// 1-bit output for positive edge of clock
      .Q2   (dout2   ),// 1-bit output for negative edge of clock
      .C    (clk     ),// 1-bit clock input
      .CE   (clk_en_r),// 1-bit clock enable input
      .D    (din     ),// 1-bit DDR data input
      .R    (rst     ),// 1-bit reset
      .S    (1'b0    ) // 1-bit set
   );

endmodule

  TestBench代码如下所示:

`timescale 1 ns/1 ns
module test();
    parameter	CYCLE		=   10      ;//系统时钟周期,单位ns,默认10ns;
    parameter	RST_TIME	=   10      ;//系统复位持续时间,默认10个系统时钟周期;

    reg			                clk     ;//系统时钟,默认100MHz;
    reg			                rst     ;//系统复位,默认高电平有效;
    reg                         clk_en  ;
    reg                         din     ;

    wire                        dout1   ;
    wire                        dout2   ;

    iddr_ctrl  u_iddr_ctrl (
        .clk    ( clk       ),
        .rst    ( rst       ),
        .clk_en ( clk_en    ),
        .din    ( din       ),
        .dout1  ( dout1     ),
        .dout2  ( dout2     )
    );

    //生成周期为CYCLE数值的系统时钟;
    initial begin
        clk = 1;
        forever #(CYCLE/2) clk = ~clk;
    end

    //生成复位信号;
    initial begin
        rst = 0;
        #2;
        rst = 1;//开始时复位10个时钟;
        #(RST_TIME*CYCLE);
        rst = 0;
        repeat(120) @(posedge clk);
        $stop;//停止仿真;
    end

    initial begin
        #1;
        din = 1'b0;clk_en = 1'b0;
        #(CYCLE*(10+RST_TIME));
        clk_en = 1'b1;
        #(CYCLE);
        repeat(100)begin//产生100个双沿时钟数据。
            #(CYCLE/2);
            din = ({$random} % 2);
            #(CYCLE/2);
            din = ({$random} % 2);
        end
        #(CYCLE);
        clk_en = 1'b0;
    end


endmodule

  仿真结果如图11所示,在时钟使能clk_en拉高后,输入信号din拉高后,在时钟的第二上升沿时,dout1和dout2同时输出高电平,后续波形也能与图8对应上,仿真通过。

在这里插入图片描述

图11 SAME_EDGE_PIPELINED模式仿真结果

  将IDDR的模式进行修改,代码如下,对IDDR的OPPOSITE_EDGE模式进行仿真。

module iddr_ctrl(
   input       clk      ,//系统时钟信号;
   input       rst      ,//系统复位信号,高电平有效;

   input       clk_en   ,//时钟使能信号;
   input       din      ,//输入数据;
   output      dout1    ,//输出数据
   output      dout2    
); 
   reg         clk_en_r ;
   //(* IOB = "TRUE" *)reg clk_en_r ;//将clk_en_r放在ILOGICE中;

   //将clk_en打拍,用于验证IOB原语是否有效;
   always@(posedge clk)begin
      clk_en_r <= clk_en;
   end

   //例化IDDR原语
   IDDR #(
      .DDR_CLK_EDGE  ("OPPOSITE_EDGE"  ),// "OPPOSITE_EDGE", "SAME_EDGE" or "SAME_EDGE_PIPELINED" 
      .INIT_Q1       (1'b0                   ),// Initial value of Q1: 1'b0 or 1'b1
      .INIT_Q2       (1'b0                   ),// Initial value of Q2: 1'b0 or 1'b1
      .SRTYPE        ("SYNC"                 ) // Set/Reset type: "SYNC" or "ASYNC" 
   ) 
   IDDR_inst (
      .Q1   (dout1   ),// 1-bit output for positive edge of clock
      .Q2   (dout2   ),// 1-bit output for negative edge of clock
      .C    (clk     ),// 1-bit clock input
      .CE   (clk_en_r),// 1-bit clock enable input
      .D    (din     ),// 1-bit DDR data input
      .R    (rst     ),// 1-bit reset
      .S    (1'b0    ) // 1-bit set
   );

endmodule

  仿真结果如图12所示,在din信号变化后,dout1在时钟上升沿输出采集到的数据,dout2在时钟下降沿输出在时钟下降沿采集到的数据,与时序图6对应,仿真通过。
xilinx原语介绍及仿真——IDDR_第10张图片

图12 OPPOSITE_EDGE模式仿真结果

  同样TestBetch文件不变,只需要将IDDR的模式变为SAME_EDGE模式,就可以对该模式进行仿真,对应代码如下。

module iddr_ctrl(
   input       clk      ,//系统时钟信号;
   input       rst      ,//系统复位信号,高电平有效;

   input       clk_en   ,//时钟使能信号;
   input       din      ,//输入数据;
   output      dout1    ,//输出数据
   output      dout2    
); 
   reg         clk_en_r ;
   //(* IOB = "TRUE" *)reg clk_en_r ;//将clk_en_r放在ILOGICE中;

   //将clk_en打拍,用于验证IOB原语是否有效;
   always@(posedge clk)begin
      clk_en_r <= clk_en;
   end

   //例化IDDR原语
   IDDR #(
      .DDR_CLK_EDGE  ("SAME_EDGE"  ),// "OPPOSITE_EDGE", "SAME_EDGE" or "SAME_EDGE_PIPELINED" 
      .INIT_Q1       (1'b0                   ),// Initial value of Q1: 1'b0 or 1'b1
      .INIT_Q2       (1'b0                   ),// Initial value of Q2: 1'b0 or 1'b1
      .SRTYPE        ("SYNC"                 ) // Set/Reset type: "SYNC" or "ASYNC" 
   ) 
   IDDR_inst (
      .Q1   (dout1   ),// 1-bit output for positive edge of clock
      .Q2   (dout2   ),// 1-bit output for negative edge of clock
      .C    (clk     ),// 1-bit clock input
      .CE   (clk_en_r),// 1-bit clock enable input
      .D    (din     ),// 1-bit DDR data input
      .R    (rst     ),// 1-bit reset
      .S    (1'b0    ) // 1-bit set
   );

endmodule

  仿真结果如图13所示,在din信号变化后,dout1在时钟上升沿输出采集到的数据,dout2在时钟上升沿输出其在时钟下降沿采集到的数据,与时序图7对应,仿真通过。
xilinx原语介绍及仿真——IDDR_第11张图片

图13 SAME_EDGE模式仿真结果

4、查看硬件走线

  上述仿真结束后,对工程进行综合、分配管脚、然后实现,在实现后,如图14所示,点击Open Implementation Design,然后选择Defaout Layout,放大查看走线。

xilinx原语介绍及仿真——IDDR_第12张图片

图14 查看布局布线后线路

  Vivado默认是将走线关闭的,点击图15中方框部分,就可以打开走线视图,查看更加详细的走线,以及小的结构单元。

xilinx原语介绍及仿真——IDDR_第13张图片

图15 打开走线

  图16就是布局布线后的一个走线,图中Y143是din输入所在管脚,灰色部分就是IOB,经过白线先到IDDR,然后经过dout1输出FPGA。

xilinx原语介绍及仿真——IDDR_第14张图片

图16 din到dout1的走线

  图17是将din所在管脚放大,din的管脚在IOB33,信号从金属管脚PAD进入芯片,然后经过了一个IBUF,通过I端口输出。由图也可以知道IOB可以实现管脚的上拉(PAD左边有类似波浪线的上拉电阻)和下拉,有IBUF、OBUF(IBUF左边那个)。

xilinx原语介绍及仿真——IDDR_第15张图片

图17 IOB模块

  上图中输出的信号经过一段距离传输,传输到图18所示的ILOGICE2的IDDR输入端口D了,由图18可知同一ILOGICE2(因为IDDR和IDELAYE2位置编号均为X1Y144)的IDDR和IDELAYE2分布在上下位置,此处没有使用IDELAYE2,信号就直接到达了IDDR。

xilinx原语介绍及仿真——IDDR_第16张图片

图18 IDDR结构图

  图18是din的信号走向,经过了IDDR,那如果不使用IDDR的信号,是否如之前所说,会直接经过IDDR上面的组合路径输出呢?

  我们可以通过查看clk_en信号的流向得到答案,这个信号没有经过IDDR,对应走线如下图19所示,结果与前文分析一致,所又输入信号都需要经过ILOGICE,没有使用ILOGICE内部IDDR、寄存器功能的信号,通过顶部组合逻辑电路输出。

xilinx原语介绍及仿真——IDDR_第17张图片

图19 clk_en信号流向

  最后图20是一个输出信号的管脚信号走向,目的是确定IOB单元内IBUF对面的就是OBUF结构,IBUF和OBUF是vivado自动对输入输出信号添加的。

xilinx原语介绍及仿真——IDDR_第18张图片

图20 输出信号走向

5、ILOGICE的寄存器(IFD)使用

  前文讲了如果不使用ILOGICE的IDDR功能,可以将通过使用原语,将ILOGICE配置成触发器,这个触发器相比FPGA内部逻辑的触发器,更靠近FPGA管脚,使接口信号更有利于满足建立时间要求。

  clk_en信号没有使用IDDR功能,那么此处在clk_en进入FPGA后,使用触发器打一拍后,先不做任何限制(去掉第10行代码注释,11行代码注释掉),然后对工程进行综合,去查看布线后的走线图,寄存器分布位置。

  在vivado综合编译之后,如图21是clk_en走线图,信号从端口输入,然后经过ILOGICE的组合逻辑部分,然后进入到FPGA内部CLB的一个D触发器中。

xilinx原语介绍及仿真——IDDR_第19张图片

图21 clk_en信号走线

  经图21中三个部分放大,如图22所示,比较平常的结果。

xilinx原语介绍及仿真——IDDR_第20张图片

图22 将图21的IOB、ILOGICE、D触发器放大

  如果在clk_en_r定义处添加IOB原语(将上述代码第10行注释,第11行注释取消), 在vivado综合编译之后,走线如图23所示,clk_en信号在经过ILOGICE时,并没有像图21一样,从组合逻辑部分直接输出,而是经过了下面部分。

xilinx原语介绍及仿真——IDDR_第21张图片

图23 clk_en信号的走线图

  将图23中ILOGICE部分进行放大,如图24所示,clk_en_r触发器就位于ILOGICE中IDDR位置,只是目前的功能是D触发器。

xilinx原语介绍及仿真——IDDR_第22张图片

图24 放大clk_en信号的ILOGICE

  对上述代码进行仿真,查看clk_en是否被延迟一个时钟周期,仿真结果如图25所示,clk_en_r相对clk_en延迟一个时钟周期,仿真正确。

xilinx原语介绍及仿真——IDDR_第23张图片

图25 仿真截图

  很明显图23中clk_en从PAD到clk_en_r触发器的路径,相比图21中的路径会短很多,并且走线都是固定的,clk_en_r的位置也是固定的,不能进行随意更换,在ADC采集数据时,可以将触发器放入ILOGICE减小延时。

  总结本文就几点:

第一:了解ILOGICE的结构及功能,能够实现IDDR和触发器功能。
第二:熟悉IDDR的三种模式,常用的是SAME_EDGE_PIPELINED模式,并对三种模式依次仿真,通过查看走线图,更加详细了解IOB和ILOGICE的结构。
第三:通过使用原语,将触发器放入ILOGICE中,减少从FPGA管脚到触发器的路径。

  最后需要此工程文件的用户,在公众号后台回复“IDDR”(不包括引号)即可,工程里只有一个设计文件,因为三个文件只需要修改IDDR的工作模式即可,IDDR会在千兆网接口中使用。

你可能感兴趣的:(FPGA,fpga开发)