Reputation: 31
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
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 name
one` 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
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