在沒看這篇文章前,回想一下平時我們常用的複位方式:
① 首先,上電後肯定是要複位一下,不然仿真時會出現沒有初值的情況;
② 最好有個複位的按鍵,在調試時按一下複位鍵就可以全局複位了;
③ 也許是同步複位,也許是異步複位,不同的工程師可能有不同的方案。
但如果認真看了Xilinx的White Paper,就會對複位有了新的認識。
我們把White Paper的内容總結為下面4個問題:
① 需不需要複位?
② 同步複位 or 異步複位?
③ 高複位 or 低複位?
④ 全局複位 or 局部複位?怎麼用?
1. 需不需要複位?
看到這個問題,可能很多同學會有點懵,怎麼可能不需要複位?其實Xilinx FPGA在系統上電配置時,會有一個GSR(Global Set/Reset)的信号,這個信号有以下幾個特點:
• 預布線
• 高扇出
• 可靠的
這個信号可初始化所有的cell,包括所有的Flip-Flop和BRAM。
這個信号可初始化所有的cell,包括所有的Flip-Flop和BRAM。

如果我們在程式裡用自己生成的複位信号,也隻能複位Flip-Flop。
這個GSR信号我們可以在程式中通過執行個體化STARTUP直接調用,但Xilinx并不推薦這麼使用。
主要原因是FPGA會把像系統複位這種高扇出的信号放到高速布線資源上,這比使用GSR要快,而且更容易進行時序分析。
雖然有GSR,但這并不是說要避免使用複位信号,以下兩種情況就必須要加複位:
- 帶有回報的子產品,比如IIR這種濾波器和狀态機,當狀态跑飛了,就需要複位一下
- 應用過程中需要複位的寄存器
這個就具體看是什麼應用了,我們公司的很多寄存器都需要在調試過程中需要經常複位,像這種複位就是必須的了。
是以,需不需要複位完全看設計。這裡多提一點,時序收斂也是一樣,主要看設計,而不是限制。
2. 同步複位 or 異步複位?
在HDL中,如果敏感清單中不包含rst,會被綜合成同步複位:
always @ ( posedge clk )
begin
if(rst)
...
end
如果敏感清單中包含rst,則會被綜合成異步複位:
always @ ( posedge clk or posedge rst)
begin
...
end
同步複位的好處,不言而喻,有利于時序分析,降低亞穩态的幾率,避免毛刺。
同步信号的缺點:
- 複位信号有效電平持續時間必須大于時鐘周期,不然時鐘可能采不到複位
- 在沒有時鐘的時候無法複位
也有很多同學會說同步複位會需要額外的資源,但對于Xilinx的FPGA,是沒有這個問題的,具體原因後面講。
對于異步複位,好處就是同步複位的反方面:脈沖寬度沒有限制,沒有時鐘也可以複位。
缺點就是異步電路,容易引起亞穩态,産生毛刺,不利于時序分析,而且不同觸發器的複位時間可能不同。下面這個圖中,在A時刻接收到複位信号拉低的FF可以在下一個時鐘上升沿時就釋放複位狀态,但C時刻接收到複位信号拉低的FF則在下下個時鐘上升沿時才能釋放複位狀态。
按照White Paper上所講,99.99%的機率這種情況都不會發生,但如果你剛好碰到一次這種現象,那你就是那0.01%。
下面我們來舉一個例子來說明同步複位和異步複位,FPGA為V7,代碼如下:
module rst_demo(
input clk,
input rst1,
input rst2,
input in1,
input in2,
output reg out1,
output reg out2);
always @ ( posedge clk )
begin
if(rst1)
out1 <= 1'b0;
else
out1 <= in1;
end
always @ ( posedge clk or posedge rst2 )
begin
if(rst2)
out2 <= 1'b0;
else
out2 <= in2;
end
endmodule
綜合後的schematic如下圖:
可以看出來,同步複位和異步複位都是占用一個Storage Element,我們在之前的一篇文章中講過Storage Element可以配置為Latch,同樣的,也可以配置為FDRE和FDCE,而且在7Series手冊中也并未提到配置成FDRE或FDCE時是否會占用更多資源(比如,7Series的FPGA中,一個Slice中有8個Storage Element,如果其中一個被配置成了Latch,那有4個Storage Element是不能用的),是以在Xilinx的FPGA中,同步複位和異步複位在資源占用上,并沒有差別。
3. 高複位 or 低複位?
很多處理器上的複位都是低複位,這也導緻了很多同學在使用複位信号時也習慣使用低複位了。但從我們上一節所講中可以看出,無論是同步複位還是異步複位,複位信号都是高有效,如果采用低複位,還需要增加一個反相器。
如果接收到其他處理器發過來的低有效複位信号,我們最好在頂層子產品中翻轉複位信号的極性,這樣做可以将反相器放入IO Logic中,不會占用FPGA内部的邏輯資源和布線資源。
這裡多補充一點,如果使用Zynq和Microblaze,則Reset子產品預設是低複位,我們可以手動設定為高複位。
4. 全局複位 or 局部複位?怎麼用?
我們對複位常用的做法是将系統中的每個FF都連接配接到某個複位信号,但這樣就造成了複位信号的高扇出,高扇出就容易導緻時序的違規。而且全局複位占用的資源比我們想象中要高的多:
• 其他網絡的布線空間就相應減少
• 邏輯資源占用
• 占用FF作為專門的複位電路
• 如果該複位信号還受其他信号控制,會導緻FF的輸入前增加門電路
• 增加布局布線時間
• 全局複位不會使用像SRL16E這種高效結構
• 在LUT中SRL16E可當作16個FF
• 這些Virtual FF不支援複位
• 增加設計的size,并降低系統性能
是以,Xilinx推薦盡量使用局部複位的方式,前面我們也講到然同步複位和異步複位都多多少少有些問題,那有沒有一種方式可以結合同步複位和異步複位的優點?當然有,就是異步複位,同步釋放。這種方法可以将兩者結合起來,取長補短。如下圖所示,所謂異步複位,就是輸入的複位信号仍然是異步的,這樣可以保證複位信号能夠起效;而同步釋放是指當複位信号釋放時,輸出的sys_rst并不是立即變化,而且被FF延遲了一個時鐘周期,這樣讓複位和時鐘同步起來。
圖中的Verilog代碼如下:
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
綜合後的schematic如下圖:
異步複位子產品輸出的sys_rst通過n個D觸發器後輸出給n個子產品,當做子產品的複位信号。
總結
在使用複位信号時,考慮這個寄存器需不需要在運作過程中進行複位,如果隻需要上電後複位一次,那隻需在定義時寫上初值即可,無需使用其他複位信号;在Xilinx的FPGA中盡量使用高有效的複位信号,采用異步複位同步釋放的方式,并且要将複位信号局部化,避免使用高扇出的全局複位。