Skip to content

VHDL · Chapter 2.5 · Data Types

Resolved vs Unresolved Types

Some VHDL types allow a wire to have several drivers and some do not, and that single difference is what separates the standard-logic type from its unresolved base type. The resolved type permits multiple drivers and combines them through a resolution function, which is why two fighting drivers quietly settle to an X value. The unresolved base type allows only one driver, so a second one is illegal and the tool reports it at compile time. Both types carry the same nine values and differ only in this rule. This lesson explains the distinction, why a language needs both, and the practical payoff: the unresolved type turns an accidental double-drive into an error you cannot miss instead of a silent X.

Foundation13 min readVHDLstd_logicstd_ulogicResolutionMultiple DriversTypes

1. Intuition — who is allowed to drive this wire?

Every wire in a design has drivers — the processes or assignments that set its value. The question a type answers here is: how many drivers may a single wire have?

  • A resolved type allows many drivers and defines a resolution function to combine them into one value. std_logic is resolved — which is exactly why a tri-state bus (many drivers, one at a time) works, and why two fighting drivers produce 'X' instead of a compile error.
  • An unresolved type allows one driver, full stop. A second driver is an error caught at compile/elaboration time. std_ulogic (the u is for unresolved) is the unresolved base type, and std_logic is its resolved subtype.

So the two types describe the same nine values; they differ only in whether multiple drivers are permitted and resolved or forbidden and flagged.

2. The distinction, drawn

Resolved std_logic versus unresolved std_ulogic on multiple driversstd_logicRESOLVED subtype2+ drivers →resolution fndefined value, or 'X' onconflictstd_ulogicUNRESOLVED base type2+ drivers → ERRORcaught at elaboration12
std_ulogic and std_logic carry the same nine values but differ on multiple drivers. With the RESOLVED std_logic, two drivers on one wire are legal: a resolution function combines them by strength (lesson 2.2), producing a defined value — or 'X' when forcing drivers disagree. With the UNRESOLVED std_ulogic, a second driver on the same wire is illegal and reported as an error at elaboration. Resolved buys bus capability at the cost of hiding accidental double-drive as 'X'; unresolved buys early detection at the cost of forbidding intentional multi-driver wires.

There is no waveform on this page: the difference is a compile-time legality rule, not a timing behaviour. (The runtime side — two resolved drivers combining by strength over time — is the resolution waveform you already saw in lesson 2.2.) Here the teaching artifact is the type relationship, not a signal trace.

3. The resolution function — what "resolved" actually does

When a resolved signal has more than one driver, the simulator does not pick one — it calls a resolution function that takes all the driver values and returns a single result, using the strength model from lesson 2.2:

  • a forcing driver beats a weak one,
  • a weak driver beats 'Z' (a released driver),
  • two forcing drivers that disagree resolve to 'X'.

This is what makes a real bus work: every driver releases to 'Z' except the active one, so resolution returns the active driver's value. The same function is also what turns an accidental second driver into 'X' — useful, but only if you notice the 'X'.

4. Vectors too — std_logic_vector vs std_ulogic_vector

The same pairing exists for buses: std_logic_vector is resolved (each element is a resolved std_logic), and std_ulogic_vector is unresolved. In modern VHDL (2008 onward) std_logic_vector is defined as the resolved subtype of std_ulogic_vector, so the two interoperate, and either can carry a bus. The choice is the same one: should the elements permit multiple drivers, or forbid them?

resolved_vs_unresolved.vhd
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
library ieee;
use ieee.std_logic_1164.all;
 
signal sig_r : std_logic;          -- resolved: a 2nd driver resolves (to 'X' on conflict)
signal sig_u : std_ulogic;         -- unresolved: a 2nd driver is a COMPILE error
 
signal bus_r : std_logic_vector(7 downto 0);   -- resolved bus (the everyday choice)
signal bus_u : std_ulogic_vector(7 downto 0);  -- unresolved bus (single-driver enforced)

5. Debugging example — a silent X vs a loud error

Suppose two processes accidentally drive the same single-bit signal. The type decides whether you find out at compile time or in a waveform hunt:

accidental double-drive
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
-- With std_logic (resolved): COMPILES. At runtime, when both drive,
-- the signal shows 'X' — you must spot it in simulation and trace it.
signal busy : std_logic;
busy <= '1' when state = ACTIVE else '0';   -- driver 1
busy <= sensor_flag;                         -- driver 2 (accidental) → resolves to 'X'
 
-- With std_ulogic (unresolved): the SAME two drivers are rejected at
-- elaboration: "signal busy has multiple sources / drivers".
signal busy_u : std_ulogic;

With the resolved type, the mistake is a runtime 'X' you might chase for an hour. With the unresolved type, it is a compile-time error naming the over-driven signal. That is the practical value of unresolved types: they convert a class of silent bugs into immediate errors.

6. When to use each

  • std_logic / std_logic_vector — the default for almost everything, and required anywhere a wire genuinely has multiple drivers (tri-state buses, shared lines). Convention across most code bases.
  • std_ulogic / std_ulogic_vector — when you want the tool to guarantee a signal has exactly one driver, so an accidental second driver is impossible to ship. Some teams use them by default for internal signals precisely for this extra safety.

Either way, the values, operators, and behaviour are identical for a correctly single-driven signal — the choice only changes what happens to a second driver.

7. Common mistakes & what to watch for

  • Believing std_logic prevents double-drives. It does not — it resolves them, often to 'X'. Only an unresolved type rejects them.
  • Chasing an 'X' that is really contention. A persistent 'X' on a resolved signal is often a second, unintended driver; switching that signal to std_ulogic will name the culprit at compile time.
  • Thinking they are different value sets. std_logic and std_ulogic have the same nine values; only multi-driver legality differs.
  • Mixing the families carelessly pre-2008. Modern VHDL makes them interoperate as subtypes; very old code may need explicit handling — prefer a 2008-aware flow.

8. Engineering insight

Resolved and unresolved types are two answers to one design rule: should this wire be allowed more than one driver? Buses need "yes," so std_logic resolves. Most internal signals should have exactly one driver, and there "no" is safer — std_ulogic makes the accidental second driver a compile error instead of a 'X' you have to discover. The 'X' from lesson 2.2 and the "multiple drivers" error here are the same bug seen through the two type choices: one defers it to simulation, the other catches it at build.

9. Summary & next step

std_logic is a resolved type (multiple drivers allowed, combined by a resolution function using strength), and std_ulogic is its unresolved base (a second driver is a compile error). Same nine values, different multi-driver legality. Resolved enables buses and hides accidental double-drives as 'X'; unresolved forbids them and flags the mistake early. The vector forms (std_logic_vector / std_ulogic_vector) mirror the choice.

The chapter now turns from logic-valued types to numbers. The next lesson covers VHDL's abstract whole-number type — integer types and ranges — and why constraining an integer's range is what makes it synthesize to the right number of bits.