01signal.com

Resets on FPGA: Synchronous, asynchronous or not at all?

This is the second page in a series about resets in FPGAs. After explaining why asynchronous resets are not what many people think in the previous page, this page discusses the different options for resets and FPGA initialization.

First: What is a reset?

Like, come on, we all know what a reset is! It's like that button on the PC, that you press and everything starts from clean. It's that signal that goes into a chip that ensures that no matter what happened before, from now everything will be fine. Some people refer to the reset as the signal that brings the system to a known state.

To FPGA designers, the reset is often just that extra input to add to every module and use in a repeated code pattern. Something we just do, not necessarily paying attention to what this reset signal actually ensures, if at all, or if it can be omitted altogether.

The most common misconception is to focus on the fact that the reset signal brings the system to a known state. That's true, of course, but the important part is what happens after the reset is released. The logic must be ensured to begin working in a predictable manner. Or at least, predictable enough to ensure it works properly. It's pointless to reset a system if we're not sure about its behavior after we've released it.

What makes this topic tricky in particular is that there's luck involved: Generally speaking, the state of the system when the reset was asserted isn't predictable, and neither is the timing of the reset's release. An improper handling of the reset signal can therefore result in rare malfunctions, which may appear to be a completely different problem. Likewise, it's possible to neglect this issue without any apparent consequences, except for occasional problems that are usually treated with witchcraft.

Just like proper timing constraints, proper clock handling and clock domain crossing, a proper treatment of the FPGA's wakeup and reset is a necessity to ensure that the FPGA works reliably. Common to all of these necessities is that one can kind-of get away with neglecting them, and quite some engineers do, but unfortunately at the cost of an FPGA that behaves like it's haunted every now and then.

Simulation vs. hardware

It's important to distinguish between the consequences on the simulation and those on the synthesized design: Simulators are typically inclined towards using resets, and hence assign the X (unknown) initial value to all registers, in particular in behavioral simulation. These X values then propagate to any register that depends on an X value in its logic function, so quite often even a single register with an X value swamps the entire design with X's, rendering the simulation useless.

It's therefore a common lazy choice to reset all registers in order to avoid chasing the source of X values in the simulation. This doesn't only waste resources and possibly makes it harder to meet timing: Refraining from resetting registers that don't need it can also help spotting bugs, as a flood of X values may origin from an unintentional dependency from one register to another; hence this flood is a warning that something is wrong with the design.

As for synthesis, all registers have some initial value of course, but not necessarily the one expected. For example, if a synthesizer is given this snippet,

reg val;

always @(posedge clk)
  val <= 1;

it may very well decide that @val is a wire that has a constant value of 1, as opposed to assigning a register with zero as the initial value, so it changes to 1 on the first clock.

So the hardware implementation is much more forgiving on avoiding resets, but it's also likely to fail miserably if resets are not applied where they should.

Unstable clocks and the need for reset

It's quite common (and usually recommended) to use the FPGA's own PLLs for generating clocks. But these PLLs usually start operating at the same time as all other logic on the FPGA becomes active. As a result, logic that depends on these clocks is fed with an unstable clock, having a frequency that can be significantly higher than normal.

When this happens, the timing of the relevant logic paths is not guaranteed. Hence any logic that relies on clocks generated by PLLs should be treated as if it failed meeting timing constraints until the PLL is locked.

The adequate and common solution is to hold all such logic in reset until the related PLL is locked. Alternatively, this logic can be set to ignore the clock until the PLL's lock, e.g. by ensuring that the flip-flops' Clock Enable (CE) input is deasserted.

If an external clock is connected directly from the FPGA's pin to its logic elements, it's a matter of whether the clock generator (typically a PLL) has locked quicker than the FPGA is configured. It's not always easy to be sure about this.

Consequently, many of the synchronous elements need to be reset in most designs. Or more precisely, one can divide these elements into three groups:

It's worth mentioning that some FPGAs allow to set up the configuration process, so that the FPGA's wakeup is delayed until all PLLs are locked. This could be a way to solve this issue, however it can also cause the FPGA to appear completely dead if some input clock is missing or otherwise problematic.

