Skip to content

VHDL · Chapter 15.4 · Debugging and Simulation

Delta-Cycle and Race Bugs

The nastiest simulation bugs hide inside one moment of time. At a single instant, signals settle over successive delta cycles, which are zero-time steps within that instant. Two failure modes live there. A delta-read-too-early bug reads a signal before its combinational chain has finished settling across deltas, getting a stale value. A race happens when a clock and the data it should capture change at the same time, so which the simulator processes first becomes order-dependent. The classic trigger is a clock derived through combinational logic, such as a gated or divided clock, that arrives one delta late and races or misses the data. The tell-tale sign is a result that depends on process order when it should not. The fixes are familiar design rules: clock enables instead of gated clocks, registering across clock domains, and preferring a single clock. This lesson covers diagnosing these bugs and removing them.

Foundation14 min readVHDLDebuggingDelta CycleRaceGated ClockSimulation

1. Engineering intuition — when "the same time" hides an order

Simulated time can stand still while the design settles — those are delta cycles. Most of the time you can ignore them, but they bite when two things happen at the same T and your logic secretly depends on which goes first. The archetype: you build a clock out of combinational logic (gate it, divide it, route it through a mux) and use it to capture data that changes on the original clock edge. The derived clock comes out one delta later than the data's edge, so in simulation it arrives just behind — racing the data and capturing the wrong value, or none. The symptom is unnerving: the answer changes if the simulator happens to evaluate processes in a different order. Real synchronous design avoids this entirely by never making clocks in logic.

2. Formal explanation — delta reads and the derived-clock race

delta_race.vhd
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
-- DERIVED CLOCK via logic → arrives ONE DELTA after the real edge → races the data it samples.
clk_div <= not clk_div when rising_edge(clk);        -- a divided "clock" (a SIGNAL, updated a delta late)
-- ...used as a clock elsewhere:
process (clk_div) begin
  if rising_edge(clk_div) then q <= d; end if;       -- clk_div edge lags clk by a delta → races 'd'
end process;
-- 'd' may change on the SAME T (driven off clk); whether q captures old or new d is ORDER-DEPENDENT.
 
-- DELTA-READ-TOO-EARLY: reading a signal before its combinational chain settles.
a <= b;   b <= c;     -- when c changes: b updates (delta 1), THEN a (delta 2)
-- a process reading 'a' in the same first delta sees its OLD value — settled only after deltas.
 
-- DIAGNOSIS: many delta cycles at one time T, and a result that DEPENDS ON PROCESS ORDER
--   (a correct design must NOT depend on which process the simulator runs first within a delta).

A derived clock (made in logic) updates a delta after the source edge, so it races same-time data. A delta-read bug reads a signal before its chain settles. The signature of both is order dependence within a single T — which a correct design must never have.

3. Production usage — the structural fixes

delta_race_fixes.vhd
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
-- FIX 1: never gate/divide a clock in logic — use a CLOCK ENABLE on the real clock (7.5).
process (clk) begin
  if rising_edge(clk) then
    if tick_en = '1' then q <= d; end if;            -- "half-rate" behavior, ONE clock, no derived edge
  end if;
end process;
-- tick_en is a normal signal pulsed by a counter — no second clock, no delta race.
 
-- FIX 2: cross clock domains by REGISTERING (synchronizing), never by sampling a logic-made clock.
--   (proper CDC synchronizer — Module 17 — not a derived clock.)
 
-- FIX 3: keep the design on a SINGLE clock wherever possible; real clocks come from clock resources,
--   not combinational logic (gated/divided clocks belong to clock-management hardware, not RTL fabric).

What hardware does this become? The clock-enable version is one clock feeding flip-flops with an en — clean, race-free, and exactly what synthesis wants. The derived-clock version, even where it synthesizes, creates a second clock domain through the logic fabric with skew and timing-closure problems — the simulation delta race is the early warning of a real hardware hazard. So fixing the delta/race bug (enables, single clock, proper CDC) removes both the simulation order-dependence and the physical clocking problem it predicts.

