A VHDL signal assignment is the basic statement that connects logic to a signal: target <= expression. It looks like an ordinary variable assignment, but it describes a continuous dataflow connection — the target signal continuously takes the value of the expression, just like a wire driven by gates in real hardware.

f <= (x1 AND x3) OR (x2 AND x4);

The <= is the signal-assignment operator. Read it as “is driven by.” Whenever any input changes, the target re-evaluates.

Concurrent semantics

The defining property: all signal assignments in a VHDL architecture body run in parallel. There’s no order:

architecture LogicFunc of example2 is
begin
    f <= (x1 AND x3) OR (x2 AND x4);
    g <= (x1 OR NOT x3) AND (NOT x2 OR x4);
end architecture;

Both f and g are assigned “simultaneously” in the hardware sense — every time the inputs change, both outputs re-evaluate. There’s no notion of “f’s assignment runs before g’s.” The order they appear in the source is irrelevant.

This matches actual hardware: a chip has both gates wired up, both responding to input changes in parallel. VHDL signal assignments describe that.

Signals as wires

A signal in VHDL is the abstraction for a wire. Signals can be declared between is and begin of an architecture (internal signals) or appear as ports in an entity.

architecture rtl of Q1 is
    signal k : std_logic;
begin
    k <= x1 AND x2;
    f <= k AND NOT x1;
end architecture rtl;

Here, k is an internal wire. The first assignment drives k; the second uses it.

Operators

The operators legal in signal-assignment expressions:

  • Boolean: AND, OR, NOT, NAND, NOR, XOR, XNOR.
  • Arithmetic (with appropriate types): +, -, *, /, mod, rem.
  • Comparison: =, /=, <, <=, >, >=.
  • Concatenation: & for joining vectors.

Conditional assignments

A more elaborate form using when ... else:

f <= a when sel = '0' else b;

This is a 2-to-1 MUX in dataflow style. Multiple conditions chain:

y <= "00" when state = idle
else "01" when state = read
else "10" when state = write
else "11";

Equivalent to a tree of MUXes in hardware.

Selected signal assignment

Another conditional form, parallel to a case statement:

with sel select
    f <= a when "00",
         b when "01",
         c when "10",
         d when others;

Synthesizes to one -to- MUX. Behaves identically to nested when ... else but reads more cleanly when one selector picks among many alternatives.

Variables vs signals (a subtle point)

Inside a process, you can also declare variables with := for assignment. Variables update immediately (sequential, like normal programming). Signal assignments inside a process don’t take effect until the process suspends — the new value is scheduled for the next delta cycle, a zero-time but ordered simulation step that runs after the process has finished executing. So if you write:

process(clk)
    variable v : std_logic;
begin
    v := a;        -- variable updates now
    s <= a;        -- signal scheduled, takes effect at end of process
    if v = s then  -- v has new a; s still has its old value
        ...
    end if;
end process;

v already holds the new value, but s still reads as its previous value inside the same process activation. This is the classic trap: a chain of signal assignments to the same target inside a process keeps only the last assignment, because all of them schedule for the same delta cycle. Use a variable when you need an intermediate that updates immediately.

For most synthesizable designs, you use signals everywhere. Variables show up in process bodies for loop counters or temporary computations within a single process iteration.

For the surrounding container, see VHDL architecture. For the language overview, see VHDL.