Strategies for resetting

The decision on if and how to apply resets on registers requires considering the case of each register separately. Doing this doesn't just avoid an unnecessarily high fan-out of the reset signals, but it's also a good opportunity to reflect on whether the logic is guaranteed to start off correctly after the reset, no matter its previous state.

There are in essence four options:

My opinion

There's a long discussion on each option below, so I'll first present what I consider to be the correct way, and then elaborate:

This is pretty much in line with what FPGA vendors recommend these days.

To wrap up with a very general guideline: Always reset control logic explicitly and let data paths flush themselves from their initial junk data.

And now the lengthy discussion on each option.

Option #1: Unknown initial value

Some registers don't need any reset nor initial value. This applies in particular to shift registers and other delay elements. Generally speaking, data paths are likely to fit this option.

Consider this snippet:

reg [31:0] d0, d1, d2, d3, d4;

always @(posedge clk)
  begin
    d4 <= d3;
    d3 <= d2;
    d2 <= d1;
    d1 <= d0;
    d0 <= orig_data;
  end

This is clearly five delay registers of 32 bits each. On some FPGA devices (Xilinx in particular), the synthesizer detects this as a shift register if only the last element (register @d4) is used, and there's no reset on any of these registers. This can reduce the logic consumption considerably.

Clearly, the logic that consumes the output of these delay registers must be able to tolerate some initial random data going its way. A typical case when this is no problem is when there's some other register or state machine, that is properly reset and makes sure that uninitialized values are ignored as they arrive. For example, if these delay lines are related to a pipeline, the pipeline's control logic will naturally ignore invalid data.

More generally speaking, the opportunity to not reset nor initialize a register is easily recognized when there's an accompanying flag or state that indicates its validity, or when there's a clear sequence of first assigning the register a value and then consuming it. In short, when it's easy to tell that the register's value is ignored until it has been assigned a proper value.

Option #2: FPGA's initial values

The basic synchronous elements in an FPGA — commonly flip-flops, shift registers and memories — have their initial value given in the configuration bitstream. The well-known use of this feature is to create a ROM by assigning a block RAM with initial values and never write to it.

Another well-known aspect of this feature is that an FPGA typically wakes up from configuration with apparently all registers having the value zero. This is because the synthesizer usually assigns all registers with zero as their initial value, but there can be surprises unless the initial value is set explicitly.

Some synchronous elements, in particular shift registers and dedicated RAM elements, can be inferred by describing their behavior in Verilog or VHDL: The synthesizer is likely to create a shift register where it finds a delay line, and a RAM element for an array. However if a reset is used on these registers, synchronous or asynchronous, the synthesizer is prevented from saving logic this way, because neither shift registers nor RAMs have a reset input signal that sets the values of the internal memory.

So how does this work? During the configuration process, all synchronous elements are given their initial values just before the FPGA is about to become active, i.e. before the synchronous elements start responding to their clocks and asynchronous reset inputs. For Xilinx devices, this is implemented by virtue of the Global Set Reset (GSR) signal, which puts all synchronous elements in their initial state, followed by the assertion of the Global Write Enable (GWE), which makes the synchronous elements operate normally.

Since the configuration process is carried out regardless of any of the clocks used by the FPGA's application logic, the FPGA's transition into its operational state is asynchronous to any of these clocks. Consequently, the sequential elements behave exactly as if an asynchronous reset was deasserted regardless to any clock. In other words, it's possible that some synchronous elements respond to the first clock edge that follows the transition to operational state, while other elements miss it due to a timing violation. The implications of this were discussed in the first page in this series.

It's important to note that the clocks aren't necessarily stable when the FPGA wakes up. If they are generated by the FPGA's own PLLs, they may violate their timing constraints wildly. As discussed above, this is not an issue if the clock is guaranteed to be ignored until stable (e.g. by virtue of a clock enable), or if it's known to be stable when the FPGA wakes up. Also, if the arrangement of initial value is such that no synchronous element is supposed to change state until the clock is stable, it's fine. Otherwise, setting an initial value doesn't guarantee much.

