Skip to content

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_vs_procedure.vhd
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
-- 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

using_subprograms.vhd
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
-- 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

function returns one value in an expression; procedure produces several outputs as a statementfunctioninputs → ONE return value(expression)procedurein/out params → severaloutputs (statement)used in an expressiony <= parity(data); —combinationalused as a statementadd_sat(a,b,sum,ovf);live in package ordeclarative partshared vs local visibility12
The two kinds of subprogram and their roles. A function takes inputs and returns exactly one value, has no signal side effects, and is used inside an expression — it models combinational logic and inlines at the call site. A procedure takes in/out/inout parameters, produces zero or more outputs through them, and is called as a statement — the right tool when an operation yields several results or performs a sequence. Both can live in a package (shared across the design) or in a local declarative part (local helper). Synthesizable subprograms inline into ordinary logic, so a role/structure diagram, not a waveform, captures them.

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.

pick_the_right_kind.vhd
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
-- 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 out parameters (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.
  • wait or 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.