Skip to content

VHDL · Chapter 3.6 · Signals & Hardware Behavior

Multiple Drivers and Contention

A signal with one driver is a plain wire, but put two sources on the same net and you now have two drivers, so something must decide what the net actually carries. For a resolved type like the standard logic type that decision is made by a resolution function. High-impedance yields to any real driver, strong values beat weak ones, and two conflicting strong values produce an X, which is modelled contention. For an unresolved type, a second driver is simply illegal and is caught before simulation even starts. This lesson shows how multiple drivers become tristate buses, where exactly one source is active at a time, and how to read and debug the X that a driver fight produces.

Foundation15 min readVHDLMultiple DriversResolutionTristatestd_logicContention

1. Engineering intuition — two sources, one wire, a referee

Electrically, tying two outputs to one wire is a question, not a contradiction: if one is driving and the other is released (high-impedance), the wire follows the active one; if both push opposite values hard, they fight and the result is indeterminate. VHDL models exactly this. Each source of a signal is a driver (lesson 3.5), and when there is more than one, a resolution function plays referee — combining the drivers into the single value the net carries.

2. Formal explanation — resolved vs unresolved types

Whether multiple drivers are even allowed depends on the type (lesson 2.5):

  • std_logic is a resolved subtype of std_ulogic: it carries a resolution function, so multiple drivers are legal and combined.
  • std_ulogic is unresolved: a second driver on the same signal is an elaboration error, caught before simulation even starts.

The std_logic resolution combines two drivers roughly as: 'Z' (high-Z) yields to any driver; a strong value ('0'/'1') overrides a weak one ('L'/'H'/'W'); equal values agree; two opposing strong values ('0' vs '1') resolve to 'X'; and 'U' (uninitialised) or 'X' contaminates the result.

resolution_outcomes.vhd
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
-- conceptual outcomes of resolving two std_logic drivers:
--   '1' and 'Z'  -> '1'    (Z yields to the real driver)
--   '0' and 'Z'  -> '0'
--   '1' and '1'  -> '1'    (agreement)
--   '0' and '1'  -> 'X'    (conflict — both drive hard, opposite values)
--   '1' and 'H'  -> '1'    (strong beats weak)
--   'U' and  x   -> 'U'    (uninitialised contaminates)

3. Production-quality RTL — the tristate bus

The intended use of multiple drivers is a tristate bus: several masters share one set of wires, each driving 'Z' (released) except the one currently granted, which drives real data.

tristate_bus.vhd
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
-- two drivers on 'bus_o'; each is high-Z unless its enable is asserted.
bus_o <= drv_a when en_a = '1' else (others => 'Z');   -- driver 1
bus_o <= drv_b when en_b = '1' else (others => 'Z');   -- driver 2
-- Correct protocol: en_a and en_b are NEVER both '1' at once, so exactly one
-- driver is active and the other is 'Z'; resolution then just passes the active value.

What hardware does this become? Two tristate buffers wired to a shared bus. The arbitration that guarantees one enable at a time is the contract that keeps the bus from 'X'. (Modern on-chip designs usually replace tristate buses with muxes; the resolution model still explains the behaviour.)

4. Hardware interpretation — resolution models electrical reality

multiple drivers feeding a resolution function that produces the signal valuecontributescontributescombinesdriver 1e.g. drv_a or 'Z'driver 2e.g. drv_b or 'Z'resolution functionZ yields · strong>weak · 0vs 1 = Xresolved signalthe single value the netcarries12
A net with multiple sources has one driver per source; the resolution function combines them into the net's value. 'Z' (released) yields to any real driver; a strong value overrides a weak pull; agreement passes through; two opposing strong drivers fight and produce 'X'. This mirrors the real electrical outcome: a released output lets another drive the wire, but two outputs forcing opposite values short together to an indeterminate level.

5. Simulation interpretation — when resolution runs

Whenever any driver of a resolved signal changes, the simulator re-runs the resolution function over all of that signal's drivers and applies the combined result — one delta later, exactly like any other signal update.

