目前,大型设计一般推荐使用同步时序电路。同步时序电路基于时钟触发沿设计,对时钟的周期、占空比、延时和抖动提出了更高的要求。为了满足同步时序设计的要求,一般在FPGA设 计中采用全局时钟资源驱动设计的主时钟,以达到最低的时钟抖动和延迟。FPGA全局时钟资源一般使用全铜层工艺实现,并设计了专用时钟缓冲与驱动结构,从 而使全局时钟到达芯片内部的所有可配置单元(CLB)、I/O单元(IOB)和选择性块RAM(BlockSelectRAM)的时延和抖动都为最小。为 了适应复杂设计的需要,Xilinx的FPGA中集成的专用时钟资源与数字延迟锁相环(DLL)的数目不断增加,最新的VirtexII器件最多可以提供16个全局时钟输入端口和8个数字时钟管理模块(DCM)。 与全局时钟资源相关的原语常用的与全局时钟资源相关的Xilinx器件原语包括:IBUFG、IBUFGDS、BUFG、BUFGP、BUFGCE、BUFGMUX、BUFGDLL和DCM等。
1.IBUFG即输入全局缓冲,是与专用全局时钟输入管脚相连接的首级全局缓冲。所有从全局时钟管脚输入的信号必须经过IBUF元,否则在布局 布线时会报错。IBUFG支持AGP、CTT、GTL、GTLP、HSTL、LVCMOS、LVDCI、LVDS、LVPECL、LVTTL、PCI、 PCIX和SSTL等多种格式的IO标准。
2.IBUFGDS是IBUFG的差分形式,当信号从一对差分全局时钟管脚输入时,必须使用IBUFGDS作为全局时钟输入缓冲。IBUFG支持BLVDS、LDT、LVDSEXT、LVDS、LVPECL和ULVDS等多种格式的IO标准。
3.BUFG是全局缓冲,它的输入是IBUFG的输出,BUFG的输出到达FPGA内部的IOB、CLB、选择性块RAM的时钟延迟和抖动最小。
4.BUFGCE是带有时钟使能端的全局缓冲。它有一个输入I、一个使能端CE和一个输出端O。只有当BUFGCE的使能端CE有效(高电平)时,BUFGCE才有输出。
5.BUFGMUX是全局时钟选择缓冲,它有I0和I1两个输入,一个控制端S,一个输出端O。当S为低电平时输出时钟为I0,反之为I1。需要指出的是BUFGMUX的应用十分灵活,I0和I1两个输入时钟甚至可以为异步关系。
6.BUFGP相当于IBUG加上BUFG。
7.BUFGDLL是全局缓冲延迟锁相环,相当于BUFG与DLL的结合。BUFGDLL在早期设计中经常使用,用以完成全局时钟的同步和驱动等功能。随着数字时钟管理单元(DCM)的日益完善,目前BUFGDLL的应用已经逐渐被DCM所取代。
8.DCM即数字时钟管理单元,主要完成时钟的同步、移相、分频、倍频和去抖动等。DCM与全局时钟有着密不可分的联系,为了达到最小的延迟和 抖动,几乎所有的DCM应用都要使用全局缓冲资源。DCM可以用XilinxISE软件中的ArchitectureWizard直接生成。
全局时钟资源的使用方法
1.IBUFG+BUFG的使用方法:
IBUFG后面连接BUFG的方法是最基本的全局时钟资源使用方法,由于IBUFG组合BUFG相当于BUFGP,所以在这种使用方法也称为BUFGP方法。
2.IBUFGDS+BUFG的使用方法:
当输入时钟信号为差分信号时,需要使用IBUFGDS代替IBUFG。
3.IBUFG+DCM+BUFG的使用方法:
这种使用方法最灵活,对全局时钟的控制更加有效。通过DCM模块不仅仅能对时钟进行同步、移相、分频和倍频等变换,而且可以使全局时钟的输出达到无抖动延迟。
4.Logic+BUFG的使用方法:
BUFG不但可以驱动IBUFG的输出,还可以驱动其它普通信号的输出。当某个信号(时钟、使能、快速路径)的扇出非常大,并且要求抖动延迟最 小时,可以使用BUFG驱动该信号,使该信号利用全局时钟资源。但需要注意的是,普通IO的输入或普通片内信号进入全局时钟布线层需要一个固有的延时,一 般在10ns左右,即普通IO和普通片内信号从输入到BUFG输出有一个约10ns左右的固有延时,但是BUFG的输出到片内所有单元(IOB、CLB、 选择性块RAM)的延时可以忽略不计为“0”ns。
5.Logic+DCM+BUFG的使用方法:
DCM同样也可以控制并变换普通时钟信号,即DCM的输入也可以是普通片内信号。使用全局时钟资源的注意事项全局时钟资源必须满足的重要原则 是:使用IBUFG或IBUFGDS的充分必要条件是信号从专用全局时钟管脚输入。换言之,当某个信号从全局时钟管脚输入,不论它是否为时钟信号,都必须 使用IBUFG或IBUFGDS;如果对某个信号使用了IBUFG或IBUFG DS硬件原语,则这个信号必定是从全局时钟管脚输入的。如果违反了这条原则,那么在布局布线时会报错。这条规则的使用是由FPGA的内部结构决定的:IBUFG和IBUFGDS的输入端仅仅与芯片的专用全局时钟输入管脚有物理连接,与普通IO和其它内部CLB等没有物理连接。另外,由于BUFGP相当于IBUFG和BUFG的组合,所以BUFGP的使用也必须遵循上述的原则。
全局时钟资源的例化方法
全局时钟资源的例化方法大致可分为两种:
一是在程序中直接例化全局时钟资源;
二是通过综合阶段约束或者实现阶段约束实现对全局时钟资源的使用;
第一种方法比较简单,用户只需按照前面讲述的5种全局时钟资源的基本使用方法编写代码或者绘制原理图即可。
第二方法是通过综合阶段约束或实现阶段的约束完成对全局时钟资源的调用,这种方法根据综合工具和布局布线工具的不同而异。
使用DCM,有两种方法。记住CLKFB的输入是CLK0进过一级BUFG处理后得到的信号
一,就是直接调用原语DCM_ADV或者DCM_BASE。该种方法需要手工添加BUFG和IBUGDS等。在调用原语前,先使用defparam对其进行参数设置。如下例所示:
IBUFDS refclk_ibufds(
.I(REFCLK200P),
.IB(REFCLK200N),
.O(refclk200)
);
defparam U_DCM_CLK200.DLL_FREQUENCY_MODE = "HIGH";
defparam U_DCM_CLK200.DFS_FREQUENCY_MODE = "HIGH";
defparam U_DCM_CLK200.DUTY_CYCLE_CORRECTION = "TRUE";
defparam U_DCM_CLK200.CLKDV_DIVIDE = 5.0;
defparam U_DCM_CLK200.CLKFX_MULTIPLY = 4;
defparam U_DCM_CLK200.CLKFX_DIVIDE = 5;
defparam U_DCM_CLK200.FACTORY_JF = 16'hF0F0;
defparam U_DCM_CLK200.DCM_PERFORMANCE_MODE = "MAX_SPEED";
defparam U_DCM_CLK200.CLK_FEEDBACK = "1X";
DCM_BASE
U_DCM_CLK200(
.CLKFB(Gclk200),
.CLKIN(refclk200),
.RST(HardRst),
.CLK0(clk200_dcm),
.CLK90(clk200_90_dcm),
.CLK180(),
.CLK270(),
.CLK2X(),
.CLK2X180(),
.CLKDV(clk200_div_dcm),
.CLKFX(clk200_fx_dcm),
.CLKFX180(),
.LOCKED(clk200_dcm_locked)
);
BUFG CLK200_BUFG (.I(clk200_dcm),.O(Gclk200));
BUFG CLK200_P90_BUFG (.I(clk200_90_dcm),.O(Gclk200_90));
BUFGCLK200_DV_BUFG (.I(clk200_div_dcm), .O(Gclk40));
对于DCM_ADV,则例化模型如下
DCM_ADV U_DCM_CLK200(
.CLKFB(Gclk200),
.CLKIN(refclk200),
.RST(HardRst),
.PSCLK(),
.PSINCDEC(),
.PSEN(),
.DI(),
.ADDR (),
.DWE(),
.DEN(),
.DCLK(),
.CLK0(clk200_dcm),
.CLK90(clk200_90_dcm),
.CLK180(),
.CLK270(),
.CLK2X(),
.CLK2X180(),
.CLKDV(clk200_div_dcm),
.CLKFX(clk200_fx_dcm),
.CLKFX180(),
.LOCKED(clk200_dcm_locked),
.PSDONE(),
.DO(),
.DRDY()
);
其相关的信号和参数说明都是可以在ISE的文档中找到的
二,IP core来实现。该种实现方法一般会自动连上BUFG,因此不需要手工添加。但是还是要查看wrapper文件确认一下。如果warpper文件中没有自动添加,则需要自己手工添加BUFG。下面附上一个wrapper文件用以研究。
module DCM180(CLKIN_IN,
RST_IN,
CLKDV_OUT,
CLKFX_OUT,
CLKFX180_OUT,
CLKIN_IBUFG_OUT,
CLK0_OUT,
CLK2X_OUT,
CLK2X180_OUT,
CLK90_OUT,
CLK180_OUT,
CLK270_OUT,
DO_OUT,
LOCKED_OUT);
input CLKIN_IN;
input RST_IN;
output CLKDV_OUT;
output CLKFX_OUT;
output CLKFX180_OUT;
output CLKIN_IBUFG_OUT;
output CLK0_OUT;
output CLK2X_OUT;
output CLK2X180_OUT;
output CLK90_OUT;
output CLK180_OUT;
output CLK270_OUT;
output [15:0] DO_OUT;
output LOCKED_OUT;
wire CLKDV_BUF;
wire CLKFB_IN;
wire CLKFX_BUF;
wire CLKFX180_BUF;
wire CLKIN_IBUFG;
wire CLK0_BUF;
wire CLK2X_BUF;
wire CLK2X180_BUF;
wire CLK90_BUF;
wire CLK180_BUF;
wire CLK270_BUF;
wire GND_BIT;
wire [6:0] GND_BUS_7;
wire [15:0] GND_BUS_16;
assign GND_BIT = 0;
assign GND_BUS_7 = 7'b0000000;
assign GND_BUS_16 = 16'b0000000000000000;
assign CLKIN_IBUFG_OUT = CLKIN_IBUFG;
assign CLK0_OUT = CLKFB_IN;
BUFG CLKDV_BUFG_INST (.I(CLKDV_BUF), .O(CLKDV_OUT));
BUFG CLKFX_BUFG_INST (.I(CLKFX_BUF), .O(CLKFX_OUT));
BUFG CLKFX180_BUFG_INST (.I(CLKFX180_BUF), .O(CLKFX180_OUT));
IBUFG CLKIN_IBUFG_INST (.I(CLKIN_IN), .O(CLKIN_IBUFG));
BUFG CLK0_BUFG_INST (.I(CLK0_BUF), .O(CLKFB_IN));
BUFG CLK2X_BUFG_INST (.I(CLK2X_BUF), .O(CLK2X_OUT));
BUFG CLK2X180_BUFG_INST (.I(CLK2X180_BUF), .O(CLK2X180_OUT));
BUFG CLK90_BUFG_INST (.I(CLK90_BUF), .O(CLK90_OUT));
BUFG CLK180_BUFG_INST (.I(CLK180_BUF), .O(CLK180_OUT));
BUFG CLK270_BUFG_INST (.I(CLK270_BUF), .O(CLK270_OUT));
DCM_ADV DCM_ADV_INST (.CLKFB(CLKFB_IN),
.CLKIN(CLKIN_IBUFG),
.DADDR(GND_BUS_7[6:0]),
.DCLK(GND_BIT),
.DEN(GND_BIT),
.DI(GND_BUS_16[15:0]),
.DWE(GND_BIT),
.PSCLK(GND_BIT),
.PSEN(GND_BIT),
.PSINCDEC(GND_BIT),
.RST(RST_IN),
.CLKDV(CLKDV_BUF),
.CLKFX(CLKFX_BUF),
.CLKFX180(CLKFX180_BUF),
.CLK0(CLK0_BUF),
.CLK2X(CLK2X_BUF),
.CLK2X180(CLK2X180_BUF),
.CLK90(CLK90_BUF),
.CLK180(CLK180_BUF),
.CLK270(CLK270_BUF),
.DO(DO_OUT[15:0]),
.DRDY(),
.LOCKED(LOCKED_OUT),
.PSDONE());
defparam DCM_ADV_INST.CLK_FEEDBACK = "1X";
defparam DCM_ADV_INST.CLKDV_DIVIDE = 4.0;
defparam DCM_ADV_INST.CLKFX_DIVIDE = 1;
defparam DCM_ADV_INST.CLKFX_MULTIPLY = 3;
defparam DCM_ADV_INST.CLKIN_DIVIDE_BY_2 = "FALSE";
defparam DCM_ADV_INST.CLKIN_PERIOD = 10.000;
defparam DCM_ADV_INST.CLKOUT_PHASE_SHIFT = "NONE";
defparam DCM_ADV_INST.DCM_AUTOCALIBRATION = "TRUE";
defparam DCM_ADV_INST.DCM_PERFORMANCE_MODE = "MAX_SPEED";
defparam DCM_ADV_INST.DESKEW_ADJUST = "SYSTEM_SYNCHRONOUS";
defparam DCM_ADV_INST.DFS_FREQUENCY_MODE = "HIGH";
defparam DCM_ADV_INST.DLL_FREQUENCY_MODE = "LOW";
defparam DCM_ADV_INST.DUTY_CYCLE_CORRECTION = "TRUE";
defparam DCM_ADV_INST.FACTORY_JF = 16'hF0F0;
defparam DCM_ADV_INST.PHASE_SHIFT = 0;
defparam DCM_ADV_INST.STARTUP_WAIT = "FALSE";
defparam DCM_ADV_INST.SIM_DEVICE = "VIRTEX5";
endmodule
其中defparam语句代表DCM的参数。
对应通过CoreGen产生的DCM来说,可以通过以下方法来例化多个不同参数的实例DCM,而不必每次都要重新生成一个核。
defparam uDCM.DCM_ADV_INST.CLK_FEEDBACK = "1X";
defparam uDCM.DCM_ADV_INST.CLKDV_DIVIDE = 2.0;
defparam uDCM.DCM_ADV_INST.CLKFX_DIVIDE = 1;
defparam uDCM.DCM_ADV_INST.CLKFX_MULTIPLY = 3;
defparam uDCM.DCM_ADV_INST.CLKIN_DIVIDE_BY_2 = "FALSE";
defparam uDCM.DCM_ADV_INST.CLKIN_PERIOD = 20.000;
DCM180 uDCM(
.CLKIN_IN(clk),
.RST_IN(rst_n),
.CLKDV_OUT(clkdv),
.CLKFX_OUT(clkfx),
.CLKFX180_OUT(clkfx180),
.CLKIN_IBUFG_OUT(clkibufg),
.CLK0_OUT(clk0),
.CLK2X_OUT(clk2x),
.CLK2X180_OUT(clk2x180),
.CLK90_OUT(clk90),
.CLK180_OUT(clk180),
.CLK270_OUT(clk270),
.DO_OUT(ddo),
.LOCKED_OUT(locked)
);
这样在综合之后,DCM的CLKDV_DIVIDE就由4.0变成2.0了。其他的也是同样变化 |