通常同步電路由兩種復位方式,即同步復位和異步復位。同步復位同步於寄存器的時鍾域,異步復位則是立即自然地作用於寄存器,與其寄存器所在的時鍾域之間沒有確定的時序關系。同步化的異步復位是FPGA電路設計時復位電路的首選。
1 同步復位
1.1 同步復位在外部的情況
代碼:
module sync_reset_ext( input clock, input reset_n, input data_a, input data_b, output out_a, output out_b ); reg reg1,reg2; assign out_a = reg1; assign out_b = reg2; always @(posedge clock) begin if(!reset_n) begin reg1 <= 1'b0; reg2 <= 1'b0; end else begin reg1 <= data_a; reg2 <= data_b; end end endmodule
Vivado工具綜合出來的RTL如下圖所示:
這里用到的是MUX(也可以使用與門來實現),這種方式需要考慮額外的門延遲,復位信號數據經過MUX邏輯電路使得復位信號到達時間(Data Arrival Time)會增加,在這種情況下,建立時間的slack可能為負值。同步復位總是比異步復位來的慢,在FPGA中不是最好的復位方式。
1.2 同步復位在內部的情況
代碼:
module sync_reset( input clock, input reset_n, input data_a, input data_b, output out_a, output out_b ); reg reg1,reg2; reg reg3,reg4; wire rst_n; assign out_a = reg1; assign out_b = reg2; assign rst_n = reg4; always @(posedge clock) begin if(!rst_n) begin reg1 <= 1'b0; reg2 <= 1'b0; end else begin reg1 <= data_a; reg2 <= data_b; end end always @(posedge clock) begin reg3 <= reset_n; reg4 <= reg3; end endmodule
Vivado綜合出來的RTL如下圖:
跟1.1的區別是,復位信號打了兩拍。為什么要這么做?因為大部分時候,輸入到FPGA的復位信號是異步信號,在這種情況下,復位信號必須在內部先同步后再送達寄存器。既然輸入的是異步信號,那么常常有可能該異步信號的脈寬比較小(小於一個時鍾周期)。這種異步信號比時鍾脈寬小的缺點是,異步信號同步時必須保證脈寬至少是一個時鍾周期長,。才能保證異步復位信號在第一個同步寄存器被捕獲;優點是,脈寬段可以增加其抗噪性能,在異步輸入上的一些虛假脈沖,例如毛刺,很難在第一個寄存器被捕獲,也就不會誤觸發同步復位。
2 異步復位
異步復位最大的優點,是沒有像同步復位那樣插入到數據路徑中,因此異步復位對寄存器之間的數據到達時間不會產生負面影響。另一個優點是,異步復位是立即生效的。
代碼:
module aync_reset( input clock, input reset_n, input data_a, output out_a ); reg reg1,reg2,reg3; assign out_a = reg3; always @(posedge clock,negedge reset_n) begin if(!reset_n) begin reg1 <= 1'b0; end else begin reg1 <= data_a; end end always @(posedge clock) begin reg2 <= reg1; reg3 <= reg2; end endmodule
Vivado綜合出來的電路圖:
但是,異步復位在復位被釋放的時候可能會出現問題。異步復位在釋放的時候,可以出現在時鍾的任何一個時候,復位信號在撤除是,復位信號的邊沿可能會落入時鍾的一個亞穩態區域。亞穩態帶來的后果是寄存器的輸出需要花費更多的時間來恢復穩定或者正確的狀態。這個額外的增加的時間可能會導致寄存器下一級的建立時間失敗,從而導致系統錯誤。那么,如果這個異步復位信號,能夠被同步到clock時鍾域下,那么這個問題也就解決了,也就是接下來要說的異步復位同步釋放的設計。
3 異步復位同步化
代碼:
module sync_async_reset( input clock, input reset_n, input data_a, input data_b, output out_a, output out_b ); reg reg1,reg2; reg reg3,reg4; wire rst_n; assign out_a = reg1; assign out_b = reg2; assign rst_n = reg4; always @(posedge clock,negedge reset_n) begin if(!reset_n) begin reg3 <= 1'b0; reg4 <= 1'b0; end else begin reg3 <= 1'b1; reg4 <= reg3; end end always @(posedge clock,negedge rst_n) begin if(!rst_n) begin reg1 <= 1'b0; reg2 <= 1'b0; end else begin reg1 <= data_a; reg2 <= data_b; end end endmodule
第一個always塊用來產生同步復位輸出rst_n,作為第二個always塊的異步復位,第二個將這個已經同步化了的復位信號當做異步復位使用。兩個進程模塊的復位信號都位於各自的敏感列表中。同步器中的寄存器級數(打拍級數)可以視情況而定,但是要確保同步后的異步復位信號至少有一個時鍾周期的長度。
Vivado綜合出來的RTL如下圖所示: