本文整合特权(吴厚航)和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端。读者自行对比哦,哈哈