fpga中的同步复位设计是时序约束的限制因素

Doo*_*oov 6 verilog fpga xilinx

我有一个利用同步复位的fpga设计(由于其他地方讨论的原因,我更喜欢同步复位到异步).我在设计中有四个不同的时钟域,我利用一个按钮来产生我的复位信号,这当然是完全异步的(保存我的手指).我在四个时钟域中的每一个中去抖按钮信号,以从单个源生成四个域的同步复位.我的去抖模块基本上计算了被置位的复位按钮的N个时钟周期.如果复位断言超过N个周期,则生成复位信号(此模块的代码粘贴在下面).

第一个问题 - 有没有比这种方法更好的方法来产生重置?

第二个(更有趣的问题):当我查看时序报告(使用xilinx工具)时,我发现一致的限制信号都与模块有关.例如,限制路径是从复位发生器(去抖动器)到某个状态机的状态寄存器.复位信号的扇出非常高(它们触及各自时钟域中的所有内容).虽然我的速度受到重置的限制,但我有点惊讶.我发现我只限于8.5 nS,其中~50%是路由,其中​​约50%是逻辑.关于如何做得更好的任何建议?你如何处理fpga设计中的同步复位生成?

这是重置生成的代码.注意,信号复位信号类似于去抖动输出(例如,当我实例化模块时,debounced输出是该特定时钟域的复位).

module button_debouncer(/*AUTOARG*/
   // Outputs
   debounced,
   // Inputs
   clk, button
   );
   /* Parameters */
   parameter WIDTH = 1;
   parameter NUM_CLKS_HIGH = 12000000;
   parameter log2_NUM_CLKS = 24;

   /* Inputs */
   input clk;
   input [WIDTH-1:0] button;

   /* Outputs */
   output [WIDTH-1:0] debounced;

   /* Regs and Wires */
   reg [WIDTH-1:0]    b1, b2;
   reg [log2_NUM_CLKS-1:0] counter;

   /* Synched to clock domain */
   always @(posedge clk) begin
      b1 <= button;
      b2 <= b1;
   end

   /* Debounce the button */
   always @(posedge clk) begin
      if(~b2)
    counter <= 0;
      else if(counter < {log2_NUM_CLKS{1'b1}})
    counter <= counter + 1;
   end

   /* Assign the output */
   //wire [WIDTH-1:0] debounced = counter > NUM_CLKS_HIGH;
   reg [WIDTH-1:0] debounced;

   always @(posedge clk) begin
      debounced <= counter > NUM_CLKS_HIGH;
   end

endmodule //button_debouncer
Run Code Online (Sandbox Code Playgroud)

ale*_*use 2

在处理重置时提高时序分数的一个非常好的方法是限制最大扇出。然后,工具将缓冲信号,以便没有一个 lut 尝试路由并用于驱动每个寄存器。这可以通过以下方式完成:

(* max_fanout = <arbitrary_value> *) 
wire reset; 
Run Code Online (Sandbox Code Playgroud)

所以我们这里有一个 vivado Synth 工具使用的约束(或者如果您仍在使用 ISE,则使用该工具)。另外,应该注意的是,这仅影响网络的下一个声明,因此在此之前或之后声明的其他网络(wires、regs、ext)不受影响。

xilinx 网站上有一份很好的约束用户指南。您可能还想研究其他一些内容,它们是:IBUF 或 BUFG。