VHDL · Chapter 14.3 · Testbench Development
Clock and Reset Generation
Two signals underpin every synchronous testbench: the clock and the reset. A clock is a free-running process that toggles the signal every half period to set the frequency, and you can shape its duty cycle, run multiple clocks, and stop it to end the simulation. A reset is a short sequence: assert it at time zero, hold it for a few cycles so the design under test initializes, then release it, ideally synchronized to a clock edge but not right on the active edge, which avoids recovery and removal issues. Getting these right gives the rest of the testbench a clean, deterministic time base. This lesson covers generating clocks with a given period, duty, and count, sequencing reset assert and release, and stopping the clock to terminate the run.
Foundation14 min readVHDLTestbenchClockResetVerificationSimulation
1. Engineering intuition — a heartbeat and a clean start
A synchronous design needs a heartbeat and a known starting point. The clock is the heartbeat: a signal that flips at a steady rate so every flip-flop has edges to act on — in a testbench you make it by hand, toggling a signal every half period. The reset is the clean start: hold the design in a known state long enough for it to initialize, then let go. The subtlety is how you let go — release reset near a clock edge but not exactly on it, so the DUT's flip-flops see a settled reset before the first real edge. Get the clock period and the reset hold/release right and everything downstream — stimulus, checking — has a solid, repeatable time base.
2. Formal explanation — clock and reset processes
constant TCLK : time := 10 ns; -- 100 MHz period
-- CLOCK: a free-running process, toggling every HALF period (50% duty).
clk_gen : process begin
clk <= '0'; wait for TCLK/2;
clk <= '1'; wait for TCLK/2; -- (or: clk <= not clk; wait for TCLK/2;)
end process;
-- RESET: assert at t=0, hold a few cycles, release away from the active edge.
rst_gen : process begin
rst_n <= '0'; -- assert (active-low) at time zero
wait for 5*TCLK; -- hold for ~5 clocks so the DUT initializes
wait until rising_edge(clk); -- align to a clock edge...
wait for TCLK/4; -- ...then release OFF the edge (avoid recovery issues)
rst_n <= '1'; -- release
wait; -- reset done
end process;A clock is a process that toggles the signal every half period (the constant TCLK sets the frequency;
unequal wait for values give a non-50% duty cycle). A reset process asserts at time zero, holds
for several cycles, then releases synchronized near — but deliberately off — the active clock edge to avoid
removal/recovery problems.
3. Production usage — duty cycle, multiple clocks, and stopping the run
-- NON-50% duty cycle: unequal high/low times.
clk_gen : process begin
clk <= '1'; wait for 6 ns; -- 60% high
clk <= '0'; wait for 4 ns; -- 40% low
end process;
-- MULTIPLE clocks (different frequencies / phase) for multi-domain DUTs.
clkA : process begin clkA_s <= not clkA_s; wait for 5 ns; end process; -- 100 MHz
clkB : process begin clkB_s <= not clkB_s; wait for 7 ns; end process; -- ~71 MHz
-- STOP the clock to end the simulation deterministically.
signal running : boolean := true;
clk_stop : process begin
clk <= '0'; wait for TCLK/2;
clk <= '1'; wait for TCLK/2;
if not running then wait; end if; -- park when the test signals completion
end process;
-- (or simply std.env.stop; from a control process — VHDL-2008)What hardware does this become? None — clock and reset generation are simulation stimulus, not hardware. The DUT's internal clocking/reset are real; the generators here merely supply clk and reset to the harness. Their value is a clean, controllable time base: a precise period and duty, several clocks for multi-domain tests, and a definite way to stop so the run terminates instead of toggling forever. Everything else in the testbench times itself against these two signals.
4. Structural interpretation — clock and reset feeding the DUT
5. Simulation interpretation — clock toggling and reset release
Free-running clock with reset asserted at t=0, released after several cycles
10 cycles6. Debugging example — reset released on the active edge
Expected: the DUT starts cleanly from reset. Observed: the first cycle after reset is unpredictable, or the design occasionally misses reset entirely, with behavior that changes under tiny timing tweaks. Root cause: reset was released exactly on the active clock edge (or asynchronously at an arbitrary time), creating a recovery/removal race so flip-flops saw reset deasserting right as they sampled (Module 8); or reset was not held long enough for the DUT to initialize. Fix: hold reset for several clocks, then release it synchronized near but deliberately off the active edge (e.g. a quarter period after it), so the deassertion is settled before the next sampling edge. Engineering takeaway: never release reset on the active clock edge — hold it long enough and deassert off the edge to avoid recovery races and guarantee a clean start.
-- BUG: releasing reset right on the rising edge → recovery/removal race.
-- wait until rising_edge(clk); rst_n <= '1';
-- FIX: align to the edge, then release a fraction of a period LATER.
wait until rising_edge(clk); wait for TCLK/4; rst_n <= '1';7. Common mistakes & what to watch for
- Releasing reset on the active edge. Deassert off the edge (small skew) to avoid recovery/removal races.
- Reset held too briefly. Hold for several clocks so the DUT fully initializes before stimulus.
- A clock that never stops. Provide a stop (a
runningflag orstd.env.stop) so the simulation terminates. - Wrong half-period math. Period = 2 × (
wait for); set the constant so the frequency is what you intend (and split unevenly for a duty cycle). - Unsynchronized multiple clocks treated as related. Independent clocks drift in phase; for CDC tests model them as genuinely asynchronous.
8. Engineering insight & continuity
Clock and reset generation give a testbench its time base: a free-running clock toggling every half period (with controllable duty and multiple domains) and a reset that asserts at time zero, holds for several cycles, and releases cleanly off the active edge — plus a way to stop the clock and end the run. With a solid clock and a clean reset, stimulus has something to step against and the DUT starts from a known state. The remaining piece is deciding whether the DUT's responses are correct automatically — the subject of the next lesson, Self-Checking Testbenches.