[Verilog5]时序逻辑复位设计

时序逻辑电路的复位设计,同步复位/异步复位,同步/异步复位输入,提高复位扇出能力,复位体系设计

为什么需要设计复位模块?

  • 当我们的FPGA初始上电时,我们并无法确定其处于一个怎样的工作状态,所以,我们需要使用HDL代码,对FPGA进行必要的初始化。所以,为了确保系统能够从一个稳定的状态开始工作,我们有必要设计一个复位信号。
  • 除此之外,我们也无法保证我们的FPGA设计足够健壮,当外部输入信号出现不稳定或者非预期情况时,肯定无法保证FPGA设计行为的正确性。所以当系统陷入一个我们无法预期的状态中时,为了能够使FPGA能够恢复正常的工作状态,我们需要使用复位信号对其进行复位,使FPGA恢复到初始的稳定工作状态中。
  • 所以,综上所述,复位对FPGA设计的重要性可见一斑,并且在实际工程中,几乎所有的FPGA设计中都引入了复位功能。

复位方式的分类

  • FPGA设计的复位方式可以分为同步复位和异步复位两大类。下文将介绍两种复位方式的概念、区别及优缺点。

同步复位

  • 同步复位,是指若复位信号在时钟有效边沿到来时刻为有效,则执行一次复位操作。因此同步复位操作与置数操作是瞬间的、离散的。
  • 同步复位的优点:
  1. 由于同步复位是离散的,因此其非常有利于仿真器的仿真;
  2. 由于同步复位只有在时钟有效边沿到来时才生效,因此可以滤除高于时钟频率的毛刺,提高复位操作的可靠性;
  3. 使用同步复位的系统可以被设计成为纯粹的同步时序电路,这样会大大有利于FPGA项目开发流程中的时序约束与时序分析环节的工作,而且综合出来的FPGA设计的性能一般也会较高
  • 同步复位的缺点:
  1. 必须保证复位信号的有效持续时间长度大于一个时钟周期,否则该复位信号很可能被当做毛刺滤除掉,从而系统将漏掉一次应有的复位动作。
  2. 由于同步复位信号与时钟的相关性很大,因此设计和实现时必须要考虑到各种延迟和时间参数,确保其能够被FPGA设计正确接收并做出相应动作
  3. 由于大多数的寄存器都只有异步复位端口,因此,如果采用同步复位,那么编译器势必会在寄存器的数据输入端口添加额外的组合逻辑,这样就会消耗较多的逻辑资源。

异步复位

  • 异步复位,是指无论时钟信号的有效边沿是否到来,只要复位信号有效,就执行复位操作,直到复位信号变为无效才停止复位。因此异步复位操作与置数操作是持续的、连续的。
  • 异步复位的优点:
  1. 由于大多数的寄存器都具有异步复位端口,因此采用异步复位可以节省资源。
  2. 由于异步复位根本不关心复位信号与时钟信号及其他信号之间的关系,因此设计起来相对较简单。
  • 异步复位的缺点:
  1. 在异步复位信号释放的时,当异步复位信号释放的时刻和时钟有效沿比较接近时,就很容易导致寄存器的输出出现亚稳态;
  2. 由于复位信号所管辖的寄存器非常之多,而这些寄存器又位于FPGA芯片的不同地方,因此复位信号到达各个寄存器的路径延迟肯定是参差不齐的,所以,如果异步复位信号释放的时刻和时钟信号有效沿比较接近时,很可能导致一部分寄存器在该时钟有效沿之前完成复位,而另一部分寄存器在该时钟有效沿之后才完成复位,那么由于这一时钟周期的偏差,就很可能会导致后续的逻辑功能出现全面地混乱。
  3. 异步复位信号非常容易受到毛刺等干扰的影响。
  • 由于纯粹的异步复位会导致时序电路的功能紊乱,在时序电路中不具有可用性。故后续讨论的异步复位电路均为采用异步复位、同步释放机制的异步复位电路。

复位模块的具体设计

  • __ 纯粹的异步复位会导致系统的功能紊乱,因此不建议使用。一般情况下还是推荐使用同步复位的。不过同步复位会额外消耗不少资源,当资源比较紧张的时候,可采用低电平有效的异步复位、同步释放机制,是业界普遍推荐的能够很好地将这两者的优点集中到一起的异步复位方法。之所以采用低电平有效,是因为大部分的触发器均为低电平有效。__
  • 在下文所谈及的所有复位模块设计中,均探讨的是在时序逻辑中的复位设计。由于采用异步释放的方式会产生诸多亚稳态的时序问题,在时序电路中不具可用性,故在下文的复位模块设计中,无论是采用同步复位还是异步复位,均采用同步释放的方式进行释放。

