异步复位同步释放(Synchronized Asynchronous Reset)

1 同步复位

        示例:

always@(posedge clk)    //没有“or negedge reset”
    if(!reset) begin
        out2 <= 0  ;
    else
        out2 <= in2;

        1.1 优点

                ①一般能够确保电路是百分之百同步的。

                ②确保复位只发生在有效时钟沿,可以作为过滤掉毛刺的手段。

        1.2 缺点

                ①复位信号属于数据路径的一部分

                ②复位信号的有效时长必须大于时钟周期,且在时钟的有效边沿才能真正被系统识别并完成复位。同时还要考虑如:时钟偏移、组合逻辑路径延时、复位延时等因素。 

                ③由于大多数的厂商目标库内的触发器都只有异步复位端口,采用同步复位的话,就会耗费较多的逻辑资源。

2 异步复位

        示例:

always@(posedge clk or negedge reset)  //异步复位
    if(!reset) begin
	    out1 <= 0   ;
    else
        out1 <= in1 ;

        2.1 recovery time和removal time

                在同步电路中,输入数据需要与时钟满足setup time和hold time才能进行数据的正常传输,防止亚稳态。同样的道理,对于一个异步复位寄存器来说,同样异步复位信号同样需要和时钟满足recovery time和removal time 才能有效进行复位操作和复位释放操作,防止输出亚稳态。

                recovery time(恢复时间):

                  撤销复位时,恢复到非复位状态的电平必须在时钟有效沿来临之前的一段时间到来,才能保证时钟能有效恢复到非复位状态,此段时间为recovery time,类似于同步时钟的setup time。

                removal time (去除时间):

                   复位时,在时钟有效沿来临之后复位信号还需要保持复位状态的一段时间为去除时间removal time(去除时间)。类似同步时钟hold time。

                总结:复位信号的操作(无论是复位还是释放)如果在时钟的recovery time和removal time之间的时间窗口内,都会产生亚稳态。

                异步复位信号一般会持续相对较长的时间,保证寄存器能复位完成。但是由于复位信号是异步的,我们不知道它会在什么时刻被释放。如果异步复位信号撤销时,不满足recovery time和removal time时,可能会造成亚稳态。

                很显然,并不是复位信号撤销时才可能出现亚稳态,复位信号一开始出现时,同样可能会存在亚稳态,只不过异步复位信号持续时间长,即使第一个周期出现了亚稳态(即第一个周期复位未成功),下一个时钟周期也不会再出现亚稳态了。

                如果复位信号的变化只持续刚刚一个时钟周期,那么复位信号开始和撤销时都可能会出现亚稳态。

        2.2 优点

                ①复位信号不是数据路径的一部分,不是触发器D输入的一部分

                ②异步复位信号识别方便,而且可以很方便的使用全局复位。

                ③由于大多数的厂商目标库内的触发器都有异步复位端口,可以节约逻辑资源。

        2.3 缺点

                ①复位信号容易受到毛刺的影响。

                ②复位结束时刻恰在亚稳态窗口内时,无法决定现在的复位状态是1还是0,会导致亚稳态。 

3 异步复位同步释放

        所谓异步复位同步释放(Synchronized Asynchronous Reset),就是在复位信号到来的时候不受时钟信号的同步,而是在复位信号释放的时候受到时钟信号的同步。

        电路目的:防止复位信号撤除时产生亚稳态事件。

        异步复位:显而易见,reset_n异步复位后,rst_n将拉低,即实现异步复位。

        同步释放:这个是关键,看如何实现同步释放,即当复位信号reset_n撤除时,由于双缓冲电路(双寄存器)的作用,rst_n复位信号不会随着reset_n的撤除而撤除。

        异步复位同步释放的原理图和代码如下:

//Synchronized Asynchronous Reset
//异步复位、同步释放:只适用于没有PLL的系统复位信号的设置
module sync_async_reset(clock,reset_n,rst_n);

    input clock, reset_n;
    output rst_n;

    reg rst_nr1, rst_nr2;

    always @(posedge clock or negedge reset_n) begin
        if(!reset_n) begin
			rst_nr1 <= 1'b0;
            rst_nr2 <= 1'b0;		//异步复位
        end
        else begin
			rst_nr1 <= 1'b1;
			rst_nr2 <= rst_nr1;		//同步释放
		end
    end
	
	assign rst_n = rst_nr2;			//新的系统复位信号rst_n
    //信号rst_n作为新的系统复位信号,后续可以用来直接“异步复位”
	
endmodule							// sync_async_reset

