Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Synchronous reset design in fpga as the limiting factor for timing constraints

I've got an fpga design that utilizes synchronous resets (I prefer synchronous resets to asynchronous for reasons discussed elsewhere). I have four different clock domains in the design and I utilize a single button to generate my reset signal, which is of course totally asynchronous to everything (save my finger). I debounce the button signal in each of the four clock domains to generate synchronous resets for the four domains from a single source. My debounce module basically counts N clock cycles of the reset button being asserted. If more than N cycles have passed with reset asserted then I generate my reset signal (code for this module pasted below).

First question -- are there better ways of generating the reset(s) than this method?

Second (more interesting question): when I look at the timing reports (using xilinx tools) I see that consistently the limiting signals are all reset related. For example the limiting path is from the reset generator (debouncer) to some state machine's state register. The reset signals are very high fan out (they touch everything in their respective clock domains). I'm a little surprised though that my speed is limited by the reset. I'm finding that I'm limited to something like 8.5 nS where ~50% is routing and ~50% of that is logic. Any suggestions on how to do this a little better? How do you go about dealing with synchronous reset generation in fpga designs?

Here's the code for reset generation. Note that the signal reset signal is akin to the debounced output (e.g. when I instantiate the module the debounced output is the reset for that particular clock domain).

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
like image 439
Doov Avatar asked May 31 '13 19:05

Doov


1 Answers

A very good way to improve timing scores while working with resets is to cap the max fanout. the tools will then buffer the signal so that there is not one lut trying to be routed and used to drive every register. This can be accomplished in this way:

(* max_fanout = <arbitrary_value> *) 
wire reset; 

so what we have here is a constraint used by the vivado synth tool (or if you are still using ISE, then that tool). Also, if should be noted that this only affects the next declaration of a net, so other nets (wires, regs, ext) declared before or after this are unaffected.

There is a good constraint user guide on xilinx's website. There are a few other ones that you may want to look into as well and they are: IBUF or BUFG.

like image 122
alex_milhouse Avatar answered Nov 15 '22 12:11

alex_milhouse