• 【深入浅出玩转FPGA学习5-----复位设计】


    异步复位与同步复位

    FPGA设计中常见得复位方式即异步复位与同步复位。所谓异步,是指复位信号与系统时钟信号的触发可以在任何时刻,二者相互独立。

    异步复位实例

    下面给出异步复位的一段代码:

    always @ (posedge clk or negedge rst_n)
    		if(!rst_n) b <= 1'b0;
    		else b <= a;
    
    • 1
    • 2
    • 3

    下图是上面代码综合后的RTL视图,可以看到FPGA的寄存器都有一个异步的清零端(CLR),在异步复位的设计中,这个端口一般接低电平有效的复位信号rst_n,即使设计中是高电平复位,实际综合后也会把异步复位信号反向后接到这个CLR端。
    在这里插入图片描述

    同步复位实例

    下面给出同步复位的一段代码:

    always @ (posedge clk)
    			if(!rst_n) b <= 1'b0;
    			else b <=a;
    
    • 1
    • 2
    • 3

    代码综合后的RTL视图,和异步复位相比,同步复位没有用到寄存器的CLR端口,综合出来的实际电路只是把复位信号rst_n作为输入逻辑的使能信号,那么,这样的同步复位势必会额外增加FPGA内部的资源消耗。
    在这里插入图片描述
    那么,异步复位与同步复位到底孰优孰劣呢?只能说,各有优缺点。FPGA的寄存器有支持异步复位专用的端口,采用异步复位无需增加器件的额外资源,但是异步复位也存在着隐患。异步时钟域的亚稳态问题同样存在异步复位信号和系统时钟信号之间。同步复位在时钟信号clk的上升沿触发时进行系统是否复位的判断,这降低了亚稳态出现的概率(只是降低,不可能完全避免);它的缺点在于需要消耗更多的器件资源,无法充分利用专用的 复位端口CLR。
    再通过下面一个两级寄存器异步复位的例子来说明异步复位存在的隐患。

    always @ (posedge clk or negedge rst_n)
    			if(!rst_n) b <= 1'b0;
    			else b <=a;
    always @ (posedge clk or negedge rst_n)
    			if (!rst_n) c <= 1'b0;
    			else c <= b;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    代码综合后的RTL视图如图所示:
    在这里插入图片描述
    正常情况下,在clk的上升沿将c更新为b,b更新为a。一旦进入复位,b、c都将清零;但是并不能确定复位信号rst_n会在什么时候结束。如果结束于b_reg0和c_reg0的{latch edge setup time,latch edge + hold time} 时间之外,那么一切都会正常。但如果恰恰相反,会出现什么情况呢?复位信号rst_n的撤销(由低电平变为高电平)出现在clk锁存数据的建立时间或者保持时间内,此时clk检测到rst_n的状态就会是一个亚稳态(不确定是0还是1)。从代码里可以看到,如果此时b_reg0认为rst_n为0,那么依然保持复位清零;而如果认为rst_n为1,那么就跳出复位,执行相应的操作。
    由于此时rst_n的不确定性,可能会出现4种情况,即b_reg0和c_reg0都复位或者都跳出复位,再或者一个复位一个跳出复位,那么后者就会造成系统功能做不同步的问题。

    复位与亚稳态

    亚稳态对于一个寄存器的影响相对小一些,但是对于诸如总线式的寄存器受到的亚稳态的影响那问题就大了,搞不好就是致命性的打击。

    异步复位、同步释放

    异步复位会影响寄存器recovery时间,引起设计的稳定性问题,尤其对于状态机的无意识的复位,将导致进入不确定的状态。同步复位也存在类似的问题,而且对于不带同步复位专用端口的器件会增加额外的逻辑资源。
    下面介绍一种更为可靠的异步复位、同步释放的双缓冲电路。该电路有两个同一时钟沿触发的层叠寄存器组成,该时钟必须和目标寄存器是一个时钟域。Verilog代码如下:

    input clk;   //系统时钟信号
    input rst_n;  //输入复位信号,低有效
    output rst_nr2;  //异步复位、同步释放输出
    reg rst_nr1,rst_nr2;
    //两级层叠复位产生,低电平复位
    always @ (posedge clk or negedge rst_n)
    		if(!rst_n) rst_nr2 <= 1'b0;
    		else rst_nr2 <= rst_nr1;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    由此段代码实现的电路如图所示:
    在这里插入图片描述
    在这里插入图片描述
    如此以来,既解决了同步复位的资源消耗问题,又解决了异步复位的亚稳态问题,其根本思想,也是将异步信号同步化。

    PLL配置后得复位设计

    很多FPGA设计中都会涉及多个时钟,使用器件内部的PLL或者DLL会使得多个时钟的管理变得更加容易。但是当多个时钟都是用PLL/DLL产生时,它们的系统复位电路如何设计才更稳定呢?
    如图所示,先用FPGA的外部输入时钟clk将FPGA的输入复位信号rst_n做异步复位、同步释放处理,然后这个复位信号输入PLL,同时clk也输入PLL。设计初衷是在PLL输出时钟有效前,系统的其他部分都保持复位状态。PLL的输出locked信号在PLL有效输出之前一直是低电平,PLL输出稳定有效之后才会拉高该信号,所以这里就把FPGA外部输入复位信号rst_n和这个locked信号相与作为整个系统的复位信号,当然了,这个复位信号也需要让合适的PLL输出时钟异步复位、同步释放处理一下。也就是说,为了达到可靠稳定的复位信号,该设计中对复位信号进行了两次处理,分别是在PLL输出前和PLL输出后。
    在这里插入图片描述
    该设计实现的工程源代码如下:

    module sys_ctrl(
    						clk,rst_n,sys_rst_n,clk_25m,clk_100m
    						);
    input clk;      //FPGA输入时钟信号25Mhz
    input rst_n;   //系统复位信号
    output sys_rst_n;   //系统复位信号,低有效
    output clk_25m;    //PLL输出25MHZ时钟频率
    output clk_100m;   //PLL输出100MHZ时钟频率
    wire locked;    //PLL输出有效标志位,高表示PLL输出有效
    /PLL复位信号产生,高有效
    //异步复位,同步释放
    wire pll_rst;     //PLL复位信号,高有效
    reg rst_r1,rst_r2;
    always @ (posedge clk or negedge rst_n)
    				if(!rst_n) rst_r1 <= 1'b1;
    				else rst_r1 <= 1'b0;
    always @ (posedge clk or negedge rst_n)
     				if(!rst_n) rst_r2 <= 1'b1;
     				else rst_r2 <= rst_r1;
     assign pll_rst = rst_r2;
     //系统复位信号产生,低有效
     //异步复位,同步释放
     wire sys_rst_n;   //系统复位信号,低有效
     wire sysrst_nr0;
     reg sysrst_nr1,sysrst_nr2;
     assign sysrst_nr0 = rst_n & locked;  //系统复位知道PLL有效输出
     always @ (posedge clk_100m or negedge sysrst_nr0)
     			if(!sysrst_nr0) sysrst_nr1 <= 1'b0;
     			else sysrst_nr1 <= 1'b1;
     always @ (posedge clk_100m or negedge sysrst_nr0)
     			if(!sysrst_nr0) sysrst_nr2 <= 1'b0;
     			else sysrst_nr2 <= sysrst_nr1;
     assign sys_rst_n = sysrst_nr2;
     //例化PLL产生模块
     PLL_ctrl      uut_PLL _ctrl(
     									.areset(pll_rst),    //PLL复位信号,高电平复位
     									.inclk0(clk),    //PLL输入时钟,25MHz
     									.c0(clk_25m),  //PLL输出25MHz时钟频率
     									.c1(clk_100m),   //PLL 输出100MHZ 时钟频率
     									.locked(locked)   //PLL输出有效标志位,高电平表示PLL输出有效
     									);
     endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
  • 相关阅读:
    centos7离线安装neo4j
    R语言内连接两个dataframe数据(Inner join)
    Python基础 – 使用别人代码的模块机制
    SSM+图书馆电子文件资源管理 毕业设计-附源码191614
    IntelliJ IDEA中配置Tomcat(超详细)
    工商银行新一代银行移动开发平台建设研究
    搭建PyTorch神经网络进行气温预测
    React组件生命周期
    互联网热门词汇-媒体经常说的热门词
    如何写好科研论文笔记 李玉军 清华大学 学堂在线课程
  • 原文地址:https://blog.csdn.net/qq_38617667/article/details/125557561