simulation timeline including the resolution step for a multiply-driven signalEvent wakes adriver's processe.g. enable or data changeThat driver updatesits contribution changesProcess suspendsupdate pendingDelta cycle: resolveall driversresolution functioncombines every driverResolved valueappliedthe net takes the combinedvalueFanout wakesreaders re-evaluate12
The simulation timeline for a multiply-driven signal. A driving process resumes on an event, updates its driver's value, and suspends; one delta later the resolution function combines every driver of the net and the resolved value is applied; the fanout then wakes. The only addition over the single-driver timeline (lesson 3.5) is the resolution step that merges all drivers before the signal updates.

Tristate bus: clean handoff (one driver active) vs overlap (both drive) → 'X'

8 cycles
Tristate bus: clean handoff (one driver active) vs overlap (both drive) → 'X'only en_a: bus = drv_a (AA), driver B is 'Z'only en_a: bus = drv_a…only en_b: bus = drv_b (BB) — clean handoffonly en_b: bus = drv_b…BOTH enables high: two strong drivers conflict → 'X'BOTH enables high: two…en_a11001111en_b00110011bus_oAAAABBBBAAAAXXt0t1t2t3t4t5t6t7
While exactly one enable is asserted, resolution simply passes the active driver (the other is 'Z'). When both enables overlap, two strong, differing drivers fight and the bus resolves to 'X' — the simulator's signature for contention. The 'X' is not a glitch; it is the model telling you two sources drove the net at once.

6. Debugging example — the bus stuck at 'X'

Expected: a shared bus carries the granted master's data. Observed: the bus reads 'X' during a window, and downstream logic samples garbage. Root cause: two drivers were active at once — an arbitration/enable overlap (en_a and en_b both '1'), or a default branch that drove '0' instead of 'Z', so a "released" driver was actually still driving. Fix: ensure mutually exclusive enables and that every inactive driver outputs 'Z'. Engineering takeaway: an 'X' on a multiply-driven net almost always means more than one driver was active — trace each driver's enable and confirm only one is on (and the rest are truly high-Z).

the overlap bug and its fix
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
-- WRONG: inactive driver outputs '0', not 'Z' → it always contends.
bus_o <= drv_b when en_b = '1' else (others => '0');   -- '0' keeps DRIVING the bus
-- RIGHT: release with 'Z' so resolution lets the active driver win.
bus_o <= drv_b when en_b = '1' else (others => 'Z');
-- And guarantee en_a, en_b are mutually exclusive in the arbiter.

7. Common mistakes & what to watch for

  • Driving '0' instead of 'Z' when "inactive." A '0' is a strong driver and contends; an idle tristate source must output 'Z'.
  • Allowing overlapping enables. Two active drivers conflict to 'X'; arbitration must keep exactly one active.
  • Using std_ulogic for a multi-driver net. It is unresolved — a second driver is an elaboration error, not contention.
  • Reading 'X' as a don't-care. 'X' means unknown/conflict; treating it as '0'/'1' hides a real driver fight.
  • Assuming one process can "share" a signal with another by both assigning it. That creates two drivers and resolution, usually not what you intended — use a single driver or a mux.

8. Engineering insight

Multiple drivers are the natural extension of the driver model: the net's value is no longer one driver's value but the resolution of all of them. Resolution encodes electrical truth — released outputs yield, strong beats weak, and a genuine fight is 'X' rather than a silently-picked winner. That honesty is the point: std_logic's 'X' surfaces contention you would otherwise chase in silicon, and std_ulogic's refusal to resolve catches accidental multi-drive at compile time. Prefer a single driver (or an explicit mux) by default, and reach for resolved multi-driver nets only where the hardware truly is a shared bus — then guarantee one active driver at a time.

9. Summary

A net with multiple sources has multiple drivers; a resolution function combines them. std_logic resolves ('Z' yields, strong beats weak, opposing strong values give 'X'), while std_ulogic forbids a second driver. Tristate buses are multiple drivers with exactly one active and the rest 'Z'. An 'X' on such a net is the model's signal that two drivers were active at once.

10. Learning continuity

You now understand how value contention is resolved across drivers. The next question is about time: how a driver's scheduled transactions interact when delays are involved — does a brief glitch propagate or get swallowed? The next lesson, Inertial vs Transport Delay, explains the two delay models a driver can use, why a real gate rejects pulses shorter than its delay (inertial) while an ideal wire passes them (transport), and how that shapes the projected waveform you met in the driver model.