目录
- 1. 复位
-
- 2.1. 异步复位 同步释放
- 2.2. Xilinx FPGA复位设计
-
- reg信号初始值
- 基于PLL锁定(locked)复位设计
- 2. 时钟
1. 复位
-
同步复位:优点是时序简单,不受毛刺影响。缺点是大部分逻辑器件库内的DFF都只有异步复位端口,同步复位需要额外加入组合逻辑,整个芯片设计会消耗大量组合逻辑资源。
-
异步复位:优点是实现简单,无需额外组合逻辑,复位启动不受时钟影响。缺点是复位释放的时候,时钟若采样复位信号跳变时刻,寄存器信号容易出现亚稳态。
例如
always@(posedge clk or negedge rst_n) begin
if(!rst_n)
b <= 1'b0;
else
b <= a;
end
因此为了保证全局复位不消耗太多组合逻辑,也能保证避免异步复位释放导致的亚稳态,如何作?
2.1. 异步复位 同步释放
- 异步复位,同步释放:复位信号到来的时候不受时钟信号影响,复位信号释放的时候受到时钟信号的同步。
例如下面代码中rst_sync_n就实现了异步置0、同步置1
// rst_async_n为异步复位信号
always@(posedge clk or negedge rst_async_n) begin
if(!rst_async_n) begin
rst_s1 <= 1'b0;
rst_sync_n <= 1'b0;
end
else begin
rst_s1 <= 1'b1;
rst_sync_n <= rst_s1;
end
end
//由于rst_sync_n复位启动还是异步的,所以必须加入敏感列表中
always@(posedge clk or negedge rst_sync_n) begin
if (!rst_sync_n)
dout <= 1'b0;
else
dout <= din;
end
综合电路如下:
出现亚稳态的波形图如下
如上图所示:
- T1时刻:rst_async_n异步复位启动,rst_s1和rst_sync_n全部拉低,与clk无关
注意T1时刻是异步的,不涉及clk采样,因此rst_s1和rst_sync_n不会出亚稳态
- T2时刻:rst_async_n异步复位释放,此时clk采样rst_async_n边沿,采样值不定,因此rst_s1出现0、1之间的亚稳态。rst_sync_n仍然保持0
- T3时刻:rst_s1可能恢复也可能还是亚稳态,但clk采样到rst_async_n为1,因此rst_s1恢复为1。rst_sync_n则相当于对T2时刻的rst_async_n打两拍处理,因此会稳定至0或1两种状态,并处于clk时钟域下!
发现没有T2时刻本质上是对rst_async_n作电平同步!!!那么rst_sync_n一定会稳定在clk时钟域下的高电平。
参考异步时钟亚稳态 的解决方案——单bit信号
即T2时刻的逻辑可以看成:
always@(posedge clk) begin
rst_s1 <= rst_async_n;
rst_sync_n <= rst_s1;
end
2.2. Xilinx FPGA复位设计
第三章第1讲 Verilog语法reg变量复位使用以及异步复位同步释放设计(FPGA/IC设计公开课)- bilibili
Xilinx FPGA异步复位同步释放——同步后的复位当作同步复位还是异步复位?【FPGA探索者】
聊一聊xilinx 7系列推荐使用的复位方式
Xilinx复位准则:
- 尽量少用复位。数据路径的复位通常是不需要的。因为,老的数据总会被新数据“冲走”
- FPGA上电后所有触发器和RAM均有初始值
- 确保高电平复位
- 尽量采用同步复位。异步复位会增加时序复杂度
- 如果必须异步复位,确保异步复位、同步释放
reg信号初始值
Vivado寄存器初始值问题
不得不读的 FPGA 设计白皮书——Xilinx FPGA 复位策略白皮书翻译(WP272)【FPGA探索者】
Xilinx FPGA上电后,所有触发器和RAM都具备初始值,比任何的逻辑复位都要全面,不需要全局复位。
reg信号上电初始值可配置,可通过reg [2:0] a = 3;
配置上电初值。
默认规则如下:
- 不赋初始值、不复位,上电后寄存器值为0
- 赋初始值、不复位,上电后寄存器值为初始值
- 不赋初始值、复位,上电后寄存器值为复位值
- 赋初始值、复位,上电后寄存器值为初始值,复位后为复位值
综合后,可在synthesis/schematic网表中点击触发器,Cell Properties/Properties/INIT设置初始值
基于PLL锁定(locked)复位设计
使用pll的locked信号产生复位逻辑,locked初始为低,时钟稳定后locked拉高。locked可能出现不稳定毛刺,需要做滤波处理。locked_temp为滤波后信号,滤波后也存在异步拉低的可能。
-
注意各rst信号上电初始值为1
-
locked是从PLL输出的,故locked到cnt异步复位路径不会被分析
-
locked_temp/C到各rst信号/PRE的异步复位路径需要分析,必须满足Recover time 和Remove time。可以在XDC中忽视该路径
set_false_path -from [get_pins {U_clk_rst_gen/locked_temp_reg/C}] -to [get_pins {U_clk_rst_gen/rst*_reg/PRE}]
- rst_a/PRE到a/R的同步复位路径vivado没有进行STA。如果rst_a/PRE端输入异步复位导致
a/R端立刻拉高,a/CK采样时不满足建立时间,会造成亚稳态,影响复位启动
`timescale 1ns / 1ps
module clk_rst_gen(
input clk_in, //晶振
input clk_in2, //外部输入时钟
output clk_a,
output clk_b,
output reg rst_in2,
output reg rst_a,
output reg rst_b,
);
//--------------------------------------------------------------------------------------------------------
// pll
//--------------------------------------------------------------------------------------------------------
wire locked;
pll pll(
.clk_in1 ( clk_in ),
.clk_out1 ( clk_a ),
.clk_out2 ( clk_b ),
.locked ( locked )
);
//--------------------------------------------------------------------------------------------------------
// locked_temp attends to eliminate jitter of signal locked
//--------------------------------------------------------------------------------------------------------
reg [15:0] cnt;
always@(posedge clk_in or negedge locked) begin
if(!locked)
cnt <= 0;
else if(cnt[15])
cnt <= cnt;
else
cnt <= cnt + 1;
end
wire locked_temp = cnt[15];
//--------------------------------------------------------------------------------------------------------
// async reset and sync release
//--------------------------------------------------------------------------------------------------------
(*ASYNC_REG = "TRUE"*)reg rst_in2_d1;
(*ASYNC_REG = "TRUE"*)reg rst_in2_d2;
always@(posedge clk_in2 or negedge locked_temp) begin
if(!locked_temp) begin
rst_in2_d1 <= 1'b1;
rst_in2_d2 <= 1'b1;
rst_in2 <= 1'b1;
end
else begin
rst_in2_d1 <= 1'b0;
rst_in2_d2 <= rst_in2_d1;
rst_in2 <= rst_in2_d2;
end
end
(*ASYNC_REG = "TRUE"*)reg rst_a_d1;
(*ASYNC_REG = "TRUE"*)reg rst_a_d2;
always@(posedge clk_a or negedge locked_temp) begin
if(!locked_temp) begin
rst_a_d1 <= 1'b1;
rst_a_d2 <= 1'b1;
rst_a <= 1'b1;
end
else begin
rst_a_d1 <= 1'b0;
rst_a_d2 <= rst_a_d1;
rst_a <= rst_a_d2;
end
end
(*ASYNC_REG = "TRUE"*)reg rst_b_d1;
(*ASYNC_REG = "TRUE"*)reg rst_b_d2;
always@(posedge clk_b or negedge locked_temp) begin
if(!locked_temp) begin
rst_b_d1 <= 1'b1;
rst_b_d2 <= 1'b1;
rst_b <= 1'b1;
end
else begin
rst_b_d1 <= 1'b0;
rst_b_d2 <= rst_b_d1;
rst_b <= rst_b_d2;
end
end
endmodule
always@(posedge clk_a) begin
if(rst_a)
a <= 0;
else
a <= a + 1;
end