PiCTo
PiCTo

Reputation: 974

VHDL - Function/Procedure for any type of array

Question:

How does one declare, if possible, a function intended for a parameter of any type T where the only constraint on T is that it was defined as a 1D array as in

type T is array ( integer range <> ) of a_random_type;

where a_random_type can be any type.

The following syntactically incorrect function is an example of what is desired

function measure_size_of_any_array ( a : array ( integer range <> ) ) return natural is
    variable r : natural := 0;
begin
    for i in a'range loop
        r := r + 1;
    end loop;
    return r;
end function;

which could then be used on any array

type natural_array is array ( integer range <> ) of natural;
type stdlogv_array is array ( integer range <> ) of std_logic_vector;

[...]

variable some_natural_array : natural_array;
variable some_stdlogv_array : stdlogv_array;

[...]

constant size_1 : natural := measure_size_of_any_array(some_natural_array);
constant size_2 : natural := measure_size_of_any_array(some_stdlogv_array);

Obviously, this question is about the way of defining the function and not about the function itself: I am not looking for a'length.


Possible Solution:

From Ashenden's VHDL-2008: Just the New Stuff

Generic types can be specified for subprograms.

We can declare a formal generic type in a generic list in the following way:

type indentifier

A function with a generic list takes the form:

function indentifier
    generic   ( ... )
    parameter ( ... ) return result_type is
    ... -- declarations
begin
    ... -- statements
end function identifier

which would allow the following definition

function measure_size_of_any_array
    generic   ( type arr_type )
    parameter ( arr : arr_type );

and the following use

function measure_size_of_natural_array is new measure_size_of_any_array
    generic ( arr_type => natural_array );
function measure_size_of_stdlogv_array is new measure_size_of_any_array
    generic ( arr_type => stdlogv_array );

constant size_1 : natural := measure_size_of_natural_array(some_natural_array);
constant size_2 : natural := measure_size_of_stdlogv_array(some_stdlogv_array);

This provides the desired behavior of sharing the body of the function among different calls, regardless of the type of the elements of the array but still requires an instantiated function (which can be as local as desired so it isn't that bad).

Because of how little support is being provided for VHDL-2008 by the main vendors (the previous solution wasn't understood by the compilers I tried), a VHDL-87, -93 or -2002 solution will be preferred.

Comment after receiving the first answers:

The previous information is my attempt to find a way of writing a VHDL subprogram accepting any argument as long as it is an array (i.e. to answer the initial question). The expected answer isn't necessarily supposed to use the same approach (namely using VHDL-2008 generic subprograms)!

Upvotes: 6

Views: 7073

Answers (2)

JHBonarius
JHBonarius

Reputation: 11291

Pre-2008, defining generics was only allowed at entity level. So you could pass generics to a function by making a special entity for that function. E.g.

entity function_ent is
    generic(return_value : natural);
    port(output : out natural);
end entity;

architecture func_def of function_ent is
    function measure_size_of_any_array return natural is
    begin
        return return_value;
    end function;
begin
    output <= measure_size_of_any_array;
end architecture;

However, you want to pass a type as a generic parameter... This is not possible <2008. So, you have to use VHDL-2008.

But when using generics in VHDL, you will always have to map a certain value (or type in vhdl-2008) to them. There is no smart (pre-)compiler that will automatically detect the input type, like in C++.

When you've eventually decided to use VHDL-2008, you can ask yourself: "will I ever use the function without defining an array first?" Likely not. So you might use a generic ("templated") package as something comparable to a C++ class. Example:

package array_pkg is
    generic (type element_type);

    type array_type is array (natural range <>) of element_type;

    function measure_size_of_array(
        arr : array_type) return natural;
end package;

package body array_pkg is
    function measure_size_of_array(
        arr : array_type) return natural is
    begin
        return arr'length;
    end function;
end package body;

entity test is
end entity test;

library ieee;

architecture beh of test is
    package natural_array_pkg is new work.array_pkg
        generic map (element_type => natural);

    signal test_sig1 : natural_array_pkg.array_type(0 to 10);
    constant test_out1 : natural := natural_array_pkg.measure_size_of_array(test_sig1);

    use ieee.std_logic_1164.all;

    package slv_array_pkg is new work.array_pkg
        generic map (element_type => std_logic_vector);

    signal test_sig2 : slv_array_pkg.array_type(0 to 12)(5 downto 0);
    constant test_out2 : natural := slv_array_pkg.measure_size_of_array(test_sig2);
begin

end architecture;

I think this is the closest you can get to templated parameters in current VHDL.

Upvotes: 4

Paebbels
Paebbels

Reputation: 16249

The implementation of generic types is very minimal in VHDL-2008. I have written up several pages of LRM changes to get better generic types in VHDL-2017. The new standard is going to be balloted on in a few months.

The change set is specified in LCS-2016-059.

function foo
  generic (
    type array_type is array(type is (<>)) of type is private
  )
  parameter (
    input    : array_type;
    selected : array_type'index
  )
  return array_type'element is
begin
  return input(selected);
end function;

Upvotes: 3

Related Questions