Digital Design / Module 4: Sequential logic
23. Synchronous and asynchronous resets
Choose a reset style and defend it.
See it move
The idea
Flops power up with unknown values, so a reset brings a design to a known state. There are two styles.
// Synchronous: acts only at a clock edge
always_ff @(posedge clk)
if (rst) q <= 1'b0;
else q <= d;
// Asynchronous: acts immediately
always_ff @(posedge clk or negedge rst_n)
if (!rst_n) q <= 1'b0;
else q <= d;Comparing them
| Synchronous | Asynchronous | |
|---|---|---|
| Needs a running clock | Yes | No |
| Effect on the data path | Adds logic in front of D | Uses a special flop |
| on reset line | Ignored between edges | Resets the flop |
| Danger | Short pulses can be missed | Release near an edge |
The danger of releasing a reset
Applying an async reset is safe at any time. Releasing it isn't. If reset goes away too close to the clock edge, flops may go , or some flops may leave reset a cycle before others. The checks for this are recovery (release must come far enough before the edge, like setup) and removal (it must come far enough after, like hold).
The standard answer
Assert asynchronously and de-assert synchronously. A reset does this; you can see it in the Reset synchronizers lesson.
always_ff @(posedge clk or negedge arst_n)
if (!arst_n) {r2, r1} <= 2'b00;
else {r2, r1} <= {r1, 1'b1};
assign rst_n = r2;Common mistake
Resetting everything. Data registers in large datapaths often don't need a reset; only the control logic and valid bits do. Skipping reset on them saves area and routing. Be sure that nothing depends on their values before the first valid write, though.
Key ideas
- Sync reset needs a clock edge; async acts immediately.
- Async assert with sync de-assert is the usual safe pattern.
- De-assertion has recovery and removal checks.
Your exercise
Find the bug
This code has one deliberate bug. Read the symptom, then click the line you think is wrong.
The fix
always @(posedge clk or negedge rst_n)
Why it failed
The if (!rst_n) looks asynchronous, but the block runs only at clock edges, so this is a synchronous reset. If the clock is stopped, the reset does nothing. Adding negedge rst_n to the event list makes reset act immediately.
Interview questions
coreWhat are recovery and removal?
The setup-like and hold-like checks for async reset release relative to the clock.
basicWhat is the difference between a synchronous and an asynchronous reset, and which one works when the clock is not running?
A synchronous reset is just logic in front of D, so it only takes effect at an active clock edge. An asynchronous reset acts on the flop directly, as soon as it is asserted, with no clock needed. So only the asynchronous style can force a known state while the clock is stopped or not yet stable.
basicWhy do flops need a reset at all, and what happens in simulation to a toggle flop, q <= ~q, that has none?
Flops power up with unknown values, so a reset puts the design into a known starting state. In simulation, an un-reset flop starts as x, and the inverse of x is x, so the toggle flop stays x forever. Any flop whose next value depends on its own value has this problem if it is not reset.
coreThis flop is meant to have an active-low asynchronous reset. In simulation, when rst_n is released between clock edges, q takes the value of d immediately, without any clock edge. Why?
always @(posedge clk or rst_n) if (!rst_n) q <= 1'b0; else q <= d;
The event list contains rst_n as a level, not negedge rst_n, so the block also runs when rst_n rises. At that moment the reset branch is false, so the else branch runs and loads d with no clock edge, which is not a flop. Writing always @(posedge clk or negedge rst_n) makes the block run only on the clock edge or when reset is asserted.
coreIn this reset synchronizer, arst_n is released between clock edges. After how many rising clock edges does rst_n go high, and how quickly does it go low when arst_n is asserted again?
always @(posedge clk or negedge arst_n)
if (!arst_n) {r2, r1} <= 2'b00;
else {r2, r1} <= {r1, 1'b1};
assign rst_n = r2;rst_n goes high after the second rising edge: at the first edge r1 becomes 1, and at the second r2 copies it. Assertion is immediate, because arst_n clears both flops asynchronously without waiting for a clock. That is the asynchronous-assert, synchronous-release pattern.
coreAsserting an asynchronous reset is safe at any time, but releasing it is not. What goes wrong if the release lands close to a clock edge?
The release has its own timing window: recovery, which is like setup, and removal, which is like hold. If it falls inside that window, a flop may go metastable, or some flops may leave reset on this edge and others on the next one. For a state machine or a one-hot counter, flops leaving reset on different cycles can put the design into a state it was never meant to reach.
coreA synchronous-reset design is reset with a pulse lasting 3 ns, on a 10 ns clock. Sometimes the design resets and sometimes it does not. Why?
A synchronous reset is only seen at a rising clock edge. A 3 ns pulse covers an edge only if it happens to fall over one, so it is caught some of the time and missed otherwise. The reset must be held for at least one full clock period, or longer for safety, or the design should use an asynchronous reset that acts on its own.
advancedIn a large datapath, which registers really need a reset, and what do you gain and risk by leaving the others without one?
Control state needs a reset: state machines, counters that control behaviour, and valid bits that say whether data is meaningful. Pure data registers that are always written before they are used often do not. Skipping their reset saves area and reset routing and can ease timing. The risk is that something reads them before the first valid write, so the valid bits must be reset and must guard every use; in simulation the x on those registers also helps show whether that ever happens.
advancedIn the two-flop reset synchronizer, why is there no metastability concern when reset is asserted, and why does the release need two flops rather than one?
On assertion, both flops are cleared directly through their asynchronous inputs, so their outputs go low regardless of the clock. On release, the first flop's D is a constant 1 but the release itself can land inside its recovery and removal window, so that flop may go metastable. The second flop gives it a full clock cycle to resolve before the clean, edge-aligned release reaches the rest of the design.