目录

一开始接触到FPGA,肯定都知道”复位“,即简单又复杂。简单是因为初学时,只需要按照固定的套路——按键开关复位,见寄存器就先低电平复位一次,这样一般情况可以解决99%的问题,甚至简单的设计,就不可能有问题。复杂是因为复位本身是对大规模的硬件单元进行一种操作,必须要结核底层的设计来考虑问题。

1. 常见问题

自己在学习实践过程中,以及看到网友询问的,有关FPGA复位设计大概有以下几类问题:

  • 我板子上没有设计按键复位怎么办?
  • 怎么设计上电复位?不可能上电都要去按键吧
  • 同步复位还是异步复位?各自优势是啥?
  • 高电平复位还是低电平复位?

……

归根结底,就是怎样设计复位,我可能给不出完美的答案,但查阅了一些资料,总结了一些设计中考虑的因素,在加上参考文献,应该能解决99.9%的疑惑。

2. 常见的复位方式

我们习惯上通常使用的复位有三种方式:

  • 硬件开关:复位信号接一个拨码开关或按键,或者RC电路

  • 电源芯片:上电时候电源芯片产生,可以长时间维持,直到稳定。

  • 控制芯片:控制芯片产生复位脉冲。

没有专门的电源或控制芯片,甚至连按键都忘记设计的情况下,有人提出可不可以拿内部计数器做一个所谓的上电“软”复位,如下代码所示,当cnt计数到一定的值时,产生一个复位脉冲信号。

always@(posedge clk or negedge rst_n)
 begin
     if(!rst_n)
         cnt <= 0;
    else
         begin
        if(cnt < 23'd50_00000) //100ms
             cnt <= cnt+1'b1;
         else
             cnt <= cnt;
        end
 end
 always@(posedge clk or negedge rst_n)
  begin
      if(!rst_n)
          begin
          rst_nr0 <= 0;
          rst_nr1 <= 0;
          end
      else if(cnt == 23'd50_00000)
          begin
          rst_nr0 <= 1;
          rst_nr1 <= rst_nr0;
          end
      else
          begin
          rst_nr0 <= 0;
          rst_nr1 <= 0;
          end
  end

没有设计外部硬件复位的同学又会反驳,我rst_n都没有!去掉复位,默认上电cnt = 0,可不可以?既然默认cnt = 0了,那其他所有的寄存器不都默认为0了吗?接着往下分析。

3. 合理的复位设计

从参考文献中得出有关复位设计的几条重要结论,有助于我们明确复位设计的方向,如下:

  1. 低电平复位并不是最合理的处理方式;
  2. 建议采用异步复位同步化(异步复位同步释放处理)
  3. 全局复位并不是最佳方式;
  4. 并不是所有时序电路都要加复位;

对上述结论分析,见后续总结。

3.1 复位电平

有关复位电平,实际上是跟FPGA芯片内部的触发器结构有关,在之前的博文有提到过。作为xilinx 7系列触发器,其 R 端口既可用作同步置位/复位端口,也可用作异步预设/清除端口,但无论哪种方式,都是高电平有效。Altera的是低电平有效。

当在7系列芯片上采用低电平复位,会有什么问题呢?如下:

弄清FPGA基础 -- 复位设计-LMLPHP

所以再次强调:复位电平的选择跟芯片结构有关!

3.2 异步复位同步化

异步复位同步化简单的说就是将异步复位信号在相关的时钟域模块中进行同步化处理。单纯的同步复位、异步复位以及其他的一些复位方式,都存在一些缺陷,比如抗噪声、存在亚稳态等问题,深入学习可以查阅相关文献。

异步复位同步化处理的结构代码及schematic(xilinx 7系列)如下:

 module rst_signal(
    input       clk,
    input       rst,
    output      sys_rst
 );
    reg         r1_rst,r2_rst;

    always@(posedge clk or negedge rst) begin
        if(rst) begin
            r1_rst <= 1'b1;
            r2_rst <= 1'b1;
        end else begin
            r1_rst <= 1'b0;
            r2_rst <= r1_rst;
        end
    end

    assign sys_rst = r2_rst;

endmodule

弄清FPGA基础 -- 复位设计-LMLPHP

可以看到,模块将系统输入的异步复位信号进行同步,产生了一个后续逻辑使用的同步化了的异步复位,随后即可将该复位信号sys_rst用于其他模块的复位。为了减少亚稳态对上述同步器中的两个寄存器的影响,这两个寄存器应该在FPGA中被放置的越靠近越好(相应的约束:set_property ASYNC_REG TRUE [get_cells [list r1_rst_reg r2_rst_reg]]),尽量减少布线延迟。

以上只是一个基本原理示意,在实际使用过程中还应注意以下两点:

  • 外部输入异步复位信号应该增加滤波和去抖处理;
  • 在复位之前,确保由 MMCM 或PLL 生成的时钟是稳定且被锁定的;
  • 将异步复位信号分别引入不同的时钟域进行同步化

综上,复位处理的原理图如下所示:

弄清FPGA基础 -- 复位设计-LMLPHP

3.3 恰到好处的复位

看似简单的复位,实际上不简单,来系数复位的N宗罪:

  • 复位网络需要占用布线资源;
  • 导致其余信号的布线信号受到影响,降低了它们布线的自由度;
  • 增加的布线网络往往需要使用更高速率的芯片;
  • 复位网络占用大量布线资源,使得Place&Route的时间大大增加;
  • 复位信号需要占用大量的逻辑资源;
  • 复位信号需要使用触发器的专用复位管脚;
  • 可操作的复位信号往往导致D触发器的输入前增加额外的门操作或专用的复位信号输入;
  • 增大整个设计 的尺寸;
  • 额外的逻辑消耗降低了系统的性能;
  • 阻止了使用高效特征,如Xilinx FPGA特有的SRL16E 移位寄存器。

简单的说,复位的存在会对FPGA的综合面积产生影响,主要体现在两个方面:第一、在编写代买的时候,习惯给所有时序电路都加上复位信号,这样往往会导致资源无形的浪费;第二,没有合理的设计复位电路会产生额外的资源消耗。

什么时候可以叫复位呢?一般判断原则是:

4. 补充

4.1 所谓的上电初始化

所以在xilinx平台,开篇的“软”复位,实际上是没有多大意义的。

综上,采用以上总结的复位处理方法,应该能解决99.9%的问题了。

参考文献

  1. 《wp272: Get Smart About Reset: Think Local, Not Global》;
  2. 《FPGA实战演练. 高级技巧篇》——王敏志编著;
  3. DC综合之CDC篇
  4. How do I reset my FPGA?
  5. Xilinx FPGA复位逻辑处理小结
  6. FPGA的复位方法几种方法
  7. 在FPGA开发中尽量避免全局复位的使用?
01-24 16:15