A common approach to resets in a design is to have one single global asynchronous reset network. In this post, I will argue why this is a bad idea, and why you should in fact do the exact opposite, by implementing a reset strategy that is:
- synchronous - not asynchronous
- local - not global
Furthermore, many developers add a reset to all clocked logic just by habit - this is a bad habit as well. Resets should be added only when needed. I'll start with that point and then move on to the motivations for synchronous and local reset.
Use resets only when you have to
Most clocked resources won't need a reset. For many designs, the majority of FFs will be pipelining or delay FFs. For pipelining FFs, if data is valid on every clock cycle, the reset is needed, but if data validity is indicated by a valid/Write Enable-signal, only that bit needs the reset.
Some other examples of FFs that generally do need a reset are
- FFs within a feedback loop,
- FFs storing the state of a state machine,
- other state-carrying FFs such as S/R FFs and
- IIR filter FFs.
On the other hand, FIR filter FFs are not part of a feedback loop and generally would not need a reset.
The main benefits of getting rid of resets on FFs where it's not needed are
- less logic utilization
- SRL16E's can be used for delay chains fitting 16 FFs within one LUT
- less routing challenge leading to
- less routing run-time
- better timing for surrounding logic
Make resets synchronous - not asynchronous
The problem with asynchronous reset is that the reset falling edge isn't related to the clock and could appear anywhere in relation to the rising clock edge. Due to varying network skews this can lead to different FFs coming out of reset on different clock cycles giving an indeterminate behaviour.
For a large reset network with a huge fan-out we can assume the network skew to be considerable - which further worsens the situation and increases the likelihood of problems.
The situation is illustrated in the timing diagram above. Good news: the cure is straight-forward, make the resets synchronous. Note that just synchronizing the reset signal is not enough - the FFs it is fed to must implement synchronous reset, otherwise the tools will not care about their timing and network skews might still distribute the falling edge of the reset on different sides of the rising clock edge for different FFs.
Make resets local - not global
Even when resets are used as sparingly as possible, and are synchronous when they are indeed used, the reset signal might still be prone to generate timing problems. For large designs, the reset net might still be very large, and distributing the reset over the entire chip within timing limits might still be a challenge. The situation is illustrated in the timing diagram below.
The cure this time is to get rid of that huge global reset net. Instead, distribute a master reset signal to various reset sub-nets, with FFs between the master reset and the subnets. This can equivalently be viewed as pipelining the reset signal (with individual pipeline FFs for each reset subnet).
In my opinion, this should be the standard procedure - not something that is applied only if the tools tell you that there is a timing problem on the reset signal. Even if the design does meet timing with a global reset network, the tools might have had to struggle hard for it without you knowing. This might have
- increased routing runtime,
- increased logic utilization and
- reduced timing performance on surrounding logic
Some other notes on resets
Use the Global Clock Tree to distribute a reset
The Global Clock Trees of the Xilinx FPGA's are used to distribute clocks across the die. These dedicated routing networks are designed for low skews and high fan-outs, so the idea of using them for other signals, such as a global reset, is not far-fetched. These networks are only connected to the clock input of FFs, but since the Virtex 5, there is logic that can route these signals into the interconnect of the CLBs, and the global network could hence drive e.g. the reset input of the FFs (or any other logic).
If it's hard to get the reset signal to meet timing, it might be worth trying this approach. The reset signal is then brought on to a Global Clock Tree by driving the signal to a Global Clock Buffer (BUFG) primitive.
It should be noted that this method is useful for a design with one global reset network - not for designs having used my suggested local reset approach.
VHDL signal initializations
A note about the abilities of FPGAs to initialize FFs (and BRAM) to a given value at configuration. This can be done by initializing a VHDL signal:
This is a useful feature, not at hand in ASICS, and if it is helpful for you, use it. However, still being able to put the FPGA in a known, resetted state without having to configure it, is very useful for testing purposes. Imagine e.g. a situation where yo have a PCIe block on the FPGA, communicating with the host. If the FPGA is re-configured the PCIe block vanishes and the host must be rebooted in order to use the block again (even if the block appears again only a second later). In this case, it is useful to be able to reset the user logic (not the PCIe block) to begin new PCIe transactions with the user logic in a known and determined state.