FPGA reset synchronous design as a limiting factor for time constraints

I have an fpga project that uses synchronous flushes (I prefer synchronous flushes to asynchronous flushes for reasons discussed elsewhere). I have four different clock domains in the design, and I use one button to generate my reset signal, which, of course, is completely asynchronous to everything (except for my finger). I reject the button signal in each of the four clock domains in order to generate synchronous drops for four domains from the same source. My debounce module basically calculates N clock cycles of the reset button. If more than N cycles have passed with reset, then I generate my reset signal (the code for this module is inserted below).

The first question is, are there better ways to generate reset (s) than this method?

The second (more interesting question): when I look at the deadline reports (using xilinx tools), I see that all limit signals are related to reset. For example, the limit path from the reset generator (debouncer) to some register of the state of the machine state. The reset signals are very high (they relate to everything in their clock domains). I am a little surprised, although my speed is limited to reset. I find that I am limited to something like 8.5 nS where ~ 50% is routed and ~ 50% is the logic. Any suggestions on how to make this a little better? How do you feel about synchronous reset generation in fpga projects?

Here is the code to generate reset. Note that the reset signal is akin to debut output (for example, when I create an instance of the module, the debounced output is reset for this particular synchronization 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 
+6
source share
2 answers

A very good way to improve time performance when working with discharges is to limit the maximum branching. the tools will then buffer the signal so that there is not one loot trying to route and used to manage each register. This can be done as follows:

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

so we have here the limitation used by the synv vivado tool (or if you are still using ISE, then this tool). In addition, it should be noted that this only affects the next announcement of the network, therefore other networks (wires, regs, ext) declared before or after are not affected.

The xilinx website has a good guide to limit restrictions. There are several others that you might want to learn, as well: IBUF or BUFG.

+2
source

You do not need four instances of the debouncer. Place one debounder from your main watch, and then use three metastable filters to synchronize its output with the other three domains.

Also, when you distribute your reset, you should use what Cliff Cummings calls the "synchronous reset distribution tree." Check his website for some documents about this.

0
source

Source: https://habr.com/ru/post/946289/


All Articles