VHDL · Chapter 11.4 · Functions and Procedures
Subprogram Parameters and Modes
Every subprogram parameter is governed by two independent properties. The mode sets direction: in for read-only input (the default), out for a write-only result, and inout for both. The class sets what kind of object the parameter is: constant for a passed value, variable for a mutable object, or signal for an actual signal that is driven or sensed, as testbench procedures need. Functions are restricted to in parameters, which keeps them pure, while procedures use the full range. Arguments associate either by position or by name, and parameters may carry default values. This lesson maps how modes and classes combine and how the association rules work so your subprogram interfaces come out correct and readable.
Foundation14 min readVHDLSubprogramsParametersModesAssociationReuse
1. Engineering intuition — direction and kind, separately
Every subprogram parameter answers two separate questions. First, which way does data flow? — that is the
mode: in (a value coming in), out (a result going out), inout (both). Second, what kind of thing is it? —
that is the class: a plain value (constant), a mutable object (variable), or an actual signal. These are
independent: an in parameter is usually a constant value, an out parameter usually a variable you write, and
— only in testbench procedures that must drive or observe real hardware signals — a parameter is given the
signal class. Getting both right is what makes a subprogram interface behave the way you intend.
2. Formal explanation — modes, classes, and their defaults
-- MODE = direction; CLASS = kind of object. Defaults shown in [brackets].
-- in : read-only [class defaults to constant] -- the only mode a FUNCTION may use
-- out : write-only [class defaults to variable]
-- inout : read+write [class defaults to variable]
-- signal class: the parameter IS a signal (driven/sensed) — testbench procedures.
procedure example ( a : in std_logic_vector; -- constant-class in (a value)
y : out std_logic_vector; -- variable-class out (write result)
acc : inout integer; -- variable-class inout (read+write)
signal clk : in std_logic; -- SIGNAL-class (sense a real signal)
signal bus_o : out std_logic_vector) is -- SIGNAL-class (drive a real signal)
begin
-- ... body ...
end procedure;
-- A FUNCTION may only have 'in' parameters (purity); no out/inout.
function f (x : in integer) return integer is begin return x + 1; end function;The mode fixes direction; the class fixes object kind, each with a sensible default (in→constant,
out/inout→variable). The signal class is explicit and is what lets a testbench procedure drive or sense
actual design signals. Functions allow only in, which is precisely why they stay pure.
3. Production usage — association by position, name, and default
-- Given: procedure cfg (width : in positive; mode : in std_logic := '0'; q : out integer);
-- POSITIONAL: arguments in declared order.
cfg(8, '1', result);
-- NAMED: order-independent, self-documenting; skip params that have defaults.
cfg(width => 8, q => result); -- 'mode' takes its default '0'
cfg(q => result, width => 16, mode => '1');
-- Unconstrained array parameter adapts to the argument's width via 'range/'length.
-- function parity(v : std_logic_vector) return std_logic; -- works for any width passed inWhat hardware does this become? Association is purely how arguments are wired to parameters — it changes readability and which defaults apply, not the synthesized result. A synthesizable subprogram still inlines as logic; the parameter system just defines the inputs and outputs of that inlined block. Named association is the production habit for anything beyond two or three parameters: it is order-independent, documents intent at the call, and lets defaulted parameters be omitted.
4. Structural interpretation — the mode × class system
5. Why this is structural, not timing
Parameters and association define a subprogram's interface — the directions and kinds of its inputs and outputs — which is structure, not behaviour, so the mode×class map (above) communicates it, not a waveform. The synthesizable subprogram still inlines to logic whose timing you have already seen; the parameter system only shapes what connects to what. The one timing-flavoured case is the signal-class parameter in a testbench procedure, where driving/sensing real signals interacts with the simulation timeline — but that timing belongs to the stimulus, not to the parameter mechanism itself.
6. Debugging example — wrong class or mode at the interface
Expected: a procedure drives a design signal, or reads and updates an accumulator. Observed: the driven
signal never changes in simulation, or a compile error that an out parameter is read, or that a signal is
associated with a non-signal (constant/variable) parameter. Root cause: a parameter that must drive/sense a
real signal was left as the default variable class instead of signal; or a read-and-write parameter was
out instead of inout; or an actual signal was passed to a constant/variable-class parameter. Fix:
mark testbench drive/sense parameters as signal class, use inout for read-and-write, and match the
parameter class to the kind of object passed. Engineering takeaway: mode sets direction, class sets object
kind — a testbench procedure that must touch real signals needs the signal class, and read-write needs
inout.
-- BUG: default variable-class param can't drive the design's signal as expected in a TB.
-- procedure drive (q : out std_logic) ...
-- FIX: signal-class parameter to actually drive the signal.
procedure drive (signal q : out std_logic) is begin q <= '1'; end procedure;7. Common mistakes & what to watch for
- Forgetting the
signalclass in testbench procedures. To drive or sense actual signals, the parameter must besignalclass, not the default variable. outwhereinoutis needed. A parameter both read and written must beinout;outis write-only.- Giving a function
out/inoutparameters. Functions arein-only by rule; use a procedure for outputs. - All-positional long argument lists. Use named association beyond a couple of parameters for clarity and to apply defaults.
- Over-constraining array parameters. Leave arrays unconstrained and use
'range/'lengthfor width-generic subprograms.
8. Engineering insight & continuity
The parameter system has two independent axes: mode (in/out/inout) for direction and class (constant/variable/signal) for object kind, with defaults that cover the common cases and the explicit signal class reserved for testbench procedures that touch real signals — plus positional/named/default association for clean call sites. Master this and your subprogram interfaces say exactly what they mean. With one definition able to serve many widths via unconstrained parameters, the remaining question is serving many types and operators under one name — which is the next lesson, Operator and Subprogram Overloading.