Skip to content

VHDL · Chapter 3.8 · Signals & Hardware Behavior

Initial Values, U, and Uninitialized Hardware

Hardware does not power up at zero. A flip-flop comes out of reset-less power-on in an unknown state, and VHDL models that honestly with two special values: U means a signal has never been driven, and X means its value is unknown or the result of a conflict. The dangerous part is propagation, because feeding a U or X into any logic makes the output U or X too, so one uninitialised register can turn a whole design red in simulation. This lesson explains why that is actually a useful feature that catches missing resets, why a signal initialiser is a simulation and FPGA convenience rather than an ASIC guarantee, and how to keep unknown values from contaminating your real logic.

Foundation15 min readVHDLstd_logicMetalogical ValuesResetX PropagationInitialization

1. Engineering intuition — silicon powers up unknown

When a chip powers on, every flip-flop settles to some level, but which one is not designed in — it depends on process, voltage, and noise. Treating that as "0" is wishful thinking. VHDL refuses to pretend: an undriven std_logic signal is 'U' (uninitialised), and any genuinely-unknown value is 'X'. These are metalogical values — they exist to model uncertainty, not to be built. The engineering consequence is simple and strict: a design must drive every flip-flop to a known state (via reset) before its value is trusted.

2. Formal explanation — U, X, and propagation

From the nine std_logic values (lesson 2.2), two are central here:

  • 'U'uninitialised: the signal has had no driver since elaboration. It is the default initial value of any std_logic with no explicit :=.
  • 'X'unknown/forcing unknown: a value that cannot be determined, including the result of driver contention (lesson 3.6).

Both propagate: operate on a 'U'/'X' and the result is metalogical too.

unknowns_propagate.vhd
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
-- if any operand is 'U' or 'X', the result is generally 'U'/'X':
y <= a and b;     -- a='X' → y='X' (unless b forces it: '0' and 'X' = '0' for AND)
sum <= unsigned(a) + unsigned(b);   -- a has any 'U'/'X' bit → that arithmetic result is 'X'
-- A comparison against an unknown is itself unknown: ('X' = '1') is not TRUE.

The few exceptions are controlling values ('0' and 'X' = '0', '1' or 'X' = '1') where one operand forces the result regardless of the unknown — useful, but not something to rely on for correctness.

3. Production-quality RTL — reset is how you escape U/X

The cure for power-on unknown is an explicit reset that drives state to a defined value:

reset_defines_state.vhd
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
signal count : unsigned(7 downto 0);    -- powers up 'U' in simulation (no init)
process (clk)
begin
  if rising_edge(clk) then
    if rst = '1' then
      count <= (others => '0');          -- reset DRIVES count to a known 0 → leaves 'U'
    else
      count <= count + 1;                -- only meaningful once count is known
    end if;
  end if;
end process;

What hardware does this become? An 8-bit register with a reset. Until rst asserts, count is 'U' in simulation (and genuinely unknown in silicon); after reset it is defined. Without the reset branch, count would stay 'U' and count + 1 would be 'U' forever — visible immediately in simulation, which is exactly the point.

4. Hardware interpretation — initializer ≠ reset

A signal initializer (signal s : std_logic := '0';) is not a universal hardware guarantee:

  • Simulation always honours it: s starts at '0' at time zero.
  • FPGA synthesis can honour it: the bitstream presets flip-flops, so power-on state is defined.
  • ASIC synthesis generally cannot: standard-cell flip-flops have no power-on preset, so an initializer is ignored and the real power-on state is unknown — you must use a reset.