And yet in several situations, setting the initial value is good enough, and an explicit reset signal isn't required. And in some cases, a reset signal isn't available, for example in the piece of logic that creates the FPGA's reset signals after wakeup. An example of such logic is shown on the third page of this series.

With most synthesizers, setting a register's initial value is quite simple: Use the Verilog "initial" keyword:

reg [15:0] counter;
initial counter = 1000;

It may come as a surprise that "initial" can be used in Verilog code for synthesis, but as it turns out, this usage is widely supported, so it's definitely the preferred method if the synthesizer supports it (as in written explicitly in its documentation). Besides, the alternative method tends to be vendor-specific, and sometimes even device family specific. So even if "initial" isn't guaranteed to be portable, it's probably still the most portable way.

The alternative method for setting the initial value depends on the targeted FPGA. Often it's to instantiate the synchronous element as a primitive, and assign the initial value as an instantiation parameter. For example, a Xilinx' flip-flop:

FDCE myflipflop (
  .C(clk),
  .D(in),
  .Q(out),
  .CLR(1'b0),
  .CE(1'b1)
);

defparam myflipflop.INIT = 1;

Using "initial" is nicer, isn't it?

Option #3: Asynchronous reset

If you haven't read the page on why asynchronous resets are usually used wrongly, I suggest doing that first.

For some reason, a lot of people consider this the catch-all correct way. Maybe because it often appears in code examples, maybe because of the illusion of a simple fix for a global reset that reaches all synchronous elements. Maybe because in the old ASIC world, the asynchronous reset came handy for the chip test in the manufacturing process, as it allows to reset the entire chip and begin applying test vectors.

So to reality: The proper and clean use of an asynchronous reset is with the clocks turned off. That's what the "asynchronous" part really means. In a practical design, this consists of the following sequence:

This sequence isn't difficult to implement, but it might be harder to ensure that the first edge of each clock is properly formed, so there are no glitches: A common issue with clock buffers is that there's a timing requirement between the assertion of the clock enable signal and the clock that is gated. If this timing requirement is violated, the clock buffer may output a glitch (a short pulse that violates the FPGA's clock requirements), resulting in unpredictable behavior of all synchronous elements that are clocked by it.

Unfortunately, the documentation offered by FPGA vendors isn't always clear on how to ensure this timing requirement, making it difficult to implement the sequence shown above as a reliable means for applying an asynchronous reset.

There's an alternative and commonly suggested method for applying an asynchronous reset fairly reliably, which doesn't involve clock gating: To add a few flip-flops which pass through the assertion of the reset signal directly, but deassert the reset synchronously. In other words, a synchronized asynchronous reset.

For example, given an original reset input @external_resetn and the clock @clk to synchronize to:

   reg pre_rstn1, pre_rstn2;
   reg resetn;

   always @(posedge clk or negedge external_resetn)
     if (!external_resetn)
       begin
         resetn <= 0;
         pre_rstn2 <= 0;
         pre_rstn1 <= 0;
       end
     else
       begin
         resetn <= pre_rstn2;
         pre_rstn2 <= pre_rstn1;
         pre_rstn1 <= 1;
       end

When @external_resetn is asserted, all three registers become zero (i.e. asserted as well) asynchronously. However when @external_resetn is deasserted, only @pre_rstn1 becomes deasserted on the next clock edge, and this propagates to @pre_rstn2 and @resetn on the following clocks.

Almost needless to say, each clock needs its own synchronized asynchronous reset.

Timing violations between the deassertion of @external_resetn and @clk may result in an metastable condition on @pre_rstn1, and the two extra registers are there to ensure a clean deassertion of @resetn nevertheless.

It's important to note that even though @resetn, as generated above, is synchronous with @clk, using it as an asynchronous reset doesn't by itself necessarily ensure a safe deassertion of the reset. This is only the case if the timing constraints are enforced on asynchronous reset paths, which is usually not the tools' default.

Hence if @resetn is used as in

  always @(posedge clk or negedge resetn)
    if (!resetn) // Are you sure this path is timed?
      the_register <= 0;
    else
      [ ... ]

the synchronizer above is not enough to ensure a reliable recovery from reset. It's your responsibility to verify that the paths starting at @resetn and end at the flip-flops' asynchronous reset inputs are indeed timed.

As a plain synchronous reset, i.e. when used like

  always @(posedge clk) // @resetn not in sensitivity list!
    if (!resetn)
      the_register <= 0;
    else
      [ ... ]

it's fairly OK to use @resetn, as its deassertion is surely constrained. The asynchronous assertion of @resetn can however result in random outputs from the relevant synchronous elements, so it's best to fully synchronize a reset that is intended as a synchronous one.

It's also important to note that this synchronizer doesn't help against a glitchy @external_resetn: A short assertion pulse may very well result in a @resetn signal that violates timing. The only way to ensure a clean output reset signal is to synchronize it completely with something like:

   reg pre_rstn;
   reg resetn;

   always @(posedge clk)
     begin
       resetn <= pre_rstn;
       pre_rstn <= external_resetn;
     end

but this makes the reset fully synchronous. Hence the synchronizer ignores the reset altogether if @clk doesn't toggle, which is problematic if the asynchronous reset is expected to work as such — that is, even without clocks toggling.

I should mention that I've used active-low resets in the examples above, mainly because of a tradition that stems from the days when the reset signal was generated with a capacitor that was charged by the power supply voltage through a resistor. As the capacitor had no voltage initially, the reset input read as logic '0', and as it got charged, it switched to '1'. This ancient type of power-up reset is the reason many resets are active low to this day.

In conclusion, it is possible to use an asynchronous reset reliably, however achieving this is definitely not as simple as many believe.

Option #4: Synchronous reset

The synchronous reset is most known with the following code pattern:

  always @(posedge clk)
    if (reset)
      the_register <= 0;
    else
      [ ... ]

I'll suggest what I consider a better code pattern further on, but for now we'll stick with this one. Regardless, note that I chose the active-high reset form, as this is the more common choice with synchronous resets. Or so is my impression.

A synchronous reset is better than the asynchronous reset in almost all aspects, except for these:

Since FPGAs are rarely used in a no-clock scenario (unlike ASICs that traditionally need this for testing), and the dedicated routing resource issue is somewhat vague, I'll focus on the main topic: Fan-out. Which is easy to solve.

It's also worth mentioning that the same fan-out problem strikes the asynchronous reset just the same if its deassertion is synchronized and timing constrained, as it often needs to be. So the only ones that can truly say that fan-out is a disadvantage of the synchronous reset are those who use the asynchronous reset with the clocks off (i.e. gated).

Attempting to solve the fan-out problem with a synthesizer constraint or attribute to limit the fan-out is the less preferred way, because the synthesizer just duplicates the flip-flop when the limit is reached. Therefore, it often happens that the output of a duplicated flip-flops go to modules with completely different purposes, hence physically placed far away on the FPGA, which results in long routing and a significant propagation delay.

A simple and efficient solution is to create a local reset for each significant piece of logic. Something like

module medium_sized_module (
  input clk,
  input reset,
  input [15:0] in_data
  output [15:0] out_data
);

  (* dont_touch = "true" *) reg local_reset;
  reg the_register;

  always @(posedge clk)
    local_reset <= reset;

  always (@posedge clk)
    if (local_reset)
      the_register <= 0;
    else
      [ ... ]

The whole story is that @local_reset is a local copy of @reset (delayed by one clock). Using @local_reset instead of @reset from this module and downwards holds the fan-out at a reasonable level. As the consumers of this local reset are expected to be interconnected tightly anyhow, odds are that they will be placed in a certain region of the FPGA, hence the local reset won't need to travel long distances across the logic fabric.

It's important to prevent the synthesizer from optimizing away the local reset registers, something that it usually does when there are registers with identical logic behavior, even if they belong to different modules. In the example above, the synthesis "dont_touch" attribute for Vivado is shown. Each synthesizer has its own way to request this (for Intel FPGAs, the same is achieved with the "dont_merge" synthesis attribute).

To verify that the synthesizer indeed kept all registers, it's useful to give all these registers the same name (e.g. local_reset as suggested above) and then search for registers with this name in the implemented design.

There's of course no need to create a local reset for each and every module. As a ballpark figure, a fan-out of 50-100 is reasonable for a local reset, in particular when it reaches logic elements within a small physical region on the FPGA.

More on synchronous resets

A common myth about synchronous resets is that if the synthesizer encounters a Verilog code pattern that matches that of a synchronous reset, it will connect the reset signal to the flip-flop's synchronous reset input. This can be the case, but it will often not be.

This is different from an asynchronous reset, which must be connected to the flip-flop's asynchronous reset input, or else it won't work without a clock.

Synthesizers tend to give no special meaning to the coding pattern, but rather calculate the logic equation as implied by the Verilog code. Consider this example:

  always @(posedge clk)
    if (reset)
      the_register <= 0;
    else if (some_condition)
      the_register <= !the_register;
    else if (some_other_condition)
      the_register <= 0;

One way to read this snippet is that the always statement begins with a standard code pattern that implies a synchronous reset, and then comes a specific definition for the register's behavior. Consequently, one could have expected @reset to be connected to the synchronous reset input of the relevant flip-flop, and the output of some logic function (implemented as a LUT) to the flip-flop's data input.

In reality, synthesizers usually implement the next clock's value of @the_register as concisely as possible. For example, the flip-flops's reset input could be connected to a logic function (i.e. a LUT) that implements the expression (reset || (some_other_condition && !some_condition) ). Likewise, the flip-flop's reset might not be used at all, but instead only the data input is used, and the logic function uses the @reset signal as one of its inputs. So if @reset is asserted, the logic function's value is zero. This way @reset indeed brings @the_register to zero, but it's not treated differently from any other signal.

So to reiterate: Even though the flip-flop has a synchronous reset input, synthesizers tend not to treat the synchronous reset code pattern specially, and neither treat the reset signal any different from any other. The flip-flop's reset input is used in the best way to implement the behavior required by the Verilog code. That can sometimes mean to connect it directly to the reset signal, sometimes to some logic function that may involve the reset signal, and sometimes not use it at all. Whatever meets the synthesizer's performance goals better, nothing else.

Xilinx' Vivado users can use the DIRECT_RESET and EXTRACT_RESET synthesis attributes to get more control on this issue.

I'll wrap this up with another disadvantage of asynchronous resets: In the common implementation of a flip-flop on FPGAs, it only has one reset/set input, which can be programmed to behave synchronously or asynchronously. If the reset is synchronous, the synthesizer might find tricks to use it for saving LUTs in order to fulfill the requested behavior. This can't be done when the reset is asynchronous, of course. So an asynchronous reset ties the hands of the synthesizer, forcing it to waste more logic resources.

Avoiding accidental register freeze

There's a pitfall with the commonly used code patterns for implementing resets, as shown in this code example:

   always @(posedge clk or negedge resetn)
     if (!resetn)
       begin
         reg1 <= 0;
         reg2 <= 0;
         // Ayeee! Forgot to reset reg3 !
       end
     else
       begin
         reg1 <= [ ... ];
         reg2 <= [ ... ];
         reg3 <= [ ... ];
       end

As implied by the comment, @reg3 doesn't appear in the begin-end clause for active @resetn. As a result, the Verilog code above requires that @reg3 won't change value as long as @resetn is asserted. Effectively, it's the same as if @reg3 would be defined with

   always @(posedge clk)
     if (resetn)
       reg3 <= [ ... ];

or in other words, @resetn functions as a clock enable for @reg3: The clock is effective only when it's high (i.e. deasserted as a reset).

Exactly the same happens with synchronous resets:

   always @(posedge clk)
     if (reset)
       begin
         reg1 <= 0;
         reg2 <= 0;
         // Ayeee! Forgot to reset reg3 !
       end
     else
       begin
         reg1 <= [ ... ];
         reg2 <= [ ... ];
         reg3 <= [ ... ];
       end

This is actually easier to understand, as this is just a pair of begin-end clauses, with the second coming to effect only when @reset is deasserted. So the definition of @reg3 for this example is clearly

   always @(posedge clk)
     if (!reset)
       reg3 <= [ ... ];

So the obvious (and not necessarily clever) conclusion is not to forget any register in the reset's begin-end clause. In fact, many FPGA designers reset all registers, whether needed or not, because they believe that's the only way to do it. Or alternatively, they adopt a coding style where each register has its own "always" statement.

But what if you intentionally want to reset some registers and not others?

If the reset is asynchronous, there's no choice but to put those registers in a separate "always" statement. But with a synchronous reset, there's a simple way to work this out:

   always @(posedge clk)
     begin
       reg1 <= [ ... ];
       reg2 <= [ ... ];
       reg3 <= [ ... ];

       if (reset)
         begin
           reg1 <= 0;
           reg2 <= 0;
           // I don't want to reset reg3, and that's fine!
         end
     end

Instead of an "if (reset)" sentence at the beginning, and having the interesting stuff under the "else" statement, the "if (reset)" is put last, so the reset assignments override everything that came before them.

Note that this is not equivalent to any of the examples above: @reg1 and @reg2 are synchronously reset when @reset is asserted, however @reg3 is not influenced by the reset at all.

If you feel uncomfortable with this alternative way to apply a synchronous reset, I can understand that, and there are a few reasons for it: To begin with, it's generally good practice to stick to commonly used coding patterns in FPGA design, or the synthesizer might expose an exotic bug, something that is much less likely to happen with well-established code patterns (as in Golden Rule #4). So even though the overriding assignments as shown above are explicitly required to work by the Verilog standard, one could argue that it's not necessarily a good idea to rely on this feature.

This is a strong argument, but for what it's worth, I'm here to tell you that I've been using overriding assignments heavily for more than a decade, with a pretty large range of synthesizers. In particular, this is how I define synchronous resets in my own code. I have never had a single problem with this.

Another possible reason for unease is to think that the synthesizer might miss the hint that a synchronous reset is desired, when the alternative code pattern is used. However as already mentioned above, most synthesizers don't take the hint anyway, and consider the synchronous reset and yet another definition of the logic's required behavior. So this reason has no grounds.

So if you want to take my word for it that it's safe, you'll save yourself some headache.

Can the same be done with an asynchronous reset? For example, what will this do?

    always @(posedge clk or negedge resetn)
      begin
        reg1 <= [ ... ];
        reg2 <= [ ... ];
        
        if (!resetn)
          reg1 <= 0;
      end

This is of course a diversion from the asynchronous reset's common coding pattern. An anecdotal test on Vivado's synthesizer revealed this it got the hint, and assigned an asynchronous reset for @reg1.

But the behavior that is defined for @reg2 is not synthesizable for an FPGA: As written above, it means that both @clk and @resetn are clocks, and that @reg2 samples a new value on their rising and falling edges, respectively. Since flip-flops with dual clock inputs are not present in any FPGA I know of, there's no direct possibility to synthesize anything sane from @reg2's definition.

Vivado's synthesizer reacted to this by ignoring the requirement to clock @reg2 with negative edges of @resetn, and created a flip-flop that is clocked by @clk only. There were no traces of this oddity in the synthesized result, and neither did the synthesizer issue any warning or otherwise complain. That despite the fact that the synthesizer created logic that doesn't behave as defined by the Verilog code.

So specifically with Vivado's synthesizer, the same reset-by-override patterns actually works even for an asynchronous reset, but this shouldn't be relied upon: The Verilog code should say what you want the logic to do, or the synthesizer is perfectly entitled to misinterpret it at will.

This concludes the second page in this series on resets. The next page goes through different aspects of starting up the FPGA after powerup and external reset.

Copyright © 2021-2022. All rights reserved. (42e6e8c4)