VHDL · Chapter 3.2 · Signals & Hardware Behavior
Signal Assignment in VHDL
Signal assignment looks like storing a value, but it is really scheduling one. Assigning a signal projects a transaction onto that signal's driver, and the signal only takes the new value after a delta delay, or after an explicit delay if you add one. Two consequences follow that trip up newcomers and explain a great deal of real RTL. Inside a process, if you assign the same signal twice, the last assignment wins, and a concurrent assignment outside a process is simply a driver that is always re-evaluated. This lesson builds the driver-and-schedule model, contrasts signal assignment with the immediate update of a variable or constant, and shows how last-assignment-wins, default assignments, and multiple drivers all fall out of one idea.
Foundation15 min readVHDLSignal AssignmentDriversDelta Cyclenumeric_stdRTL
1. Intuition — assignment projects a transaction onto a driver
A signal does not hold a value the way a variable does. Behind every signal is a driver, and
s <= value places a transaction — "become this value at this (future) time" — onto that
driver. With no explicit delay the time is the next delta cycle; with after t (lesson
2.13) it is t later. The signal's actual value is whatever its driver projects once that time
arrives.
s <= a; -- schedule s := a for the next delta cycle
s <= a after 2 ns; -- schedule s := a for 2 ns from now (simulation modelling)Holding "assignment = schedule a transaction on a driver" in mind is what makes the rest of this lesson — and multiple drivers, and the delta model — coherent rather than a list of special cases.
2. Inside a process — last assignment wins
A process executes top to bottom, but signal updates are not applied until it suspends. So if a process assigns the same signal more than once, every assignment targets the same delta update, and the last one executed overwrites the earlier ones. Only the final value is ever scheduled:
process (sel, a, b)
begin
y <= a; -- scheduled...
if sel = '1' then
y <= b; -- ...overwritten: if sel='1', the final scheduled value is b
end if;
end process;
-- Net effect: y = b when sel='1', else y = a. The first 'y <= a' acts as a DEFAULT.This is not a bug — it is the single most useful idiom in combinational VHDL: assign a default
first, then override conditionally. Because the default always runs, every path assigns y, which
(as a later lesson details) is exactly how you avoid an unintended latch.
3. The driver and the delta update, drawn
4. The update over time — and last-wins on the waveform
The delta update means a signal assigned in a process changes after the triggering event, not during it, and only the final assignment of the step is what you see:
Default-then-override: y is assigned twice; only the last (sel-dependent) value appears
8 cycles5. Concurrent assignment — a driver that is always live
Outside a process, a concurrent signal assignment is a driver that re-evaluates whenever any input changes — a continuously-active piece of combinational hardware:
-- These run continuously and concurrently; order between them does not matter.
sum <= std_logic_vector(unsigned(a) + unsigned(b)); -- numeric_std arithmetic
y <= a when sel = '1' else b; -- conditional driver (a mux)
parity <= xor a; -- reduction (VHDL-2008)Each line is its own driver on its own signal. There is no top-to-bottom execution between them: they all evaluate in parallel, exactly like the gates they describe. (Assigning the same signal from two concurrent statements creates two drivers — see Section 6.)
6. Debugging example — two drivers on one signal
Last-assignment-wins applies within one process. Assign the same signal from two places (two processes, or two concurrent statements) and you create two drivers, which do not overwrite — they are resolved (lesson 2.5):
-- Two concurrent drivers on bus_o:
bus_o <= x"AA"; -- driver 1
bus_o <= data when en = '1' else (others => 'Z'); -- driver 2
-- With std_logic, the resolution function combines them: driver 1 forces AA while
-- driver 2 drives data → the two FIGHT and you get 'X' on the conflicting bits.
-- With std_ulogic (unresolved), the second driver is an elaboration ERROR.The symptom is 'X' on a bus you "only assigned once" — but you assigned it from two drivers.
The fix is to ensure a signal has a single driver unless you intend a resolved multi-driver bus
(tristate), in which case exactly one driver should be active ('Z' elsewhere) at any time. This
is why last-assignment-wins (one driver, intentional override) and resolution (multiple drivers,
combined) are different mechanisms you must not confuse.
7. Common mistakes & what to watch for
- Expecting intermediate in-process assignments to take effect. Only the last assignment to a signal in a process step is scheduled; use a variable if you need each step's value.
- Confusing
<=and:=.<=schedules a signal;:=updates a variable/constant immediately. They are not interchangeable. - Creating accidental multiple drivers. Assigning one signal from two processes/concurrent
statements builds two drivers that resolve (to
'X'on conflict), not overwrite. - Forgetting the default assignment. In a combinational process, skipping the default-first idiom leaves some path unassigned and infers a latch.
- Using
afterto create real timing. In synthesizable logicafteris ignored (lesson 2.13); timing comes from clocked registers, not assignment delays.
8. Engineering insight
One model — assignment projects a transaction onto a driver, applied at the delta cycle — explains the behaviours that otherwise look like unrelated rules. Last-assignment-wins is one driver receiving several writes before it updates. The default-then-override idiom is that same behaviour put to work to guarantee full assignment. Concurrent statements are drivers that re-evaluate continuously. Multiple drivers are several drivers on one net, resolved by strength. Once you see signal assignment as scheduling onto drivers rather than storing values, RTL behaviour — combinational vs registered, single vs multi-driver, immediate vs delayed — reads as one consistent system.
9. Summary & next step
Signal assignment (<=) schedules a transaction onto a signal's driver, applied after a delta
delay. Inside a process the last assignment to a signal wins, which powers the default-then-override
idiom; outside a process, concurrent assignments are always-live drivers. Assigning one signal
from two places creates multiple drivers that resolve (not overwrite), and := (variables) is a
separate, immediate mechanism.
You can now reason about how a signal takes its value. The module continues by pinning down the remaining signal mechanics — declaring signals and their scope, then the delta cycle and multiple drivers in full — building toward processes and the combinational and sequential logic they describe.