4. Structural interpretation — a derived clock racing the data

real clock and a logic-derived clock racing to capture data that changes on the real edgegate/divideracesracesreal clkdata changes on this edgederived clk (logic)updates ONE DELTA laterdata ddriven off real clkcapture registerold or new d?order-dependent12
A delta race from a clock built in logic. The real clock drives the data register, so data changes on the clock edge; a derived clock (gated or divided in the fabric) is a signal that updates one delta after that edge. A second register uses the derived clock to capture the data — but the derived edge arrives a delta behind, racing the data that changed at the same time, so whether it captures the old or new value depends on process order. The fix replaces the derived clock with a clock enable on the single real clock. This is a clocking-race structure; the waveform below shows the derived clock arriving a delta late.

5. Simulation interpretation — the derived clock one delta late

Derived clock lags the real edge by a delta and races the data

8 cycles
Derived clock lags the real edge by a delta and races the datareal edge: d updates to B (this T)real edge: d updates t…clk_div edge arrives a delta/cycle LATE → captures the value around its own edgeclk_div edge arrives a…q is order-dependent: did it catch d before or after it changed? (the race)q is order-dependent: …clkdABBCCDDEclk_divq00AAAABBt0t1t2t3t4t5t6t7
The derived clock clk_div is generated in logic, so its edges arrive after the real clk edges that change d — at the same simulated time the data moves, but a delta behind. The capture register q therefore races d: whether it samples the old or new value depends on evaluation order, which is exactly the non-deterministic delta-race bug. Replacing clk_div with a clock enable on clk removes the second edge and the race.

6. Debugging example — the order-dependent result

Expected: a deterministic design that behaves the same on any simulator. Observed: results change between simulators (or simulator versions), or after an unrelated edit — and the waveform shows many delta cycles at one time with a value that flips depending on process order. Root cause: the design depends on process evaluation order within a delta — almost always because a clock was made in combinational logic (gated or divided) and used to sample data that moves on the same edge, creating a delta race; or a signal was read before its chain settled. Fix: remove derived clocks — use a clock enable on the single real clock, register/synchronize across domains, and keep clocks coming from clock resources, not fabric logic; for delta reads, restructure so the value is stable when read (or use a variable). Engineering takeaway: a correct design never depends on intra-delta process order — if a result does, you have a race, usually a logic-made clock; replace it with an enable on one real clock.

enable_not_derived_clock.vhd
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
-- BUG: clock made in logic → delta-races the data it samples; order-dependent.
-- clk_div <= not clk_div when rising_edge(clk);
-- process (clk_div) begin if rising_edge(clk_div) then q <= d; end if; end process;
-- FIX: one clock + a clock enable — no derived edge, no race.
process (clk) begin if rising_edge(clk) then if tick_en='1' then q <= d; end if; end if; end process;

7. Common mistakes & what to watch for

  • Clocks made in logic. Gated/divided/muxed clocks arrive a delta late and race data; use clock enables on one real clock instead.
  • Order-dependent results. If the answer depends on intra-delta process order, it is a race — a correct design never does.
  • Sampling across domains with a logic clock. Cross domains by registering/synchronizing (CDC), never by a derived clock.
  • Reading a signal before it settles. Combinational chains settle over deltas; read stable values or use a variable for immediate results.
  • Blaming the simulator. Different delta-order outcomes mean your design has a race, not that the simulator is wrong.

8. Engineering insight & continuity

Delta-cycle and race bugs live inside a single instant: a clock derived in logic arrives a delta late and races the data it should capture, and the tell-tale is a result that depends on process order — which a correct design must never have. The fixes are structural and familiar: clock enables instead of gated/divided clocks, registering across domains, and a single clock from real clock resources. These bugs often only appear in simulation, foreshadowing the broader and more dangerous category where simulation and hardware disagree — the subject of the next lesson, Simulation vs Synthesis Mismatches.