VHDL · Chapter 11.1 · Functions and Procedures
Subprograms — Functions and Procedures
Constants and types let a package share a design's numbers and structure, and subprograms let it share computation. A subprogram is a named, reusable piece of behaviour you call by name, and VHDL offers two kinds. A function takes inputs and returns exactly one value, has no side effects on signals, and is used inside an expression, so it models combinational logic. A procedure can take inputs and also produce several outputs through its parameters, is called as a statement, and is the right tool when a reusable operation yields more than one result or performs a sequence of actions. This lesson introduces both, shows where they live in packages or declarative parts, and explains how synthesizable subprograms simply inline into ordinary logic.
Foundation13 min readVHDLSubprogramsFunctionsProceduresReuseSynthesis
1. Engineering intuition — name a computation, call it everywhere
When the same calculation appears in several places — compute parity, convert a code, pick a field, saturate a sum — copying the logic each time invites divergence and bugs. A subprogram packages that computation under a name: write it once, call it wherever needed, and every call uses the identical logic. VHDL gives you two shapes for this. When the computation produces one result and belongs inside an expression, use a function. When it produces several results, or performs a sequence of steps, use a procedure. Choosing between them is mostly about how many things come out and where you want to call it.
2. Formal explanation — function vs procedure
-- FUNCTION: inputs in, exactly ONE value out via 'return'. Used inside an expression.
-- No signal side effects, no wait. Models combinational logic.
function parity (v : std_logic_vector) return std_logic is
variable p : std_logic := '0';
begin
for i in v'range loop p := p xor v(i); end loop;
return p; -- single returned value
end function;
-- PROCEDURE: any number of in/out/inout parameters. Called as a STATEMENT.
-- Can produce several outputs; (non-synth procedures may contain wait).
procedure add_sat (signal a, b : in unsigned(7 downto 0);
signal sum : out unsigned(7 downto 0);
signal ovf : out std_logic) is
variable t : unsigned(8 downto 0);
begin
t := ('0' & a) + ('0' & b);
sum <= t(7 downto 0); ovf <= t(8); -- TWO outputs, via parameters
end procedure;A function has only in parameters and returns one value with return; it is an expression. A
procedure can have in, out, and inout parameters, returns nothing directly but writes results through
its out parameters, and is a statement. Use a function for single-value computation in an expression; a
procedure for multi-output operations or action sequences.
3. Production usage — where subprograms live, and calling them
-- Declared in a PACKAGE → shared across the design (reuse, Module 10).
-- Or in an architecture/process declarative part → local helper.
architecture rtl of top of ... is
-- (functions/procedures could be declared here for local use)
begin
-- FUNCTION call: sits inside an expression.
par <= parity(data); -- combinational
process (clk) begin
if rising_edge(clk) then
-- PROCEDURE call: a statement; results come back through parameters.
add_sat(a, b, sum_r, ovf_r);
end if;
end process;
end architecture;What hardware does this become? A synthesizable subprogram is inlined: parity(data) becomes the XOR
tree directly in the expression that calls it, and add_sat(...) becomes the adder-plus-overflow logic at the
call site. The subprogram is a source-level abstraction for reuse and readability — there is no "call" in
hardware, just the logic substituted in. Where it is declared (package vs local declarative part) controls
visibility, not the resulting circuit.
4. Structural interpretation — two roles for reusable computation
5. Why this is structural, not timing
A subprogram is a source abstraction for reusable computation, and a synthesizable one inlines into the
logic at its call site — so the right picture is the role/structure map above, not a waveform. Its run-time
behaviour is simply that of the logic it expands to: parity(data) behaves exactly like the XOR tree it becomes,
add_sat(...) like the adder it becomes. The value of subprograms is at design time — one definition, many
calls, readable intent — not a new timing behaviour, which is why later lessons focus on what synthesizes and
how parameters and overloading work rather than on waveforms.
6. Debugging example — function where a procedure was needed (or vice versa)
Expected: a reusable operation with two results. Observed: a compile error that a function cannot return
two values, or that a procedure call was placed inside an expression, or an attempt to wait inside a function.
Root cause: the wrong subprogram kind — a function was used for a multi-output operation (it returns only
one value and may not suspend), or a procedure (a statement) was written inside an expression. Fix: use a
procedure with out parameters when there is more than one result or a sequence of actions; use a
function for a single returned value inside an expression; never wait in a function. Engineering
takeaway: pick the kind by outputs and call site — one value in an expression → function; several outputs or a
statement → procedure.
-- BUG: trying to return two things from a function.
-- function add_sat(...) return (sum, ovf) -- not legal: a function returns ONE value
-- FIX: a procedure with two 'out' parameters.
procedure add_sat (... ; signal sum : out unsigned(7 downto 0); signal ovf : out std_logic);7. Common mistakes & what to watch for
- Using a function for multiple outputs. A function returns exactly one value; use a procedure with
outparameters (or return a record) for several. - Calling a procedure inside an expression. A procedure is a statement; only a function call goes in an expression.
waitor signal side effects in a function. Functions must not suspend or drive signals; that is procedure (or process) territory.- Declaring a one-off helper in a package. Use a package for shared subprograms; a local declarative part for local helpers.
- Expecting a hardware "call." Synthesizable subprograms inline; there is no call/return in the netlist, just substituted logic.
8. Engineering insight & continuity
Subprograms are how VHDL shares computation: a function returns one value for use in an expression (a piece of combinational logic), and a procedure produces several outputs or a sequence of actions as a statement — both written once and called everywhere, both inlining into ordinary logic when synthesized. With this distinction set, Module 11 drills into each: the next lesson, Functions, covers writing and using functions in depth — their parameters, return values, and the combinational logic they synthesize to — before procedures, parameter modes, overloading, conversion functions, and the rules for what is synthesizable.