courses:system_design:vhdl_language_and_syntax:subprograms

Subprograms

  • Functions
    • Function name can be an operator
    • Arbitrary number of input parameters
    • Exactly one return value
    • No WAIT statement allowed
    • Function call ⇔ VHDL expression
  • Procedures
    • Arbitrary number of parameters of any possible direction (in/out/inout)
    • RETURN statement optional (no return value!)
    • Procedure call ⇔ VHDL statement
  • Subprograms can be overloaded
  • Parameters can be constants, signals, variables or files
VHDL’93: ‘impure’ functions are allowed in VHDL’93

Notes

The term subprogram is used as collective name for functions, procedures and operators. Operator definitions are treated as a special case of function definitions where the name is replaced by the operator symbol, enclosed by quotation marks (“). Please note that it is not permitted to declare new operators, i.e. it is just possible to provide a function with a different set of input parameters. This feature is called overloading (different subprograms differ by their parameters, only) and may be applied to all subprograms.

Subprogram definitions consist of the subprogram declaration, where the identifier and parameter list are defined, and the subprogram body, defining the behavior. The statements in the subprogram body are executed sequentially. A function call is an expression (like ’a + b’) that can exist within a statement, only. A procedure call, on the other hand, is a statement (like ’c := a + b;’) and therefore it can be placed inside a process where it is executed sequentially or inside an architecture where it acts like any other concurrent statement. The return value is given after the keyword ’return’ which may be placed several times within a subprogram body. Please note that procedures do not have a return value!

IMPURE functions can have access to external objects outside of their scope. This allows returning different values, even when called with the same parameters. If, for example, a function call was used to read input values from a file, the file would have to be declared inside the function in VHDL’87. Consequently, the file would be opened with each function call and closed whenever at the end of the execution of the function. Therefore, always the first character would be read! It was impossible to read character after character via a function call in VHDL’87, unless the file itself was provided with each function call.

architecture EXAMPLE of FUNCTIONS is
  [(im)pure] function COUNT_ZEROS (A : bit_vector) return integer is variable ZEROS : integer;
  begin
    ZEROS := 0;
    for I in A’range loop
      if A(I) =0then
        ZEROS := ZEROS + 1;
      end if;
    end loop;
    return ZEROS;
  end COUNT_ZEROS;
  signal WORD: bit_vector(15 downto 0);
  signal WORD_0: integer;
begin
  WORD_0 <= COUNT_ZEROS("01101001");
  process(...)
  begin
    if COUNT_ZEROS(WORD) > 0 then
       ...
    end if;
    ...
  end process;
end EXAMPLE;
  • (Im)pure declaration optional (default: ‘pure’ = VHDL’87)
  • Body split into declarative and definition part (cf. process)
  • Unconstrained parameters possible (array size remains unspecified)
  • Are used as expression in other VHDL statements (concurrent or sequential)

Notes

The keyword ’pure’ can be used for “oldstyled” functions, the keyword ’impure’ declares the new VHDL’93 function type. By default, i.e. if no keyword is given, functions are declared as PURE. A PURE function does not have access to a shared variable, because shared variables are declared in the declarative part of an architecture and PURE functions do not have access to objects outside of their scope.

The code example shows a function that counts the number of ’0’s in a bit vector. Only parameters of mode ’in’ are allowed in function calls and are treated as ’constant’ by default. The size of the bit vector is not declared, i.e. a so called unconstrained formal parameter is used. Consequently, the subprogram code has to be written independently of the actual vector width. This can be done with the help of predefined attributes, like the attribute ’range’ in the example. This way, the FOR loop works for any vector size passed to the function. If a constrained array is used instead (e.g. bit_vector(15 downto 0)), the actual parameter will have to be of the same type, i.e. the type of the array elements and the size of the array must match. The directions of the array ranges may differ.

Functions may be used wherever an expression is necessary within a VHDL statement. Subprograms themselves, however, are executed sequentially like processes. Similar to a process, it is also possible to declare local variables. These variables are initialised with every function call with the leftmost element of the type declaration (boolean: false, bit: ’0’). The leftmost value of integers is guaranteed to be at least -(2^31)-1, i.e. ZEROS must be initialised to 0 at the beginning of the function body. It is recommended to initialise all variables in order to enhance the clarity of the code.

architecture EXAMPLE of PROCEDURES is
  procedure COUNT_ZEROS(A: in bit_vector;
               variable Q: out integer) is
    variable ZEROS : integer;
  begin
    ZEROS := 0;
    for I in A’range loop
      if A(I) =0then
        ZEROS := ZEROS + 1;
      end if;
    end loop;
    Q := ZEROS;
  end COUNT_ZEROS;
 
  signal WORD: bit_vector(15 downto 0);
begin
  process(WORD)
    variable COUNT : integer;
  begin
    COUNT_ZEROS(WORD, COUNT);
    if COUNT > 0 then
      ...
    end if;
    ...
  end process;
end EXAMPLE;
  • No return value
  • Parameter values may be update (mode out/inout)
  • Body split into declarative and definition part (cf. process)
  • Unconstrained parameters possible (array size remains unspecified)
  • Are used as VHDL statements (concurrent or sequential)

Notes

Procedures, in contrast to functions, are used like any other statement in VHDL. Consequently, they do not have a return value, although the keyword ’return’ may be used to indicate the termination of the subprogram. Depending on their position within the VHDL code, either in an architecture or in a process, the procedure as a whole is executed concurrently or sequentially, respectively. The code within all subprograms is always executed sequentially.

Procedures can feed back results to their environment via an arbitrary number of output parameters. As the default mode of a parameter is ’in’, the keyword ’out’ or ’inout’ is necessary to declare output signals/variables. Per default, output parameters are of the class variable. The VHDL compiler will report an error message if a function declared with a signal as parameter is called with a variable and vice versa.

Since the class of the parameters have to match, one might think of overloading a procedure, i.e. by writing procedures that differ in the class declaration of the parameters and the corresponding assignment operators, only. Yet this is not possible because the parameter class is ignored when the appropriate subprogram is selected!

The example procedure is the equivalent of the previously presented function for counting the ’0’ elements within a bit_vector. Again, all internal variables should be initialized because subprograms do not store variable values and initialize them with type’left at each call instead.

Fuction Procedure
mode: in in out/inout
class: constant, signal constant, signal, variable variable, signal
no mode: file file file
  • Formal parameters (parameter declaration)
    • Default mode: IN
    • Default parameter classes for mode IN: constant, for mode OUT/INOUT: variable
    • File parameters have no mode
  • Actual parameters (subprogram call)
    • Must match classes of formal parameter
    • Class constant matches actual constants. signals or variables
Function parameters are always of mode IN and can not be declared as variables

Notes

The IMPURE mechanism and the existence of global objects in VHDL’93 allows to open the file somewhere in the VHDL code and to read character after character by a function call. Another good example is the implementation of a random number generator which returns a different value each time it is called. Of course, the random numbers could be read from a file, then.

As to entity ports, subprogram parameters have a certain mode associated with them. The default mode is IN, i.e. these objects can be read only. Signal attributes (event’, ’last_value’, etc.) are only available if the formal parameter (i.e. in the declaration part of the subprogram) has been declared as signal. Please note that the use of the signal attributesstable’, ’quiet’, ’transaction’ and ’delayedis forbidden.

Actual parameters are the ones used in the subprogram call and are treated as constants by default. The classes of the formal and actual parameters must match. So it is an error if a parameter is declared as signal and a variable is used as actual parameter in the call. Parameters of type ’constant’ are an exception as they match all possible types.


Chapters of System Design > VHDL Language and Syntax