1. 时序约束
1.1 时序约束是什么
在FPGA设计中,时序约束文件(Timing Constraints File)用于指定设计中的时序要求和限制。这些约束文件对于确保电路在特定的时钟频率下正确运行非常重要。
比如,对时钟频率约束最简单的理解就是,设计者需要告诉EDA工具设计中所使用的时钟的频率是多少,然后工具才能按照所要求的时钟频率去优化布局布线,使设计能够在要求的时钟频率下正常工作。
1.2 为什么要时序约束
这里以常见的D触发器为例来讲述
- 当复位信号有效的时候,复位信号为低电平时,输出被强制为低电平
- 当时钟信号CLK发生变化(上升沿或者下降沿)时,D触发器进入到传输状态,在这个状态下,D输入端的值会被传递到输出端Q上
时序就是时钟与谁的关系,这里需要引入建立时间和保持时间这两个概念,D触发器要想完成一次数据的正确采样,就必须满足“建立时间”和“保持时间的要求”。
1.2.1 建立时间
是指在触发器的时钟信号上升沿到来以前,数据稳定不变的时间,如果建立时间不够,数据将不能再这个时钟上升沿被稳定的打入触发器,Tsu就是指这个最小的稳定时间。
1.2.2 保持时间
是指在触发器的时钟信号上升沿到来以后,数据稳定不变的时间,如果保持时间不够,数据同样不能被稳定的打入触发器,Th就是指这个最小的保持时间。
时钟约束在FPGA设计中非常重要,以下是几个原因:
时序要求:FPGA中的电路通常需要在特定的时钟频率下工作。时钟约束定义了设计所需的时钟频率,确保电路能够满足时序要求。通过指定时钟频率,设计人员可以确保电路在给定频率下正常工作,并防止时序违规问题。
时序分析:时钟约束用于时序分析,这是验证电路的时序可靠性的重要步骤。通过在设计中指定时钟约束,FPGA工具可以进行时序分析并确定设计中的关键路径、最小和最大延迟等。这些分析结果帮助设计人员了解电路的时序行为,并确保在不同工作条件下的正确性。
时钟域交叉:在FPGA设计中,常常存在多个时钟域的情况,其中每个时钟域都由不同的时钟信号驱动。时钟约束允许设计人员指定时钟域之间的关系和时序要求,确保在不同时钟域之间进行数据传输时的正确性和一致性。
约束驱动综合和布局布线:时钟约束对综合和布局布线过程起着重要的指导作用。约束驱动综合和布局布线意味着在这些步骤中使用时钟约束信息来优化电路性能和时序可靠性。工具根据约束进行优化,以满足设计人员定义的时序和时钟域要求。
总之,时钟约束在FPGA设计中起到了关键的作用,确保设计满足时序要求、提供时序分析、处理多时钟域交叉以及指导综合和布局布线过程。正确编写和应用时钟约束能够提高设计的性能、可靠性和可维护性,避免时序违规和其他时序相关的问题。
1.3 如何创建时序约束
在流水灯项目中,可以看到,即使没加时序约束,也能成功实现效果,但是在Compilation Report中可以看到,有很多地方爆红了
这是因为软件开发工具不知道实际的外部时钟频率。我们可以通过添加时钟约束来告诉它。
1.3.1 时序分析向导方式创建
点击菜单栏Assignment
,选择时序分析向导
根据实际设置
接下来到了设置输入的时钟和数据的延迟关系
由于项目简单,一般用不到,同理,设置输入到输出的延迟也可以选择跳过
将设置的时钟周期约束文件添加到我们的工程,点击next
即可
可以看到,file下生成了sdc文件
当然熟悉语法之后,可以直接写sdc文件
# Clock constraints
create_clock -name "sys_clk" -period 20.000ns [get_ports {sys_clk}] -waveform {0.000 10.000}
# Automatically constrain PLL and other generated clocks
derive_pll_clocks -create_base_clocks
# Automatically calculate clock uncertainty to jitter and other effects.
derive_clock_uncertainty
参考如下:
配置好了之后,重新对工程进行编译一下:
可以看到编译报告中已经没有爆红了
1.3.2 TimeQuest Timing Analyer的方式创建
点击菜单栏TimeQuest Timing Analyer
选项
点击netlist
,选择创建一个时序网表create Timing Netlist
选择第二项,点击下一步,点击constraint
,选择create clock
按以下步骤进行配置
选择更新时序网表
然后需要写入到SDC中去,
接下来需要手动将SDC文件添加到工程
可以看到添加成功
参考代码是
module flow_led (
input sys_clk, //系统时钟
input sys_rst_n, //系统复位,低电平有效
output reg[3:0] led // 4个led
);
// reg define
reg[23:0] counter;
// 计数器对系统时钟计数,计时为0.2秒,50MHZ的晶振周期是20ns,等于10……(-9)次方秒
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n) // 如果是低电平,表示系统复位信号处于活动状态(reset active),则执行下面的语句。
counter <= 24'd0;
else if(counter < 24'd1000_0000)
counter <= counter + 1'b1;
else
counter <= 24'd0;
end
// 通过移位寄存器控制IO的高低电平,从而改变led的显示状态
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
led <= 4'b0001;
else if (counter == 24'd1000_0000)
led[3:0] <= {led[2:0],led[3]}; // 向右移位
else
led <= led;
end
endmodule
参考资料
【正点原子手把手教你学FPGA-基于开拓者V2【第一期】】 https://www.bilibili.com/video/BV1QF41137Kf/?p=10&share_source=copy_web&vd_source=0be51b3dad5686963c05b07f55815942