Skip to content

VHDL · Chapter 6.2 · Combinational Logic Design

Combinational Processes

Concurrent assignments are perfect for a single combinational function, but real blocks often have several outputs, a case decode, or a shared intermediate value, and there a combinational process is cleaner. The recipe is precise: make the process sensitive to every input, use no clock-edge guard, and write the body as default-then-override, assigning every output a safe default at the top and then conditionally overriding it. That structure scales to multi-output logic and, crucially, is latch-free by construction. This lesson develops the combinational-process pattern, shows when it beats a concurrent assignment, and reinforces the golden rules of combinational design from the module opener.

Foundation14 min readVHDLCombinational Processprocess(all)Default OverrideLatch-freeRTL

1. Engineering intuition — a process that is pure logic

A combinational process looks like a clocked one but with two deliberate differences: it has no clock-edge guard, and it reacts to all its inputs. That makes it describe pure logic — outputs that settle to a function of the inputs, no state. The reason to use it instead of concurrent assignments is organisational: when a block computes several outputs, or decodes a value with case, or shares an intermediate result, a single process reads far better than a scatter of concurrent lines — and the default-then-override structure keeps it correct.

2. Formal explanation — the three ingredients

combinational_process_recipe.vhd
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
proc : process (all)          -- 1) complete sensitivity (every read signal)
begin
  y <= b;                     -- 3) default-then-override: default first ...
  z <= '0';
  if sel = '1' then           --    (no clock guard anywhere — 2)
    y <= a;                   --    ... then conditional overrides
    z <= '1';
  end if;
end process;

A combinational process has three defining properties: (1) complete sensitivityprocess(all) (VHDL-2008) or every read signal listed, so simulation matches synthesis (lesson 5.2); (2) no clock guard — no rising_edge(clk), so nothing registers; (3) default-then-override — every output is assigned a default before any conditional, so every path drives every output and no latch is inferred. Miss any one and you get a mismatch, a register, or a latch instead of clean logic.

3. When a process beats a concurrent assignment

process_vs_concurrent.vhd
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all;
 
-- Concurrent is fine for ONE simple function:
y <= a when sel = '1' else b;
 
-- A PROCESS is clearer for MULTI-OUTPUT + case + shared intermediate:
ctrl : process (all)
  variable s : unsigned(8 downto 0);          -- shared intermediate (immediate)
begin
  flags  <= "00";                              -- defaults
  result <= (others => '0');
  s := resize(unsigned(a), 9) + resize(unsigned(b), 9);
  case mode is
    when "00" => result <= std_logic_vector(s(7 downto 0));
                 flags(0) <= s(8);             -- carry
    when "01" => result <= a and b;
    when others => result <= a or b;
  end case;
  if result = x"00" then flags(1) <= '1'; end if;  -- zero flag
end process;

What hardware does this become? A combinational block driving result and flags from a shared adder intermediate s and a case decode — readable as one unit. The same logic as scattered concurrent assignments, but the process keeps the related outputs, the shared computation, and the decode together, which is why a process is preferred here.

4. Hardware interpretation — one cone, multiple outputs

combinational process as one logic cone driving multiple outputsinputs (process(all))every read signaldefault-then-overridebodyno clock guardoutput 1defaulted then drivenoutput 2defaulted then driven12
A combinational process is a single logic cone driving one or more outputs. process(all) makes it react to every input; the absence of a clock guard means nothing registers; default-then-override guarantees every output is driven on every path. Synthesis reads the body's data flow and builds the gates/muxes for each output. The process is an organisational wrapper around combinational logic, not a new kind of hardware.

5. Simulation interpretation — default first, then override

default assignment then conditional override inside a combinational processInput changes → wakeprocess(all)Default every outputevery path now drives themConditional overridesif / case set specificoutputsOutputs settle(delta)pure function of inputs12
The default-then-override flow inside a combinational process. On wake (any input changed), every output is first assigned its default; then conditionals override the relevant ones. Because the default ran on every path, every output is scheduled a value regardless of which branches execute — so no path leaves an output unassigned, and no latch is inferred. Signals update one delta after the process suspends (the execution model).

A combinational process drives two outputs as pure functions of its inputs

8 cycles
A combinational process drives two outputs as pure functions of its inputssel=1: y overridden to a, z=1 (both defaulted then set)sel=1: y overridden to…sel=0: defaults stand → y=b, z=0 — no held statesel=0: defaults stand …sel01100101a55999227b33336666y35936267z01100101t0t1t2t3t4t5t6t7
Both outputs track the current inputs with no memory: when sel=1 the overrides drive y=a and z=1; when sel=0 the defaults (y=b, z=0) stand. Because every output is defaulted first, every path drives them — latch-free. The process is just a tidy wrapper around this combinational function.

6. Debugging example — the process that registered or latched

Expected: combinational logic. Observed: either an inferred latch, or — surprisingly — a register. Root cause: for the latch, an output was not defaulted and some path left it unassigned (rule 1). For the accidental register, the body contained a rising_edge(clk) guard, turning the "combinational" process into clocked logic. Fix: default every output at the top and remove any clock guard from a combinational process (keep clocked behaviour in a separate process). Engineering takeaway: a combinational process must have no clock guard and default every output; a stray edge-guard makes registers, an unassigned path makes latches.

comb_process_fixes.vhd
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
-- BUG A: no default for 'z' → unassigned when sel='0' → latch.
process (all) begin
  if sel = '1' then y <= a; z <= '1'; else y <= b; end if;  -- z not assigned on else → latch
end process;
-- FIX A: default both outputs, then override.
process (all) begin
  y <= b; z <= '0';                                          -- defaults
  if sel = '1' then y <= a; z <= '1'; end if;
end process;

7. Common mistakes & what to watch for

  • Forgetting to default an output. Any output not assigned on every path infers a latch — default all outputs at the top.
  • A clock guard in a combinational process. rising_edge(clk) makes registers; keep it out of combinational processes.
  • Incomplete sensitivity. Use process(all); an omitted input causes the sim/synth mismatch.
  • Reading an output back as an intermediate. Use a variable for shared intermediates (immediate), not a signal you read after assigning.
  • One giant process. Split unrelated combinational blocks into separate processes for readability and easier review.

8. Engineering insight & continuity

The combinational process is concurrent assignment's big sibling: same hardware, but organised for multi-output, case-driven, and intermediate-sharing logic. Its correctness reduces to a mechanical habit — process(all), no clock guard, default-then-override — that makes latches and mismatches structurally impossible. Adopt that template for every combinational block of any size and the logic is clean by construction. The next lesson examines the failure this template prevents in depth: Unintended Latches — what they are, exactly how incomplete assignment creates them, and how to spot and eliminate them — followed by Default Assignments as the disciplined cure.