A common question is why STA checks only one edge of the reset. The answer lies in what each edge does to the flop. Assertion forces the output to its reset value without involving the clock, so there is no clock relationship to check. Release hands control back to the clock, and the first edge that follows must be a clean one.
The waveform below is simulation output of a 3-bit counter with an asynchronous active-low reset. One lane slot is one tick of a sampling clock; the clock lane is drawn from the real clock.
How to read it: the clock rises at slots 3, 11, 19, 27, 35, 43 and so on. The reset is released at slot 5, after the first edge, so the counter holds 0 through that edge and starts counting at the next, with 1 at slot 11, 2 at slot 19 and 3 at slot 27. At slot 29 reset falls while the clock is high, between two rising edges, and the counter returns to 0 in the same slot: assertion needs no edge. The reset is released again at slot 45; the counter stays at 0 through the edges at slots 35 and 43, and takes its first count at the edge in slot 51. The simulation uses ideal flops, so it cannot show a recovery violation; it shows the intended behaviour that the timing checks protect.
Reset edge | Effect on the flop | Timing check |
|---|---|---|
Assertion | Output forced to the reset value immediately | None against the clock; minimum pulse width of the reset may apply (see the pulse width topic) |
Release | Flop rejoins normal clocked operation | Recovery and removal against the clock edge |
# A reset released at time r: the flop's first counting edge is the first edge >= r + recovery.
T, rec = 8.0, 0.25
edges = [k * T + 4.0 for k in range(8)] # rising edges at 4, 12, 20, ...
def first_count_edge(release):
return next(e for e in edges if e >= release + rec)
assert first_count_edge(5.0) == 12.0 # released 1 ns after the edge at 4
assert first_count_edge(11.85) == 20.0 # inside the recovery window before 12: the edge is missed
assert first_count_edge(11.75) == 12.0 # released exactly 0.25 ns before: the edge is taken
print("PASS: first counting edges", first_count_edge(5.0), first_count_edge(11.85), first_count_edge(11.75))The last two lines show the sensitivity: moving the release by 0.1 ns changes which edge the flop uses. In silicon, inside the window the result may be either, or metastable, which is why the checks forbid the window.
Slot 35 is after the second assertion at slot 29. The release at slot 45 comes later, so the edges at slots 35 and 43 happen while reset is still asserted and the counter is held at 0.