復位的功能是很有必要的,讓一切正在處於工作狀態的器件的狀態恢復到初始態,可以起到重新開始工作的作用。復位有上電復位和按鍵復位兩種常見方式。
先說一下按鍵復位。
一開始,我們在設計按鍵復位的邏輯功能時,第一反應就是利用D觸發器的異步清零端(clr端),這種方式稱為異步復位,代碼和RTL圖如下:
1 always@(posedge clk or negedge rst_n) 2 begin 3 if(rst_n == 1'b0) 4 q <= 1'b0; 5 else 6 q <= 1'b1; 7 end
采取異步復位的方式的優點是不需要額外的資源,直接使用寄存器自帶的異步清零端即可。缺點是存在亞穩態狀態。
1. 當clk上升沿到來時,rst_n正好由高電平變為低電平(處於復位狀態),這時rst_n具有優先級,寄存器直接進行初始態。
2. 當clk上升沿到來時,rst_n正好由低電平變為高電平(處於置位狀態),這時寄存器是認為rst_n為1,鎖存此刻的值a,輸出前一個時鍾周期的b呢,還是認為rst_n為0,該開始初始化了呢(打架了,造成了亞穩態)
那這種方式存在問題,我們再來看看同步復位的方式,代碼和RTL圖如下:
1 always@(posedge clk) 2 begin 3 if(rst_n == 1'b0) 4 q <= 1'b0; 5 else 6 q <= 1'b1; 7 end
1. 當clk上升沿到來時,rst_n正好由高電平變為低電平(處於復位狀態),此刻寄存器僅受clk的控制,認為采樣到的是rst_n的高電平,繼續輸出已存數值,下一個時鍾周期才認為rst_n是低電平,進行初始化。
2. 當clk上升沿到來時,rst_n正好由低電平變為高電平(處於置位狀態),此刻寄存器僅受clk的控制,認為采樣到的是rst_n的低電平,繼續初始化,下一個時鍾周期才認為rst_n是高電平,輸出響應的值。
但是采取同步復位的方式的雖然能減小亞穩態的發生,但是需要額外的資源。
異步復位和同步復位都有優缺點,將兩者相互結合,互補一下,便出現了“異步復位,同步釋放”的方式,很好的解決了兩者的不足。代碼和RTL圖如下:
1 module sys_ctrl( 2 input clk, 3 input rst_n, 4 output reg sys_rst_n 5 ); 6 7 reg rst_1; 8 9 always@(posedge clk or negedge rst_n) 10 begin 11 if(!rst_n == 1'b0) 12 rst_1 <= 1'b0; 13 else 14 rst_1 <= 1'b1; 15 end 16 17 always@(posedge clk or negedge rst_n) 18 begin 19 if(rst_n == 1'b0) 20 sys_rst_n <= 1'b0; 21 else 22 sys_rst_n <= rst_1; 23 end 24 25 26 endmodule
這樣就既利用了異步復位的清零端進行復位,不需要額外開支資源,又利用了同步復位的釋放優點,將異步復位的釋放電平延遲1個時鍾周期,然后再將延遲后的釋放電平信號作為系統復位信號,避免了釋放時亞穩態的發生。
下面說一下上電復位
系統在每次上電復位初始化時,需要消耗很多方面的時間,大體如下:
1. 電源等芯片的轉換時間
2. FPGA的啟動到穩定的時間
3. 外圍電路的啟動時間
所以,為了保證FPGA上電復位后更加的穩定,可以在上電開始后,進行一定的延遲時間來保證FPGA可以達到穩定的狀態。綜合以上代碼如下:
1 module test( 2 input clk, 3 input rst_n, 4 output reg sys_rst_n 5 ); 6 7 parameter RST_TIME = 24'd2_500_000; //50ms 8 9 reg rst_1; 10 reg [23:0] cnt_rst; 11 12 always@(posedge clk or negedge rst_n) 13 begin 14 if(rst_n == 1'b0) 15 cnt_rst <= 24'd0; 16 else 17 if(cnt_rst < RST_TIME) 18 cnt_rst <= cnt_rst +1'b1; 19 else 20 cnt_rst <= cnt_rst; 21 end 22 23 always@(posedge clk or negedge rst_n) 24 begin 25 if(rst_n == 1'b0)begin 26 rst_1 <= 1'b0; 27 sys_rst_n <= 1'b0; 28 end 29 else begin 30 if(cnt_rst == RST_TIME)begin 31 rst_1 <= 1'b1; 32 sys_rst_n <= rst_1; 33 end 34 else begin 35 rst_1 <= 1'b0; 36 sys_rst_n <= 1'b0; 37 end 38 end 39 end 40 41 endmodule