我是靠谱客的博主 忐忑野狼,最近开发中收集的这篇文章主要介绍FPGA原语IODELAY、ODDR、BUFGMUX和VIVADO BRAM的使用1 IODELAY微调时钟相位2 ODDR使用与仿真3 BUFGMUX使用4 vivado BRAM IP的配置选项,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

目录

1 IODELAY微调时钟相位

2 ODDR使用与仿真

3 BUFGMUX使用

4 vivado BRAM IP的配置选项


1 IODELAY微调时钟相位

 #To Adjust GMII Tx Input Setup/Hold Timing

#set_property IDELAY_VALUE 16 [get_cells *_i/gmii_to_rgmii_0/U0/i_gmii_to_rgmii_block/*_gmii_to_rgmii_0_0_core/i_gmii_to_rgmii/i_gmii_to_rgmii/gen_rgmii_rx_zq.delay_rgmii_rx_ctl]

#set_property IDELAY_VALUE 16 [get_cells -hier -filter {name =~ *_i/gmii_to_rgmii_0/U0/*_gmii_to_rgmii_0_0_core/*delay_rgmii_rxd*}]

#set_property IODELAY_GROUP tri_mode_ethernet_mac_iodelay_grp1 [get_cells *_i/gmii_to_rgmii_0/U0/i_gmii_to_rgmii_block/*_gmii_to_rgmii_0_0_core/i_gmii_to_rgmii/i_gmii_to_rgmii/gen_rgmii_rx_zq.delay_rgmii_rx_ctl]

#set_property IODELAY_GROUP tri_mode_ethernet_mac_iodelay_grp1 [get_cells -hier -filter {name =~ *_i/gmii_to_rgmii_0/U0/*_gmii_to_rgmii_0_0_core/*delay_rgmii_rxd*}]

#set_property IODELAY_GROUP tri_mode_ethernet_mac_iodelay_grp1 [get_cells *_i/gmii_to_rgmii_0/U0/i_*_gmii_to_rgmii_0_0_idelayctrl]

2 ODDR使用与仿真

1)使用方法

在DDR接口中ODDR用于发送时钟和数据;

在SDR接口中仅用ODDR转发时钟(仍在时钟树内),输出端要直连到输出port,不可加逻辑;

使用时钟专用输入管脚输出时钟=使用GPIO输出时钟,必须使用ODDR

发送多位数据时需要用generate语句例化多个ODDR原语,参见如下链接(ODDR的使用错误):

ODDR的使用错误_christne1225i的专栏-CSDN博客 主要内容引用如下:

ODDR#(

      .DDR_CLK_EDGE("OPPOSITE_EDGE"),//"OPPOSITE_EDGE" or "SAME_EDGE"

      .INIT(1'b0),    // Initial value of Q: 1'b0 or 1'b1

      .SRTYPE("SYNC") // Set/Resettype: "SYNC" or "ASYNC"

   ) ODDR_inst (

      .Q    (Q),   // 1-bit DDR output

      .C    (C),  // 1-bit clock input

      .CE  (CE),// 1-bit clock enable input

      .D1  (D1),// 1-bit data input (positive edge)

      .D2  (D2),// 1-bit data input (negative edge)

      .R    (R),   // 1-bit reset

      .S     (S)    // 1-bit set

   );

我的使用方法为:

wire[63:0] do32;

wire[31:0]    do_o;

wiredo_clk_sel;

wire[31:0]    do_en;

genvar  dq_o;

generate

             for(dq_o= 0; dq_o < 32; dq_o = dq_o+1) begin: gen_do

                                     ODDR #(

                                                                .DDR_CLK_EDGE("SAME_EDGE"),

                                                                 .INIT(1'b0),

                                                                 .SRTYPE("SYNC")

                                                      ) do_oddr (

                                                                 .Q           (do_o[dq_o]                      ),

                                                                 .C           (do_clk_sel                        ),

                                                                 .CE  (1'b1                                  ),

                                                                 .D1  (do32[dq_o]               ),//64位

                                                                 .D2  (do32[dq_o+ 32] ),

                                                                 .R    (do_en[dq_o]                           ),

                                                                 .S     (1'b0                                  )

                                                              );

             end

assign dio[dq_o]=do_if_ctrl[dq_o]? (do_reg_vld[dq_o]?do_reg[dq_o]: do_dout_vld? do_dout[dq_o] : do_df_out_en[ dq_o ] &(~do_df_out_en_iv[dq_o]) ?  do_df[dq_o ]: 1'bz ) :1’bz;

endgenerate

错误的原因是ODDR的输出必须直接连到输出pad上,不可以再引进逻辑内部。因此会出现do_oddr的输出无法连入OLOGIC中。

我的解决办法是:

通过IOBUF将双向dio数据分离成要输入到FPGA中的di_d和从FPGA获得do_o. IOBUF的控制位T为高时FPGA输入I端口数据使能,为低时输出O使能。

2)数据输入捕获模式

      OPPOSITE_EDGE模式、SAME_EDGE模式区别在于前者先后使用上升下降沿捕获数据到ODDR内部,后者同时在上升沿捕获两个端口的数据到ODDR内部。两者的输出相同,都是在不同的沿输出各自数据。

 3)仿真

输出端口在CE=1后并不是立即工作,大约有105ns多的等待期。原语模块代码:

`timescale 1ns / 1ps

module oddr(
output wire  Q,
input wire  C,
input wire  CE,
input wire D1, 
input wire   D2,  
input wire   R,  
input wire   S  
    );   

   ODDR #(
   .DDR_CLK_EDGE("OPPOSITE_EDGE"), // "OPPOSITE_EDGE" or "SAME_EDGE" 
   .INIT(1'b0),    // Initial value of Q: 1'b0 or 1'b1
   .SRTYPE("SYNC") // Set/Reset type: "SYNC" or "ASYNC" 
) ODDR_clk (
   .Q(Q),   // 1-bit DDR output
   .C(C),   // 1-bit clock input
   .CE(CE), // 1-bit clock enable input
   .D1(D1), // 1-bit data input (positive edge)
   .D2(D2), // 1-bit data input (negative edge)
   .R(R),   // 1-bit reset
   .S(S)    // 1-bit set
);    
endmodule

简单的仿真代码: 

`timescale 1ns / 1ps

module oddr_tb();
 wire  Q;
 reg  C;
 reg  CE;
 reg  D1; 
 reg   D2;  
 reg   R;  
 reg   S ; 
initial     
begin 
C = 0;
CE= 1;
D1= 0;
D2= 1;
R=0;
S=0; 
end

 initial     
begin 
#2 R=0;
#2 R=1; 
end 
//时钟
always #15 C=~C;      

 oddr i1 (
   .Q(Q),   // 1-bit DDR output
   .C(C),   // 1-bit clock input
   .CE(CE), // 1-bit clock enable input
   .D1(D1), // 1-bit data input (positive edge)
   .D2(D2), // 1-bit data input (negative edge)
   .R(R),   // 1-bit reset
   .S(S)    // 1-bit set
   );

endmodule

Q端输出比端的延时大约为0.1ns 

 IDDR也存在等待周期:见下图

在以下文章中也提到了在IDDR使用时也存在等待周期:

IDDR仿真_猜猜_新浪博客 文中提到:

需要注意的几点

1. IDDR模块在CE信号变高之后会有一些设定时间,所以在CE信号变高的同时给出data不是一个很好的选择。我在data输出代码里加入了10个cycle的延迟。

2.IDDR对clk是边缘敏感,图中的红色线箭头可以看出,IDDR根据clk_ddr_t信号的上升下降的边缘得到data再输出。之前使用过图中的ds_low来作为IDDR驱动时钟,可是data输出不正常。

3 BUFGMUX使用

1)在多个时钟选择输出1个时,使用BUFGMUX,xilinx官方手册UG382 (38页);

2)参数Clk type: "SYNC" or "ASYNC"

SYNC:两个输入时钟必须都有效,在切换信号变化后,输出保持无效(0 or 1都可能)直到后一个clk的变化沿(上下沿)时输出时钟;The primitive guarantees that when the select line S is toggled to choose the other clock source, the output remains in the inactive state until the next active clock edge on either input.

ASYNC:切换信号变化后,立即输出下一个时钟。

 3)例化代码

BUFGMUX #(

   .CLK_SEL_TYPE("ASYNC" )// Clk type: "SYNC" or "ASYNC" (原语模版中没有注明)

     )

     BUFGMUX_1M_8M (

        .O(clk_out_i),   // 1-bit output: Clock output

        .I0(clk_divider[4]), // 1-bit input: Clock input (S=0)

        .I1(clk_divider[1]), // 1-bit input: Clock input (S=1)

        .S(s[0])    // 1-bit input: Clock select

     );

4)MUX上电后的输出有110ns左右的等待期,之后才正常用S端控制。在此期间控制端口为默认值0,输出端口输出I0默认值。

4 vivado BRAM IP的配置选项

BRAM设置界面的配置,如下入中三个框内:

1)Oprating Mode有读优先、写优先、NO_change三种模式,根据实际需求配置。NO_change功耗低;

2)输出的寄存器配置,绿色框内为BRAM内部的reg,蓝色框内为BRAM外部Slice中reg,两个都使用时数据延时3clk输出,能够获得更好的时序和性能。

3)不要使用异步复位;

4) 可通过vivado自带的仿真功能进行仿真验证。

 

把我在AET blog上的四篇文章合并一篇到CSDN,方便查看。

IODELAY微调时钟相位-Bryan-电子技术应用-AET-中国科技核心期刊-最丰富的电子设计资源平台

 BUFGMUX使用-Bryan-电子技术应用-AET-中国科技核心期刊-最丰富的电子设计资源平台

ODDR使用与仿真-Bryan-电子技术应用-AET-中国科技核心期刊-最丰富的电子设计资源平台

 BRAM IP的配置选项-Bryan-电子技术应用-AET-中国科技核心期刊-最丰富的电子设计资源平台

最后

以上就是忐忑野狼为你收集整理的FPGA原语IODELAY、ODDR、BUFGMUX和VIVADO BRAM的使用1 IODELAY微调时钟相位2 ODDR使用与仿真3 BUFGMUX使用4 vivado BRAM IP的配置选项的全部内容,希望文章能够帮你解决FPGA原语IODELAY、ODDR、BUFGMUX和VIVADO BRAM的使用1 IODELAY微调时钟相位2 ODDR使用与仿真3 BUFGMUX使用4 vivado BRAM IP的配置选项所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(53)

评论列表共有 0 条评论

立即
投稿
返回
顶部