目录
一、前言
二、设计示例
2.1 设计代码
2.2 schematic
2.3 no overwriteing
2.4 约束到非时钟引脚
三、Create_clock应用
3.1 时钟输入端口
3.2 7系列高速收发器输出管脚
3.3 部分原语的输出管脚
3.4 主时钟路径上创建主时钟
3.5 虚拟时钟
3.6 差分时钟的约束
一、前言
时序约束中,使用Create_clock约束来生成主时钟,主时钟可以说是设计的心脏。主时钟是来自FPGA芯片外部的时钟,通过时钟输入端口或高速收发器GT的输出引脚进入FPGA内部。对于赛灵思7系列的器件,主时钟必须手动定义到GT的输出,对于Ultrascale和Ultrascale+系列的器件,定时器会自动地接入到GT的输出。
生成时钟通常来源于设计内部的时钟管理单元,如MMCM,PLL等,生成时钟是与主时钟(使用create_clock创建的时钟)相关,其来源来自主时钟或其他生成时钟。因此,需先定义主时钟,再定义生成时钟。优点是主时钟变化时生成时钟会同步进行变化。
二、设计示例
2.1 设计代码
module create_clock(CLKIN1,CLKIN2,CLKINSEL,CLKFBIN,rst,d,ff_clkout0_a,ff1);
input CLKIN1,CLKIN2,CLKINSEL,CLKFBIN,rst,d;
output reg ff_clkout0_a,ff1;
reg ff_clkout0,ff0;PLLE2_ADV #(.BANDWIDTH("OPTIMIZED"), // OPTIMIZED, HIGH, LOW.CLKFBOUT_MULT(8), // Multiply value for all CLKOUT, (2-64).CLKFBOUT_PHASE(90.0), // Phase offset in degrees of CLKFB, (-360.000-360.000).// CLKIN_PERIOD: Input clock period in nS to ps resolution (i.e. 33.333 is 30 MHz)..CLKIN1_PERIOD(0.0),.CLKIN2_PERIOD(0.0),// CLKOUT0_DIVIDE - CLKOUT5_DIVIDE: Divide amount for CLKOUT (1-128).CLKOUT0_DIVIDE(1),.CLKOUT1_DIVIDE(2),.CLKOUT2_DIVIDE(4),// CLKOUT0_DUTY_CYCLE - CLKOUT5_DUTY_CYCLE: Duty cycle for CLKOUT outputs (0.001-0.999)..CLKOUT0_DUTY_CYCLE(0.4),.CLKOUT1_DUTY_CYCLE(0.5),.CLKOUT2_DUTY_CYCLE(0.5),// CLKOUT0_PHASE - CLKOUT5_PHASE: Phase offset for CLKOUT outputs (-360.000-360.000)..CLKOUT0_PHASE(0.0),.CLKOUT1_PHASE(0.0),.CLKOUT2_PHASE(0.0),.COMPENSATION("EXTERNAL"), // ZHOLD, BUF_IN, EXTERNAL, INTERNAL.DIVCLK_DIVIDE(1), // Master division value (1-56)// REF_JITTER: Reference input jitter in UI (0.000-0.999)..REF_JITTER1(0.0),.REF_JITTER2(0.0),.STARTUP_WAIT("FALSE") // Delay DONE until PLL Locks, ("TRUE"/"FALSE"))PLLE2_ADV_inst (// Clock Outputs: 1-bit (each) output: User configurable clock outputs.CLKOUT0(CLKOUT0), // 1-bit output: CLKOUT0.CLKOUT1(CLKOUT1), // 1-bit output: CLKOUT1.CLKOUT2(CLKOUT2), // 1-bit output: CLKOUT2// Feedback Clocks: 1-bit (each) output: Clock feedback ports.CLKFBOUT(CLKFBOUT), // 1-bit output: Feedback clock// Clock Inputs: 1-bit (each) input: Clock inputs.CLKIN1(CLKIN1), // 1-bit input: Primary clock.CLKIN2(CLKIN2), // 1-bit input: Secondary clock// Control Ports: 1-bit (each) input: PLL control ports.CLKINSEL(CLKINSEL), // 1-bit input: Clock select, High=CLKIN1 Low=CLKIN2.RST(rst), // 1-bit input: Reset// Feedback Clocks: 1-bit (each) input: Clock feedback ports.CLKFBIN(CLKFBIN) // 1-bit input: Feedback clock);// End of PLLE2_ADV_inst instantiationalways@(posedge CLKOUT0,negedge rst)if(!rst)ff_clkout0<=1'b0;else beginff_clkout0<=d;end
always@(posedge CLKOUT0,negedge rst)if(!rst)ff_clkout0_a<=1'b0;else beginff_clkout0_a<=ff_clkout0;end
always@(posedge CLKIN1,negedge rst)if(!rst)ff0<=1'b0;else beginff0<=ff_clkout0;end
always@(posedge CLKIN1,negedge rst)if(!rst)ff1<=1'b0;else beginff1<=ff0;end
endmodule
2.2 schematic
生成时钟与主时钟关系可以是分频,倍频,非整数倍频率,相移,占空比切换,以及上述关系的组合。
2.3 no overwriteing
在使用Create_clock约束的时候,存在一个设置项Add this clock to the existing clock(no overwriteing),即不要覆盖已存在的时钟,通俗理解就是如果约束的位置存在create_clock时,不要覆盖,勾选则是两个时钟共存。以如下约束为例,在端口CLKIN1上约束创建了两个主时钟clkin1,clkin1_1,但clkin1_1未勾选no overwriting
create_clock -period 10.000 -name clkin1 -waveform {0.000 5.000} [get_ports CLKIN1]
create_clock -period 10.000 -name clkin1_1 -waveform {0.000 5.000} [get_ports CLKIN1]
create_clock -period 10.000 -name clkin2 -waveform {0.000 5.000} [get_ports CLKIN2]
create_generated_clock -name clkout0 -source [get_ports CLKIN1] -multiply_by 2 -add -master_clock [get_clocks clkin1] [get_pins PLLE2_ADV_inst/CLKOUT0]
查看Clock summary,只有clkin1_1,因clkin1被覆盖了所以没有clkin1
如果clkin1_1勾选no overwriting,约束如下
create_clock -period 10.000 -name clkin1_1 -waveform {0.000 5.000} -add [get_ports CLKIN1]
clock summary中clkin1和clkin1_1同时存在
同时,在时序报告中,会分析clkin1和clkin1_1间的时序结果,即将两者作为独立的时钟
在clock interaction中显示clkin1和clkin1_1的关系为Timed(unsafe)
2.4 约束到非时钟引脚
create_clock如果约束到非时钟引脚上,仍能进行正常时序分析,只是属于不合理的用法
如下示例,约束到LUT单元ff0_i_1/o上,时钟名为clk_lut
create_clock -period 10.000 -name clkin2 -waveform {0.000 5.000} [get_ports CLKIN2]
create_clock -period 10.000 -name clkin1 -waveform {0.000 5.000} [get_ports CLKIN1]
create_generated_clock -name clkout0 -source [get_ports CLKIN1] -multiply_by 2 -add -master_clock clkin1 [get_pins PLLE2_ADV_inst/CLKOUT0]
create_clock -period 9.000 -name clk_lut -waveform {0.000 4.500} [get_pins ff0_i_1/O]
ff0_i_1的输出连接到触发器ff0_reg上
时序分析报告中存在clk_lut到clkin1的时序路径
此时路径的source clock delay为0,data path的起点为ff0_i_1/o
三、Create_clock应用
3.1 时钟输入端口
时钟输入端口使用create_clock创建主时钟是最常见的场景,如下图,在sysclk端口上创建主时钟,时钟经过IBUF和BUFG驱动触发器REGA和REGB
时钟周期为10ns,占空比为50%的约束示例如下:
create_clock -name SysClk -period 10 -waveform {0 5} [get_ports sysclk]
3.2 7系列高速收发器输出管脚
第二种场景是设计中存在高速收发器GT,GT的时钟输出引脚提供时钟,如下连接设计
在gt0的TXOUTCLK引脚上创建主时钟,通过驱动mmcm0来驱动设计中的其他时序单元,
create_clock -name SysClk -period 10 -waveform {0 5} [get_pins gt0/TXOUTCLK]
注意:标题之所以指明7系列器件是因为UltraScale和UltraScale+器件的设计, AMD 不建议在 GT 的输出上定义基准时钟, 因为在定义 REFCLK 输入时钟时, 将自动衍生 GT 时钟。
3.3 部分原语的输出管脚
如下图,对于instA,因为没有输入IN到输出OUT的arc,sysclk上的时钟无法传播到OUT,此时如果要实现传播后的效果,可使用create_clock在instA/OUT上创建主时钟,从而驱动后面的时序单元。
3.4 主时钟路径上创建主时钟
对于在主时钟驱动的路径上重新创建主时钟的做法是不建议的,如下图,在sysclk上创建了一个主时钟clk0,在clk0驱动的BUFG1上又创建了一个主时钟clk1,clk1将会覆盖传播到该处的clk0,从而导致时序分析时,REGA和REGB间发起时钟和捕获时钟的时钟偏斜较大,分析不准,不符合实际情况。
3.5 虚拟时钟
虚拟时钟是设计中的一种特殊时钟,它的生成不需要物理引脚,通常用于FPGA芯片的外部接口时序分析,因为,外部器件的时钟不会直接连接到FPGA上,所以可以通过虚拟时钟来模拟外部时钟与FPGA引脚的关系。
虚拟时钟通过create_clock约束生成,约束时不指定Source objects,只需设置名称和波形,下图示例为创建周期为10ns的虚拟时钟
create_clock -period 10.000 -name virtual_clcok -waveform {0.000 5.000}
虚拟时钟通常结合set_input_delay和set_output_delay使用
create_clock -period 10.000 -name virtual_clcok -waveform {0.000 5.000}
set_output_delay -clock [get_clocks virtual_clcok] 1.123 [get_ports ff_clkout0_a]
set_input_delay -clock [get_clocks virtual_clcok] 1.110 [get_ports d]
input_delay的报告如下图,输入延时值在data path中体现
3.6 差分时钟的约束
差分时钟因为有两个输入端口,输入时钟的约束怎么约?实际只需要约束差分时钟输入端口中的p端口,也就是IBUFGDS的I端口
create_clock -name clk -period 10 [get_ports clk_I]