VHDL · Chapter 11.3 · Functions and Procedures
Procedures
Where a function returns one value inside an expression, a procedure is called as a statement and can return several results through its parameters. Its parameters carry modes, in for inputs, out for results, and inout for read-modify-write, so one call can produce a sum and a carry, or an encoded value and a valid flag. In synthesizable code a procedure simply packages multi-output logic that inlines at the call site, combinational when called in a combinational context and registered when called inside a clocked process. Procedures also shine in testbenches, where a non-synthesizable procedure with a wait can wrap a whole bus-write or reset sequence into one reusable call. This lesson covers writing procedures, how they synthesize, and their testbench role.
Foundation14 min readVHDLProceduresSubprogramsTestbenchReuseSynthesis
1. Engineering intuition — one call, several results (or a sequence)
A function fits when exactly one value comes out. Many useful operations are not like that: an adder produces a
sum and a carry; a priority encoder produces an index and a valid bit; a transaction performs a sequence of
steps. A procedure is built for these — it is called as a statement and hands results back through its out
parameters, as many as you need, and it can perform an ordered series of actions. In synthesizable RTL that means
packaging a multi-output computation under one name; in a testbench it means packaging a whole protocol sequence
(drive address, assert valid, wait, deassert) into a single readable call.
2. Formal explanation — anatomy of a procedure
-- Called as a STATEMENT. Parameters carry MODES: in (input), out (result), inout (read+write).
-- Several outputs are normal. (Synthesizable procedures contain no wait.)
procedure add_carry (a, b : in unsigned(7 downto 0); -- inputs
sum : out unsigned(7 downto 0); -- result 1
carry : out std_logic) is -- result 2
variable t : unsigned(8 downto 0);
begin
t := ('0' & a) + ('0' & b);
sum := t(7 downto 0); -- writing variable 'out' params
carry := t(8);
end procedure;
-- TESTBENCH procedure (NOT synthesizable) — packages a sequence using wait.
procedure bus_write (signal clk : in std_logic;
signal addr : out std_logic_vector;
signal wr : out std_logic;
constant a : in std_logic_vector) is
begin
wait until rising_edge(clk);
addr <= a; wr <= '1';
wait until rising_edge(clk);
wr <= '0'; -- a whole write transaction in one call
end procedure;A procedure has parameters with modes in/out/inout, a body of sequential statements, and no return
value (results flow through out/inout). Synthesizable procedures avoid wait and inline as logic;
testbench procedures may use wait to package timed sequences.
3. Production usage — multi-output logic and testbench sequences
-- SYNTHESIZABLE: a multi-output operation, called inside a clocked process → registered results.
process (clk) begin
if rising_edge(clk) then
add_carry(x, y, sum_r, carry_r); -- one call, two registered outputs
end if;
end process;
-- TESTBENCH: a reusable transaction sequence, called from a stimulus process.
stim : process begin
bus_write(clk, addr, wr, x"10"); -- a full write, readable as one line
bus_write(clk, addr, wr, x"14");
wait;
end process;What hardware does this become? The synthesizable add_carry inlines at its call site as an adder whose
two outputs (sum, carry) drive the two targets; because the call sits in a clocked process, those targets are
registered. Called in a combinational context instead, the same procedure is combinational. The testbench
bus_write is not hardware — it is simulation control, its wait statements sequencing stimulus over clock
edges. Same construct, two roles: package logic, or package a timed sequence.
4. Structural interpretation — several outputs from one call
5. Why this is structural, not timing
A synthesizable procedure inlines into the logic at its call site — an adder, an encoder, whatever its body
computes — so the right picture is the multi-output structure above; its run-time behaviour is simply that of the
logic it expands to (combinational, or registered when the call is in a clocked process), already seen in earlier
modules. The genuinely timed form is the testbench procedure with wait, but there the waveform of
interest is the stimulus it produces (a bus transaction), which belongs to the verification context rather than to
the procedure construct itself. The construct's essence is structural reuse of multi-output behaviour.
6. Debugging example — reading an out parameter (or wait in synthesizable code)
Expected: a procedure returns results through its out parameters. Observed: a compile error that an
out parameter cannot be read, or a synthesizable procedure rejected for containing wait. Root cause:
either the body tried to read an out parameter (it is write-only; to both read and write a parameter it must
be inout), or a wait was placed in a procedure meant for synthesis (legal only in simulation/testbench
procedures). Fix: use inout for a parameter that is read and written; remove wait from synthesizable
procedures (use a clocked process for sequencing). Engineering takeaway: out is write-only and inout is
read-write; wait belongs only in non-synthesizable testbench procedures.
-- BUG: reading an 'out' parameter.
-- procedure p (x : out integer) is begin x := x + 1; end procedure; -- can't read 'out' x
-- FIX: use 'inout' to read and write the same parameter.
procedure p (x : inout integer) is begin x := x + 1; end procedure;7. Common mistakes & what to watch for
- Reading an
outparameter.outis write-only; useinoutto both read and write a parameter. waitin synthesizable procedures. Legal only in testbench procedures; for hardware sequencing use a clocked process.- Expecting a return value. Procedures return through parameters, not
returnwith a value;return(no value) only exits early. - Forgetting the call context sets timing. A synthesizable procedure is combinational or registered depending on where it is called (combinational vs clocked process).
- Over-stuffing one procedure. Keep a procedure to one coherent operation; split unrelated work, just as you would partition logic.
8. Engineering insight & continuity
A procedure is the multi-output, statement-form subprogram: in/out/inout parameters let one call return
several results or, in a testbench, package a whole timed sequence behind wait. In synthesizable code it inlines
as logic (combinational or registered by context); in verification it makes stimulus read like a protocol. With
functions and procedures both covered, the natural next question is the parameters themselves — the modes,
classes, and how arguments associate — which is exactly the next lesson, Subprogram Parameters and Modes.