在没看这篇文章前,回想一下平时我们常用的复位方式:
但如果认真看了Xilinx的White Paper,就会对复位有了新的认识。
我们把White Paper的内容总结为下面4个问题:
1. 需不需要复位?
看到这个问题,可能很多同学会有点懵,怎么可能不需要复位?其实Xilinx FPGA在系统上电配置时,会有一个GSR(Global Set/Reset)的信号,这个信号有以下几个特点:
· 预布线
· 高扇出
· 可靠的
如果我们在程序里用自己生成的复位信号,也只能复位Flip-Flop。
主要原因是FPGA会把像系统复位这种高扇出的信号放到高速布线资源上,这比使用GSR要快,而且更容易进行时序分析。
虽然有GSR,但这并不是说要避免使用复位信号,以下两种情况就必须要加复位:
带有反馈的模块,比如IIR这种滤波器和状态机,当状态跑飞了,就需要复位一下
应用过程中需要复位的寄存器
always @ ( posedge clk or posedge rst)
begin
...
end
同步信号的缺点:
复位信号有效电平持续时间必须大于时钟周期,不然时钟可能采不到复位
在没有时钟的时候无法复位
按照White Paper上所讲,99.99%的概率这种情况都不会发生,但如果你刚好碰到一次这种现象,那你就是那0.01%。
下面我们来举一个例子来说明同步复位和异步复位,FPGA为V7,代码如下:
很多处理器上的复位都是低复位,这也导致了很多同学在使用复位信号时也习惯使用低复位了。但从我们上一节所讲中可以看出,无论是同步复位还是异步复位,复位信号都是高有效,如果采用低复位,还需要增加一个反相器。
如果接收到其他处理器发过来的低有效复位信号,我们最好在顶层模块中翻转复位信号的极性,这样做可以将反相器放入IO Logic中,不会占用FPGA内部的逻辑资源和布线资源。
这里多补充一点,如果使用Zynq和Microblaze,则Reset模块默认是低复位,我们可以手动设置为高复位。
4. 全局复位 or 局部复位?怎么用?
我们对复位常用的做法是将系统中的每个FF都连接到某个复位信号,但这样就造成了复位信号的高扇出,高扇出就容易导致时序的违规。而且全局复位占用的资源比我们想象中要高的多:
· 布线资源占用
· 其他网络的布线空间就相应减少
· 可能会降低系统性能
· 增加布线时间
· 逻辑资源占用
· 占用FF作为专门的复位电路
· 如果该复位信号还受其他信号控制,会导致FF的输入前增加门电路
· 会增加整个设计的size
· 增加的逻辑资源会影响系统性能
· 增加布局布线时间
· 全局复位不会使用像SRL16E这种高效结构
· 在LUT中SRL16E可当作16个FF
· 这些Virtual FF不支持复位
· 增加设计的size,并降低系统性能
· 增加布局布线时间
因此,Xilinx推荐尽量使用局部复位的方式,前面我们也讲到然同步复位和异步复位都多多少少有些问题,那有没有一种方式可以结合同步复位和异步复位的优点?当然有,就是异步复位,同步释放。这种方法可以将两者结合起来,取长补短。如下图所示,所谓异步复位,就是输入的复位信号仍然是异步的,这样可以保证复位信号能够起效;而同步释放是指当复位信号释放时,输出的sys_rst并不是立即变化,而且被FF延迟了一个时钟周期,这样让复位和时钟同步起来。
module rst_demo(
input clk,
input rst_async,
(* keep = 'true' *)
output reg rst_module1 = 0,
(* keep = 'true' *)
output reg rst_module2 = 0
);
reg sys_rst;
reg rst_r;
always @(posedge clk or posedge rst_async) begin
if (rst_async) begin
rst_r <= 1'b1;
end
else begin
rst_r <= 1'b0;
end
end
always @(posedge clk or posedge rst_async) begin
if (rst_async) begin
sys_rst <= 1'b1;
end
else begin
sys_rst <= rst_r;
end
end
always @ ( posedge clk ) begin
rst_module1 <= sys_rst;
rst_module2 <= sys_rst;
end
endmodule
异步复位模块输出的sys_rst通过n个D触发器后输出给n个模块,当做模块的复位信号。
来源:科学计算technomania,作者:猫叔
联系客服