本文整合特權(吳厚航)和coyoo(王敏志)兩位大神的博文。我也很推崇這兩位大神的書籍,特權的書籍要偏基礎一下,大家不要一聽我這么說就想買coyoo的。我還是那一句話,做技術就要step by step。閑言少敘,直入正題。
一,異步復位
先看這個電路,就是異步復位的例子。reset使用了reg的復位端
用代碼實現的話是這個樣子
1 module reset_test ( 2 clk , 3 rst_n , 4 i_data, 5 o_data 6 ); 7 8 input clk ; 9 input rst_n ; 10 input i_data ; 11 output reg o_data ; 12 13 always @ (posedge clk or negedge rst_n) 14 if(!rst_n) o_data <= 1'd0 ; 15 else o_data <= i_data ; 16 17 endmodule
二,同步復位
首先也是先看電路,這是QuartusPrime15.1綜合同步復位程序后的 RTL Viewer
代碼如下
1 module reset_test ( 2 clk , 3 rst_n , 4 i_data, 5 o_data 6 ); 7 8 input clk ; 9 input rst_n ; 10 input i_data ; 11 output reg o_data ; 12 13 always @ (posedge clk ) 14 if(!rst_n) o_data <= 1'd0 ; 15 else o_data <= i_data ; 16 17 endmodule
細心的同學有沒有發現,很多的博文里面貼出的電路圖,輸入端那里不是一個2選1多路選擇器,而是一個與門。所以我才說明我的綜合器是QuartusPrime15.1。當然這個不是重點,重點是同步復位比異步復位多用了器件。數據也是多穿過一個器件。
對比:
異步復位的優點:1,節省了器件,這個在ASIC中顯的尤為重要。2,減小了數據路徑的傳播延時。提高了系統響應頻率。3,即刻生效,不依賴於時鍾是否到來。
異步復位的缺點:由於reset信號時序是不定的,reset釋放的時候會讓異步復位系統出現亞穩態。
同步復位的優點:1,降低了亞穩態的出現。注意是降低了,而不是完全消除。如果reset毛刺或者是觸發時間點不在clock上升沿的setup和hold時間內那就萬事大吉,可是如果不是這個時間點,依然會有亞穩態。2,有利於時序分析。由於同步的reset信號必須由clock捕獲到才有效,所以容易被時序分析工具分析到它的余量slack
同步復位的缺點:1,多使用了器件。2,增加了數據路勁傳輸時間
節省器件和增大F是asic的必爭之地,所以目前大神們也喜歡在它身上進行改進,叫 異步復位的同步釋放
3,異步復位的同步釋放第一版
此種方式是事先將reset信號打一拍,去除了reset的毛刺同時,reset釋放的時候也能實現與clock同步。表面上看可以說是一個完美的方案。
然而問題出來了,一夢君曾經在面試一個崗位的時候被問過這個異步復位同步釋放的問題,當我畫出電路圖的時候,面試官當即問我一句:如果clock掛了,你的系統豈不是還不能復位了?我頓時啞口無言。隨后只好說,你說的沒錯,這個確實沒有考慮到。當然我說這個絕對不是想去責怪誰,如果沒有這些大神們在博客上奉獻着他們的技術資料,我們不可能了解到這么多,只怪自己沒有去深究。同時也希望讀者們能深究我的博文缺陷。
這里非常感謝白菜小弟,在 FPGA知識大梳理(三)verilogHDL語法入門(2)知識匯總這篇博文中指出 “assign中使用的 blocking ”這一句話的原本意思是想告訴大家assign后面是使用 “=”,而不能使用“<=”。這么理解是沒有錯,但是表述不對,根據VerilogHDL_2001_standard,assign是Continuous assignments (連續性賦值語句)不存在阻塞非阻塞之分,阻塞非阻塞只針對於procedural assignment(過程性賦值語句) ,所以assign后面當然是“=”。
好了,說了這么多,該回到這個同步復位的異步釋放問題上來了
4,改進型的異步復位同步釋放
程序是
1 //`default_nettype none 2 3 module reset_test ( 4 clock , 5 reset_n , 6 data_a, 7 data_b, 8 out_a, 9 out_b 10 ); 11 12 input clock,reset_n ; 13 input data_a,data_b ; 14 output out_a,out_b ; 15 16 reg reg1 ,reg2 ; 17 reg reg3 ,reg4 ; 18 wire rst_n ; 19 20 assign out_a = reg1 , 21 out_b = reg2 , 22 rst_n = reg4 ; 23 24 always @ (posedge clock or negedge reset_n) 25 if(!reset_n) begin 26 reg3 <= 1'd0 ; 27 reg4 <= 1'd0 ; 28 end 29 else begin 30 reg3 <= 1'd1 ; 31 reg4 <= reg3 ; 32 end 33 34 always @ (posedge clock or negedge rst_n) 35 if(!rst_n) begin 36 reg1 <= 1'b0 ; 37 reg2 <= 1'd0 ; 38 end 39 else begin 40 reg1 <= data_a ; 41 reg2 <= data_b ; 42 end 43 44 endmodule
reg3,reg4 . 異步復位產生rst_n ,由於異步復位的及時性,所有的reg都會復位。reset_n釋放后,只有在clock到來之后,VCC傳輸到rst_n系統才會運轉。所以實現了同步釋放。
這個樣子就萬事大吉了嗎?還缺一點點。在reset_n前面需要加一個濾波去抖的模塊才算完美。如果你覺得有更完美的方案,歡迎提出來!
5,異步復位同步釋放PLL版
在絕大多數的 工程中需要使用到PLL,那么有PLL的工程復位系統又有點不一樣了哦。
也就是在pll沒有准備好的時候,系統還是在復位的狀態等待
代碼實現是
1 module reset_test ( 2 clock , 3 reset_n , 4 data_a, 5 data_b, 6 out_a, 7 out_b 8 ); 9 10 input clock,reset_n ; 11 input data_a,data_b ; 12 output out_a,out_b ; 13 14 reg reg1 ,reg2 ; 15 reg reg3 ,reg4 ; 16 wire rst_n ; 17 wire pll_clk ,pll_lock; 18 19 assign out_a = reg1 , 20 out_b = reg2 , 21 rst_n = reg4 ; 22 23 always @ (posedge clock or negedge reset_n) 24 if(!reset_n) begin 25 reg3 <= 1'd0 ; 26 reg4 <= 1'd0 ; 27 end 28 else if(pll_lock) begin //pll clock is ready 29 reg3 <= 1'd1 ; 30 reg4 <= reg3 ; 31 end 32 else begin 33 reg3 <= 1'd0 ; 34 reg4 <= 1'd0 ; 35 end 36 37 //data flow ------------------------------- 38 always @ (posedge clock or negedge rst_n) 39 if(!rst_n) begin 40 reg1 <= 1'b0 ; 41 reg2 <= 1'd0 ; 42 end 43 else begin 44 reg1 <= data_a ; 45 reg2 <= data_b ; 46 end 47 48 49 altera_pll_0 U_0 ( 50 .areset (!reset_n) , 51 .inclk0 (clock), 52 .c0 (pll_clk), 53 .locked (pll_lock) 54 ); 55 56 57 endmodule
這復位算是告一段落了。如果你有更好的設計,請賜教。
最后留下一個小問題,也是一夢君本人之前一直用的復位方式。如下圖。 或者是inst(reg3)和inst1(reg4)都沒有,直接將pll_locked直接連接到后續data flow部分的reset端。讀者自行對比哦,哈哈