VHDL · Chapter 3.5 · Signals & Hardware Behavior
Drivers and the Driver Model
A signal is not a variable that holds a value; it is a net whose value is produced by a driver. Every process or concurrent statement that assigns a signal creates exactly one driver for it, and a driver is more than a current value: it holds a projected waveform, the queue of future transactions the signal is scheduled to take. The delta cycle reads that driver to update the signal. This lesson makes the driver concrete, showing how one source means one driver means a plain wire, how an explicit delay shapes the projected waveform, and why thinking in drivers is the fastest way to debug a signal that simply refuses to change, often because its driving process never re-runs. It is also the direct setup for multiple drivers and resolution.
Foundation15 min readVHDLDriversProjected WaveformSchedulingSensitivity ListRTL
1. Engineering intuition — a signal is sourced, not stored
Think of a net on a schematic: it has no value of its own; its value is whatever the gate output driving it produces. VHDL models exactly that with a driver. When code assigns a signal, it is not writing a memory cell — it is updating the output of the source that drives that net. The signal's value is read from its driver. One thing driving a net means one driver, which is the normal case: a simple wire with a single source.
2. Formal explanation — one source, one driver, a projected waveform
A driver is associated with a (signal, source) pair: each process that assigns a signal, and
each concurrent assignment to it, contributes one driver. A driver does not hold just a value —
it holds a projected waveform: an ordered queue of transactions, each a (value, time) pair the
signal is scheduled to take. A plain s <= x schedules one transaction one delta ahead; s <= x after t (lesson 2.13) schedules it t later; several timed transactions build a multi-element
projected waveform.
-- One process assigning 's' => exactly ONE driver for 's'.
s <= '1'; -- driver's projected waveform: { ('1', now+delta) }
s <= '0' after 10 ns; -- driver schedules a future transaction: { ('0', now+10ns) }
s <= '1', '0' after 5 ns, '1' after 12 ns; -- a multi-transaction projected waveform
-- The signal becomes each value as real time reaches that transaction.For a single-driver signal, the signal's value is simply its driver's current projected value. (Two drivers need a resolution function to combine them — the next lesson.)
3. Production-quality RTL — the driver behind clocked logic
A registered output is one driver (the clocked process) whose projected waveform gets a new transaction each clock edge:
signal count : unsigned(7 downto 0) := (others => '0'); -- one driver: this process
process (clk)
begin
if rising_edge(clk) then
count <= count + 1; -- each edge schedules ONE new transaction onto count's driver
end if;
end process;What hardware does this become? An 8-bit register: the single driver is the register's output,
and each clock edge updates the projected value (numeric_std increment, lesson 2.8). Because
there is exactly one driver, count is an ordinary registered net — no contention, no resolution.
4. Hardware interpretation — a driver is a source on a net
5. Simulation interpretation — the projected waveform becomes the signal
The driver's projected waveform is what the delta cycle (lesson 3.4) consults: when real time reaches a transaction's time, the engine applies that value to the signal and wakes its fanout. A multi-transaction assignment is visible as the signal stepping through the queued values:
A driver's projected waveform played back: s <= '1', '0' after 5 ns, '1' after 12 ns
7 cycles6. Debugging example — the signal that never moves
Expected: an output tracks an input combinationally. Observed: the output is frozen at its
initial value even though the input clearly changes on the waveform. Root cause: the driving
process never re-executes, so its driver's projected waveform never receives a new transaction —
the input is missing from the sensitivity list, so the process does not wake when the input
changes. Fix: add the input to the sensitivity list (or use VHDL-2008 process(all)).
Engineering takeaway: "a signal won't change" is almost always "its driver got no new
transaction" — check what is supposed to wake the source, not the signal itself.
-- WRONG: process only wakes on 'a', so 'b' changes never reach y's driver.
process (a)
begin
y <= a and b; -- y's driver updates only when 'a' changes; 'b' edges are ignored
end process;
-- RIGHT: wake on every read signal so the driver is re-evaluated correctly.
process (a, b) -- or: process(all) -- VHDL-2008
begin
y <= a and b;
end process;(In synthesis this same omission causes a simulation-vs-synthesis mismatch: the synthesiser builds
the full AND gate from the logic, while RTL simulation — driven only on a — disagrees.)
7. Common mistakes & what to watch for
- Thinking a signal has a value independent of a driver. It does not; with no driver it stays at its initial value forever. The value is always sourced from a driver.
- Expecting a stalled signal to be the signal's fault. It is the driver's — the source process did not run (sensitivity list) or scheduled nothing new.
- Assuming
afterreplaces the whole queue. Inertial/transport rules (lesson 3.7) govern how a new transaction interacts with pending ones; it is not always a clean overwrite. - Creating a second driver by accident. Assigning one signal from two processes/concurrent statements makes two drivers — resolution, not overwrite (next lesson).
- Confusing the driver with the signal in debug. Probe what schedules the driver (the process and its triggers), not just the net value.
8. Engineering insight
The driver is the bridge between assignment and value: assignment writes transactions into a
driver's projected waveform, and the simulation loop plays that waveform onto the net. This one
abstraction unifies everything in the module — a single driver is a plain wire; after shapes the
driver's queue; the delta cycle reads the driver; two drivers force resolution; a clocked process is
a driver fed one transaction per edge. Debugging gets sharper too: instead of asking "why is this
signal wrong," ask "which driver sourced it, and what transaction did it project, and why" — the
answer is always in the driving process and its triggers.
9. Summary
Every assignment to a signal creates exactly one driver, and a driver holds a projected waveform —
an ordered queue of future transactions. The signal's value is read from its driver; with a single
source it is a plain wire. after adds timed transactions to the projected waveform, and the delta
cycle applies the driver's value to the signal and wakes its fanout. A signal that will not change is
a driver that received no new transaction — usually a sensitivity-list omission.
10. Learning continuity
You have now built the full single-driver picture: declaration places the net (3.3), the driver
sources its value via a projected waveform (this lesson), and the delta cycle applies it (3.4). The
natural next step is what happens when a net has more than one source. The next lesson,
Multiple Drivers and Contention, shows how two drivers on one signal are combined by a
resolution function — the mechanism behind std_logic's 'X' on conflict and the basis of
tristate buses — closing the loop back to resolved types from Chapter 2.