复位信号为同步信号

  • 如果复位信号是属于当前时钟域的,那么该复位信号就是一个同步信号,即该复位信号不存在跨时钟域问题,故从效果上看,采用同步复位同步释放还是异步复位同步释放仅是代码书写上的问题,对使用功能并没有太多影响。下面具体介绍再同步复位信号下的两种复位方法。

同步信号同步复位

  • 如果资源不是特别紧张,我们就可以放心采用同步复位的方式来直接使用该复位信号,代码示例如下:
[email protected](posedge clk)begin
    if(!rst_n)
        dout <= 0;
    else
        dout <= din;
end

同步信号异步复位

  • 如果复位信号是一个同步信号,我们也可以采用异步复位的方式来直接使用该复位信号,因为使用同步信号可以规避异步复位方式的缺点,并且还更节省资源。需要注意的是,鉴于大部分触发器都具有低电平有效的复位引脚,因此一般来说,复位信号设计为低电平有效会更加节省资源。
  • 代码示例如下:
[email protected](posedge clk or negedge rst_n)begin
    if(!rst_n)
        dout <= 0;
    else
        dout <= din;
end

复位信号为异步信号

  • 如果复位信号并不属于当前模块的时钟域,那么该复位信号就是一个异步信号,此时无论是采用同步复位方式或者异步复位方式,都有可能造成系统行为出错,这是跨时钟域问题所导致的必然结果。当rst_n的上升变化出现在了clk上升的建立保持时间上,此时clk检测到的rst_n的状态就会是一个亚稳态(是0是1不确定)
  • 所以,除了异步复位异步置数的复位置数方式外(由于该复位方法与输入时钟无关,只由),我们都需要该对异步复位信号做相应的处理,先将其同步化,然后再用来复位系统即可。同步化的方法可使用两个触发器进行打拍操作,从而消除亚稳态,具体可参考[FPGA10]CDC_单比特跨时钟域传输
  • 下面具体介绍再异步复位信号下的两种复位方法。

异步信号同步复位

  • 异步信号同步复位的思路是,首先先将复位信号在目标时钟域下打两拍,将复位信号同步到目标时钟域下。再使用该信号进行同步信号同步复位操作。同理同步复位信号下的复位操作,对同步后的复位信号采用同步复位还是异步复位的写法均可。
    • 代码示例如下,HDL图展示的是先将异步复位信号使用触发器打两拍,再使用同步信号同步复位的实现方式
///将异步复位信号同步到目标时钟域///
always @ (posedge clk)begin
    rst_n_r <= rst_n;
    rst_n_rr <= rst_n_r;
end
///采用同步信号下的同步复位方式///
[email protected](posedge clk)begin
    if(!rst_n_rr)
        dout <= 0;
    else
        dout <= din;
end
///采用异步信号下的异步复位方式///
[email protected](posedge clk or negedge rst_n_rr)begin
    if(!rst_n_rr)
        dout <= 0;
    else
        dout <= din;
end
  • 从HDL原理图上可以看出,对于输入的复位信号,使用触发器进行了打拍操作,有效的消除了亚稳态问题;但导致复位信号会滞后于输入至少两个时钟周期才会起作用

异步信号异步复位

  • 在异步复位信号跨时钟域的情况下,采用同步复位打两拍的方式,能够很好的将复位信号同步化,但随之带来的就是复位信号会在真实的复位信号到来后至少两个时钟周期才会输出。当我们需要在一些对复位时刻较为严格的项目中时,也可考虑对复位信号的使能信号不进行同步,直接进行传输,但对复位信号的释放信号进行打拍操作,将其同步后再进行传输。同理,对于已处理后的复位信号,再采用同步信号下的同步复位方式或异步复位方式均可,仅是代码书写上的问题,对使用功能并没有太多影响。
  • 代码示例如下,HDL图展示的是对输入的复位信号,在使能时,采用异步信号直接供后级;而在释放时,将释放信号同步后再进行后续使用。处理完成后,再使用同步信号下的异步复位方式进行复位。
