Ray D
Ray D

Reputation: 31

vhdl can't slice records

Can I not take a slice of an array of records? I declare a record like this:

type mytype is record
    one : std_logic;
    two : std_logic;
end record;
Type mytypes is array (natural range <>) of mytype;

define it like this:

signal mt : mytypes(3 downto 0);
signal slv : std_logic_vector (3 downto 0);

when I use it like this it's OK:

slv(0) <= mt(0).one;
slv(1) <= mt(1).one;

but this:

slv(0 to 1) <= mt(0 to 1).one;

gets the error

"record type mytypes is used but not declared"

So is it just not allowed to takes slices of records or do I need to write some extra code to enable it?

I should have said - Quartus II

Upvotes: 3

Views: 2522

Answers (2)

user1155120
user1155120

Reputation:

The VHDL standard is originally based on the Ada'83 LRM including record types. Both Ada and VHDL share strong typing and require (here in VHDL terminology) that for an extended name who's suffix is an element name declared in a record type declaration, the prefix be appropriate (denotes a value of the record type). See IEEE 1076-2008:

8.3 Selected names (paragraphs 3 & 4)

A selected name can denote an element of a record, an object designated by an access value, or a named entity whose declaration is contained within another named entity, particularly within a library, a package, or a protected type. Furthermore, a selected name can denote all named entities whose declarations are contained within a library or a package.

For a selected name that is used to denote a record element, the suffix shall be a simple name denoting an element of a record object or value. The prefix shall be appropriate for the type of this object or value.

That means

slv(0 to 1) <= mt(0 to 1).one;

produces an error (shall denotes a mandatory requirement, see 1.3 Structure and terminology of this standard).

The extended name here is mt(0 to 1).one, the suffix is the element nameone` and the prefix mt(0 to 1), a slice name is an array type whose elements are a record type. (8.5, "A slice name denotes a one-dimensional array composed of a sequence of consecutive elements of another one-dimensional array.")

The question's original poster has commented to an unaccepted answer that a working solution was found using a generate state which would produce multiple concurrent assignment statements:

SOME_LABEL:
    for i in 1 downto 0 generate
        slv(i) <= mt(i).one;
    end generate;

Where the suffix of the selected name mt(i) would be an indexed name (8.4 "An indexed name denotes an element of an array.").

You could note this simply evades the issue by not using a slice name.

One way to slice an array of records extracting an element from each would be through the use of a subprogram function, an expression returning a value (4. Subprograms and packages). The function would return subelement one from element of an array value of type mytypes specified by parameter:

    function mytypes_ones (inp: mytypes) return std_logic_vector is
        variable retv:  std_logic_vector(inp'range);
    begin
        for i in inp'range loop
            retv(i) := inp(i).one;
        end loop;
        return retv;
    end function;

The return value is a std_logic_vector value who's length is determined by the length of the array of elements of type mytypes.

The distinction between using a function and a generate statement includes providing an expression that allows a parameter that can be a slice name and allowing the return value to include subelements from multiple record elements. While the function requires a subprogram declaration and/or definition it's usage is as an expression which can help the functional description flow. A function can be be used in multiple function calls, while a generate statement is specific. Also a generate statement will elaborate to a block statement (14.5.3 Generate statements). One really useful distinction is that a function call can be used in a sequential assignment statement (e.g. in a process statement or subprogram).

Creating a Minimal, Complete, and Verifiable example using declarations found in the question:

library ieee;
use ieee.std_logic_1164.all;

entity mytypes_slices is
end entity;

architecture fum of mytypes_slices is
    type mytype is record
        one:        std_logic;
        two:        std_logic;
    end record;
    type mytypes is array (natural range <>) of mytype;
    signal mt:      mytypes (3 downto 0) := (
                        (one => '1', two => '0'),   -- mt(3)
                        (one => '1', two => '0'),   -- mt(2)
                        (one => '0', two => '0'),   -- mt(1)
                        (one => '1', two => '0')    -- mt(0)
                    );
    signal slv:     std_logic_vector (3 downto 0);
    signal slv1:    std_logic_vector (3 downto 0);

    function mytypes_ones (inp: mytypes) return std_logic_vector is
        variable retv:  std_logic_vector(inp'range);
    begin
        for i in inp'range loop
            retv(i) := inp(i).one;
        end loop;
        return retv;
    end function;

begin

    slv  (1 downto 0) <= mytypes_ones(mt)(1 downto 0); -- slice return value
    slv1 (1 downto 0) <= mytypes_ones(mt(1 downto 0)); -- slice parameter

MONITOR:
    process
    begin
        wait for 0 ns;  -- skip default values of slv, slv1, delta cycle delay
        report "slv(1 downto 0) = " & 
            character'value(std_ulogic'image(slv(1))) &
            character'value(std_ulogic'image(slv(0)));
        report "slv1(1 downto 0) = " & 
            character'value(std_ulogic'image(slv1(1))) &
            character'value(std_ulogic'image(slv1(0)));
        wait;
    end process;

end architecture;

ghdl -r mytypes_slices
mytypes_slices.vhdl:49:9:@0ms:(report note): slv(1 downto 0) = 01
mytypes_slices.vhdl:52:9:@0ms:(report note): slv1(1 downto 0) = 01

We can see a function call can be flexible as well. The assignment to slv uses a function call who's return value is sliced (8.1 "Certain forms of name (indexed and selected names, slice names, and attribute names) include a prefix that is a name or a function call."). The array type parameter value can also be sliced. Both expressions provide the same value.

You could also note the direction of slice names match the declared direction of their respective array types. The question OP contains an additional error:

slv(0 to 1) <= mt(0 to 1).one;

If the prefix were allowed to be a slice mt(0 to 1) would be a null slice (8.5 "The slice is a null slice if the discrete range is a null range. It is an error if the direction of the discrete range is not the same as that of the index range of the array denoted by the prefix of the slice name", 5.2 Scalar types, 5.2.1 paras 3-6, 5.3.2.2 Index constraints and discrete ranges). The direction doesn't match the direction found in the declaration of mt.

Upvotes: 2

Matthew
Matthew

Reputation: 13977

You can slice arrays of records

signal mt, mt2 : mytype(0 to 3);
mt2(0 to 1) <= mt(0 to 1);

but you can't do this:

slv(0 to 1) <= mt(0 to 1).one;

You will have to do this:

slv(0) <= mt(0).one;
slv(1) <= mt(1).one;

BTW: if you declare an array using downto you cannot slice it using to. The direction of the slice must match the direction of the declaration.

Upvotes: 2

Related Questions