在这里插入图片描述

                当异步复位信号撤销时,用来同步的第二个寄存器输入的数据仍然是0,因此第二个寄存器是不会出现亚稳态的。第一个寄存器虽然可能出现亚稳态,即使其出现了亚稳态,这个亚稳态还需要通过第二个寄存器,这时第二个寄存器就起到了打拍的作用。也就是说,第二级的亚稳态只可能是上一级寄存器传播过来的,但是这个亚稳态经过第二级寄存器后,其大概率已经稳定下来了,就算稳定下来不为1,也就相当与复位信号多持续了一个周期而已。因此我们可以看出,使用异步复位同步释放时,异步复位撤销后是需要额外等待一个时钟周期的,否则会激励可能会被复位信号覆盖掉。 

  • 注意

        既解决了同步复位的资源消耗问题,又解决了异步复位的亚稳态问题,其根本思想是异步信号同步化

        新的系统复位信号可以直接用来“异步复位”;

        只适用于不带PLL的系统。 

4 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输出后。

源代码和RTL图如下所示:

module sys_ctrl(clk,rst_n,sys_rst_n,clk_25m,clk_100m);
 
	input clk;			//FPGA输入时钟信号
	input rst_n;		//系统硬件复位信号
	output sys_rst_n;	//系统复位信号,低有效	 
	output clk_25m, clk_100m;
	
	reg rst_r1, rst_r2;
	reg sysrst_nr1, sysrst_nr2;
	wire pll_rst;
	wire locked;		//输出信号有效标志,高表示PLL输出有效
	wire sysrst_nr0;
	wire sys_rst_n;		//系统复位信号,低有效
	
	//第一个异步复位同步释放
	always @(posedge clk or negedge rst_n)
		if(!rst_n) begin
			rst_r1 <= 1'b1;
			rst_r2 <= 1'b1;		//注意这里是“反”逻辑
		end
		else begin
			rst_r1 <= 1'b0;
			rst_r2 <= rst_r1;
		end
	 
	assign pll_rst = rst_r2;	//PLL的复位信号
	
	PLL_ctrl uut_PLL_ctrl(
		.areset(pll_rst),
		.inclk0(clk),
		.c0(clk_25m),
		.c1(clk_100m),
		.locked(locked)
	);
	
	assign sysrst_nr0 = rst_n & locked;		//"与"逻辑,下图中“非或”=“与非”
	
	//第二个异步复位同步释放
	//注意这里的同步时钟为合适的PLL输出时钟
	always @(posedge clk_100m or negedge sysrst_nr0)
		if(!sysrst_nr0) begin
			sysrst_nr1 <= 1'b0;
			sysrst_nr2 <= 1'b0;
		end
		else begin
			sysrst_nr1 <= 1'b1;
			sysrst_nr2 <= sysrst_nr1;
		end
	
	//信号sys_rst_n作为新的系统复位信号,后续可用作异步复位
	assign sys_rst_n = sysrst_nr2;

endmodule


 

  • 57
    点赞
  • 380
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
如果您在for循环中调用了异步方法,并且在这些异步方法中使用了UUID(通用唯一标识符)作为标识符,而且您已经在生成UUID时使用了同步锁`synchronized`,但仍然出现了UUID重复的问题,那么很有可能是因为同步锁的范围不正确。 为了避免在生成UUID时出现重复,您需要使用同步锁来保证在同一时间内只有一个线程生成UUID。但是,如果同步锁的范围不正确,多个线程仍然有可能同时访问UUID生成代码,从而导致重复。 下面是一个示例代码,演示如何在for循环中调用异步方法,并使用同步锁和唯一的UUID: ``` import java.util.UUID; import java.util.concurrent.CompletableFuture; public class Main { private static final Object lock = new Object(); // 定义同步锁 public static void main(String[] args) throws Exception { for (int i = 0; i < 10; i++) { String uuid; synchronized (lock) { // 加锁 uuid = UUID.randomUUID().toString(); // 生成唯一的UUID } CompletableFuture<Void> future = asyncTask(uuid); // 调用异步方法,并传入唯一的UUID future.get(); // 等待异步方法执行完成 } } static CompletableFuture<Void> asyncTask(String uuid) { // 异步任务 System.out.println("Starting task with UUID " + uuid); return CompletableFuture.completedFuture(null); } } ``` 在上面的示例代码中,我们定义了一个同步锁`lock`,并在生成UUID时使用`synchronized`关键字将锁的范围限定在了生成UUID的代码块内,从而保证了在同一时间内只有一个线程生成UUID,避免了UUID重复的问题。 通过这种方式,您可以使用同步锁来避免在for循环中出现UUID重复的问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值