///将异步复位信号使能信号直接使用,释放信号同步后使用///
always @ (posedge clk or negedge rst_n)begin
    if(!rst_n)begin
        rst_n_r <= 0;
        rst_n_rr <= 0;
    end
    else begin
        rst_n_r <= rst_n;
        rst_n_rr <= rst_n_r;
    end
end
///采用异步信号下的异步复位方式///
[email protected](posedge clk or negedge rst_n_rr)begin
    if(!rst_n_rr)
        dout <= 0;
    else
        dout <= din;
end
  • 从HDL原理图上可以看出,对于输入的复位信号的复位操作,直接作用于两个触发器的复位输入端,即直接进行跨时钟域异步复位,由于复位信号具有更高的优先级,故异步复位可保证系统稳定复位;当复位信号释放时,对释放信号打两拍进行同步化,从而消除当时钟沿与复位信号的撤离比较接近时,产生的亚稳态现象。
  • 使用该方法进行复位操作,可保证当复位信号到来时,系统可马上进入有效复位状态;而当复位信号撤离时,系统又可以同步释放。故该方法又被称为跨时钟域下的异步复位同步释放操作。

提高复位的扇出能力

  • 在FPGA设计中,复位信号的扇出可以说和时钟信号相当了,因为复位信号几乎是作用于设计中的所有寄存器,那么,在FPGA设计中,我们该怎么满足复位信号如此高的扇出要求呢?我们可以采用寄存器复制的方式进行实现。

实现原理

  • 假设FPGA设计中有1000个寄存器需要复位,而复位信号是由一个叫R的寄存器的输出驱动的,那么此时的复位信号的扇出即为1000。此时,如果我们能够让多个寄存器的输出都跟R保持一致,那么其实这些寄存器的输出也可用来对这1000个寄存器进行复位的,那么如果类似R的寄存器共有10个,并且我们均匀分配每一个类R寄存器所需要复位的寄存器的数量,再加上让这些类R寄存器在FPGA芯片中均匀排列,那么每一个类R寄存器都可以就近去复位其周围的100个寄存器,这样不但扇出减少了一个数量级,而且布线延迟也减小了许多。
  • 按照上述原理,我们只要让复位信号在FPGA中被一个寄存器驱动,至于需要创建多少个类R寄存器以及它们该分布在什么位置?怎么布局布线?这些都交给编译器就好了,我们只需要为编译器提供正确地时序约束即可。

具体实现方法

同步复位信号

  • 如果复位信号为同步信号,我们需要添加如下代码:
[email protected](posedge clk)begin
    rst <= reset;
end
  • 在该例子中,rst便成了R寄存器,编译器可以根据实际的扇出需求和时序约束,复制出若干个R寄存器以满足需求。

异步复位信号

  • 同理,如果复位信号为异步信号,我们只需要将原有的两级打拍改成三级打拍即可。
[email protected](posedge clk)begin
    rst_r <= rst;
    rst_rr <= rst_r;
    rst_rrr <= rst_rr;
end
  • 在该例子中,rst_r和rst_rr便构成了两级触发器进行跨时钟域的打拍操作,而rst_rrr便成为了R寄存器,编译器可利用它复制出若干个R寄存器。

复位体系设计

全局复位与局部复位

  • 全局复位指的是当复位信号有效时,整个FPGA芯片将会被重置为一个预先设定好的初始状态。可事实上,有些时候我们并不需要也并不希望重置整个FPGA芯片的状态。所以,在FPGA设计中还可以存在一种仅使部分FPGA芯片重置的复位信号,相应的,我们称其为局部复位。
  • 除了功能上的原因外,不同的时钟域也不可能共用同一个复位信号(即使我们希望使用一个复位信号来复位所有的时钟域,那么该复位信号被各个时钟域同步化后,也已经变成了多个局部复位信号),因此局部复位的情况是广泛存在的。

复位体系模板

  • 推荐一种比较常用的复位体系规划模板,即“两级复位体系”,大体思路为:整个FPGA芯片必须有一个全局复位信号,如果FPGA设计包含不止一个时钟域,该全局复位信号经过不同的时钟域同步化后,转化为每个时钟域的全域复位信号,与此同时,根据实际情况将每个时钟域划分为若干个局部子域,并为每个子域提供一个局部复位信号。其中,全局复位信号或全域复位信号采用异步复位的方式,而各个局部复位信号则采用同步复位的方式。

参考:

《FPGA之道》,狄超,刘萌著,西安交通大学出版社,5.2.10节