Filters an asynchronous reset signal so it can assert immediately and
asynchronously, but can only release synchronously with a receiving clock
(after 2 or 3 (plus
EXTRA_DEPTH) cycles of latency), which avoids
metastability issues should the reset release too close to the receiving
RESET_ACTIVE_STATE parameter to the value of your reset when
active (e.g.: 0 for active-low reset).
If you are running near the speed or temperature limits of your silicon,
you may have to add some extra synchronizer stages with the
parameter. Consult your datasheets.
This design combines the internals of a CDC Bit
Synchronizer and of a Register with
Asynchronous Reset (please see those modules for
more background). We cannot instantiate those modules here since we have
to apply some attributes directly to
reg values to make a good
synchronizer, and the CDC Synchronizer module does not have a reset.
Much like a CDC Synchronizer, you can only synchronize a given reset bit in
one place, as two synchronizers fed by the same input may have different
output latencies due to metastability. Also, feed the
directly from a register, as combinational logic glitches could trigger
spurious resets. Finally, you cannot place any of the registers into I/O
registers: they are too far away from the main logic fabric to make a good
Make sure no logic under asynchronous reset feeds logic which is not also under reset, else metastability may happen in the latter logic since the reset assertion is not synchronous to the clock. If you need reset assertion to be synchronous, use a CDC Synchronizer instead.
Also, note that introducing an asynchronous reset, even with synchronized release, may prevent any register retiming from ocurring in connected logic. Check your CAD tool results, and favour the plain CDC Synchronizer instead.
3 + EXTRA_DEPTHcycles before I/O transactions can begin.
`default_nettype none module Reset_Synchronizer #( parameter EXTRA_DEPTH = 0, parameter RESET_ACTIVE_STATE = 2 // Must be 0 (active-low) or 1 (active-high) ) ( input wire receiving_clock, input wire reset_in, output reg reset_out ); initial begin reset_out = ~RESET_ACTIVE_STATE ; end
The minimum valid synchronizer depth is 2. Add more stages if the design requires it. This usually happens near the highest operating frequencies. Consult your device datasheets.
localparam DEPTH = 2 + EXTRA_DEPTH;
For Vivado, we must specify that the synchronizer registers should be placed close together (see: UG912), and to show up as part of MTBF reports.
For Quartus, specify that these register must not be optimized (e.g. moved into the input register of a DSP or BRAM) and to mark them as composing a synchronizer (and so be placed close together).
In both cases, we also specify that the registers must not be placed in I/O register locations.
// Vivado (* IOB = "false" *) (* ASYNC_REG = "TRUE" *) // Quartus (* useioff = 0 *) (* PRESERVE *) (* altera_attribute = "-name SYNCHRONIZER_IDENTIFICATION \"FORCED IF ASYNCHRONOUS\"" *) reg sync_reg [DEPTH-1:0]; integer i; initial begin for(i=0; i < DEPTH; i=i+1) begin sync_reg [i] = ~RESET_ACTIVE_STATE ; end end
Now, depending on the reset active state, we instantiate one of two cases, distinguished only by the active edge of the reset signal. (It's grotesque to have such code duplication, but it's the only way.)
reset_in is asserted (as specified in
asynchronously place all synchronizer registers in reset, which immediately
reset_out. Then, when
reset_in is released, the synchronizer
will synchronously release
DEPTH + 1 cycles,
depending on the metastability of the first
RESET_ACTIVE_STATE is given a value other than 0 or 1, try to
instantiate a non-existent module to force synthesis or simulation to fail
immediately, with the instance name as the error message. It's ugly, but
CAD tools usually ignore
$finish() system functions
We must have this failsafe, else an invalid
reset_out always inactive, causing hard-to-find, intermittent
bugs in the logic dependent on
reset_out. Note the use of the identity
===) instead of the equality operator (
==), so a parameter
X value does not implicitly match zero/false.
generate if (RESET_ACTIVE_STATE === 0) begin always @(posedge receiving_clock, negedge reset_in) begin if (reset_in == RESET_ACTIVE_STATE ) begin for(i = 0; i < DEPTH; i = i+1) begin sync_reg [i] <= RESET_ACTIVE_STATE ; end end else begin sync_reg  <= ~RESET_ACTIVE_STATE ; for(i = 1; i < DEPTH; i = i+1) begin sync_reg [i] <= sync_reg [i-1]; end end end end else if (RESET_ACTIVE_STATE === 1) begin always @(posedge receiving_clock, posedge reset_in) begin if (reset_in == RESET_ACTIVE_STATE ) begin for(i = 0; i < DEPTH; i = i+1) begin sync_reg [i] <= RESET_ACTIVE_STATE ; end end else begin sync_reg  <= ~RESET_ACTIVE_STATE ; for(i = 1; i < DEPTH; i = i+1) begin sync_reg [i] <= sync_reg [i-1]; end end end end else begin // verilator lint_off DECLFILENAME NonExistentModuleForErrorChecking ERROR_RESET_ACTIVE_STATE_MUST_BE_0_OR_1 (); // verilator lint_on DECLFILENAME end endgenerate always @(*) begin reset_out = sync_reg [DEPTH-1]; end endmodule
Back to FPGA Design Elements