init_vs_reset.vhd
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
signal valid : std_logic := '0';   -- sim: starts '0'. FPGA: preset '0'. ASIC: NOT guaranteed.
-- Portable, synthesizable rule: define power-on state with an explicit reset, not the ':='.
initial value sources across simulation, FPGA, and ASIC targetstime 0presetno presetsignal := '0'declared initial valueSimulationalways honored ('U' ifnone)FPGAhonored via bitstreampresetASICignored → power-up unknown;needs RESET12
Where an initial value comes from, per target. In simulation the ':=' initializer (or the type's default 'U') sets the time-zero value. FPGA synthesis can realize an initializer through the configuration bitstream that presets flip-flops. ASIC standard cells have no power-on preset, so they come up unknown ('X') and only a reset defines their state. The portable, synthesizable source of a known power-on value is therefore RESET, not the initializer.

5. Simulation interpretation — U at time zero, then reset

In simulation every signal starts at its initial value — 'U' if none was given — and stays there until driven. A register therefore shows 'U'/'X' from time zero until reset defines it:

simulation timeline from uninitialised U through reset to a defined valueElaborationregister/net createdTime 0: 'U'no initializer →uninitialisedReads produce 'U'/'X'unknown propagates throughfanoutReset assertsclocked process drives aknown valueClock edge appliesresetregister becomes definedFanout definedunknowns cleared downstream12
The simulation timeline for an uninitialised register. At elaboration the signal is created; at time zero it holds 'U' (no initializer); any logic that reads it produces 'U'/'X' and that contamination spreads through the fanout. When reset asserts, the clocked process drives the register to a known value at the next edge, the unknown clears, and downstream logic becomes defined. The 'U' window before reset is deliberate — it makes a missing reset visible.

A register starts unknown ('U'/'X') and only a reset brings it to a known value

8 cycles
A register starts unknown ('U'/'X') and only a reset brings it to a known valuet=0: count is 'U' (no initializer / unreset)t=0: count is 'U' (no …rst asserted → next edge drives count to a known 0rst asserted → next ed…reset released: count now counts from a defined statereset released: count …clkrst00011000countUUUU0012t0t1t2t3t4t5t6t7
Before reset, the register is 'U' and any arithmetic on it would also be unknown. Reset drives it to a defined 0 on the clock edge, after which it behaves normally. The unknown window is not a bug to hide — it is the simulator flagging that the register is meaningless until reset.

6. Debugging example — the X that will not clear

Expected: outputs become valid shortly after start-up. Observed: some outputs sit at 'X' indefinitely and spread to everything they touch. Root cause: a register was never reset (no reset branch, reset never asserted, or reset on the wrong polarity), so it stays 'U'/'X' and propagates through the datapath. Fix: ensure every state element is driven to a known value by reset (correct polarity, asserted long enough), and trace the 'X' upstream to the first undriven register. Engineering takeaway: 'X' propagation is a gift — follow the red back to its source and you find the exact register that lacks a reset; never mask it by forcing '0'.

missing_reset.vhd
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
-- WRONG: no reset → state_reg is 'U' forever, and every output derived from it is 'X'.
process (clk) begin
  if rising_edge(clk) then
    state_reg <= next_state;     -- never initialised to a known state
  end if;
end process;
-- RIGHT: reset to a defined state so the FSM starts known.
process (clk) begin
  if rising_edge(clk) then
    if rst = '1' then state_reg <= IDLE;
    else             state_reg <= next_state;
    end if;
  end if;
end process;

7. Common mistakes & what to watch for

  • Relying on := '0' for ASIC power-on state. ASIC flip-flops have no preset; use a reset. The initializer only helps simulation and FPGA.
  • Masking 'X' by forcing '0'/'1'. That hides the missing reset and ships a real bug; fix the source instead.
  • Assuming ('X' = '1') is false-and-safe. A comparison against an unknown is itself not a clean boolean; unknowns leak into control flow.
  • Forgetting 'U''X'. 'U' means never driven (often a connectivity/reset gap); 'X' means unknown/conflict. The distinction points to different root causes.
  • Resetting only some state. A single unreset register can contaminate everything downstream; every state element needs a defined power-on value.

8. Engineering insight

'U' and 'X' make VHDL pessimistic on purpose. By refusing to assume a power-on 0, the model forces you to define state with reset and then loudly propagates any gap so it cannot hide. That pessimism is your best ally: an 'X' storm in simulation is a precise pointer to an uninitialised or contended node, and chasing the red upstream lands you on the exact defect. Designs that respect this — reset every state element, never mask unknowns — behave the same in simulation and silicon. Designs that paper over 'X' with forced constants are trading a visible simulation failure for an invisible bring-up failure.

9. Summary

'U' marks an undriven signal (the default initial value); 'X' marks an unknown or conflicting value. Both propagate, so one uninitialised register can contaminate a whole design — which is the point: it makes missing resets visible. A := … initializer is honoured by simulation and FPGA bitstreams but not by ASIC standard cells, so the portable way to define power-on state is an explicit reset, not the initializer.

10. Learning continuity

You have now completed the signal model's edge cases — contention, delay, and the unknown. The module's final lesson steps back to the unifying picture: Signals as the Model of Real Wires ties declaration, drivers, delta cycles, resolution, delay, and initialization into one mental model of the physical net, and frames how that model maps onto synthesized hardware — the bridge from "how signals behave" into the next module on concurrency and the processes that drive them.