FPGA复位电路设计及其时序分析

  通常同步电路由两种复位方式,即同步复位和异步复位。同步复位同步于寄存器的时钟域,异步复位则是立即自然地作用于寄存器,与其寄存器所在的时钟域之间没有确定的时序关系。同步化的异步复位是FPGA电路设计时复位电路的首选。

1 同步复位

1.1 同步复位在外部的情况

代码:

module sync_reset_ext(
input           clock,
input           reset_n,
input           data_a,
input           data_b,
output          out_a,
output          out_b
    );
reg             reg1,reg2;
assign          out_a = reg1;
assign          out_b = reg2;

always @(posedge clock) begin
    if(!reset_n) begin
        reg1 <= 1'b0;
        reg2 <= 1'b0;
    end
    else begin
        reg1 <= data_a;
        reg2 <= data_b;
    end
end
endmodule

Vivado工具综合出来的RTL如下图所示:

  这里用到的是MUX(也可以使用与门来实现),这种方式需要考虑额外的门延迟,复位信号数据经过MUX逻辑电路使得复位信号到达时间(Data Arrival Time)会增加,在这种情况下,建立时间的slack可能为负值。同步复位总是比异步复位来的慢,在FPGA中不是最好的复位方式。

1.2 同步复位在内部的情况

 代码:

module sync_reset(
input           clock,
input           reset_n,
input           data_a,
input           data_b,
output          out_a,
output          out_b
    );
reg             reg1,reg2;
reg             reg3,reg4;
wire            rst_n;
assign          out_a = reg1;
assign          out_b = reg2;
assign          rst_n = reg4;
always @(posedge clock) begin
    if(!rst_n) begin
        reg1 <= 1'b0;
        reg2 <= 1'b0;
    end
    else begin
        reg1 <= data_a;
        reg2 <= data_b;
    end
end
always @(posedge clock) begin
    reg3 <= reset_n;
    reg4 <= reg3;
end
endmodule

Vivado综合出来的RTL如下图:

  跟1.1的区别是,复位信号打了两拍。为什么要这么做?因为大部分时候,输入到FPGA的复位信号是异步信号,在这种情况下,复位信号必须在内部先同步后再送达寄存器。既然输入的是异步信号,那么常常有可能该异步信号的脉宽比较小(小于一个时钟周期)。这种异步信号比时钟脉宽小的缺点是,异步信号同步时必须保证脉宽至少是一个时钟周期长,。才能保证异步复位信号在第一个同步寄存器被捕获;优点是,脉宽段可以增加其抗噪性能,在异步输入上的一些虚假脉冲,例如毛刺,很难在第一个寄存器被捕获,也就不会误触发同步复位。

2 异步复位

   异步复位最大的优点,是没有像同步复位那样插入到数据路径中,因此异步复位对寄存器之间的数据到达时间不会产生负面影响。另一个优点是,异步复位是立即生效的。

代码:

module aync_reset(
input           clock,
input           reset_n,
input           data_a,
output          out_a
    );
reg             reg1,reg2,reg3;
assign          out_a = reg3;
always @(posedge clock,negedge reset_n) begin
    if(!reset_n) begin
        reg1 <= 1'b0;
    end
    else begin
        reg1 <= data_a;
    end
end
always @(posedge clock) begin
    reg2 <= reg1;
    reg3 <= reg2;
end
endmodule

Vivado综合出来的电路图:

  但是,异步复位在复位被释放的时候可能会出现问题。异步复位在释放的时候,可以出现在时钟的任何一个时候,复位信号在撤除是,复位信号的边沿可能会落入时钟的一个亚稳态区域。亚稳态带来的后果是寄存器的输出需要花费更多的时间来恢复稳定或者正确的状态。这个额外的增加的时间可能会导致寄存器下一级的建立时间失败,从而导致系统错误。那么,如果这个异步复位信号,能够被同步到clock时钟域下,那么这个问题也就解决了,也就是接下来要说的异步复位同步释放的设计。

3 异步复位同步化

代码:

module sync_async_reset(
input           clock,
input           reset_n,
input           data_a,
input           data_b,
output          out_a,
output          out_b
    );
reg             reg1,reg2;
reg             reg3,reg4;
wire            rst_n;
assign          out_a = reg1;
assign          out_b = reg2;
assign          rst_n = reg4;

always @(posedge clock,negedge reset_n) begin
    if(!reset_n) begin
        reg3 <= 1'b0;
        reg4 <= 1'b0;
    end
    else begin
        reg3 <= 1'b1;
        reg4 <= reg3;
    end
end
always @(posedge clock,negedge rst_n) begin
    if(!rst_n) begin
        reg1 <= 1'b0;
        reg2 <= 1'b0;
    end
    else begin
        reg1 <= data_a;
        reg2 <= data_b;
    end
end
endmodule

 

  第一个always块用来产生同步复位输出rst_n,作为第二个always块的异步复位,第二个将这个已经同步化了的复位信号当做异步复位使用。两个进程模块的复位信号都位于各自的敏感列表中。同步器中的寄存器级数(打拍级数)可以视情况而定,但是要确保同步后的异步复位信号至少有一个时钟周期的长度。

Vivado综合出来的RTL如下图所示:

 

posted @ 2019-07-01 22:23  yiwenbo  阅读(1883)  评论(0编辑  收藏  举报