VHDL 标准最初基于 Ada'83 LRM,包括记录类型。 Ada 和 VHDL 都共享强类型并要求(在此使用 VHDL 术语)对于后缀是在记录类型声明中声明的元素名称的扩展名称,前缀是适当的(表示记录类型的值)。参见 IEEE 1076-2008:
8.3 选定名称(第 3 和 4 段)
选定的名称可以表示记录的元素、由访问值指定的对象或命名实体,其声明包含在另一个命名实体中,特别是在库、包或受保护类型中。此外,选定的名称可以表示其声明包含在库或包中的所有命名实体。
对于用于表示记录元素的选定名称,后缀应是表示记录对象或值的元素的简单名称。前缀应适合此对象或值的类型。
意思是
slv(0 to 1) <= mt(0 to 1).one;
产生错误(应表示强制性要求,参见本标准的 1.3 结构和术语)。
这里的扩展名是mt(0 to 1).one, the suffix is the element nameone`和前缀mt(0 to 1),切片名是一个数组类型,其元素是一个记录类型。 (8.5,“切片名称表示一个一维数组,由另一个一维数组的一系列连续元素组成。”)
该问题的原始发布者评论了一个未接受的答案,即使用生成状态找到了一个可行的解决方案,该生成状态会产生多个并发的赋值语句:
SOME_LABEL:
for i in 1 downto 0 generate
slv(i) <= mt(i).one;
end generate;
其中所选名称的后缀 mt(i) 将是索引名称(8.4“索引名称表示数组的元素。”)。
您可能会注意到,这只是通过不使用切片名称来回避问题。
对记录数组进行切片并从中提取元素的一种方法是使用子程序函数,即返回值的表达式(4. 子程序和包)。该函数将从参数指定的 mytypes 类型的数组值的元素中返回子元素 one:
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;
返回值是一个 std_logic_vector 值,其长度由mytypes 类型的元素数组的长度决定。
使用函数和生成语句之间的区别包括提供一个表达式,该表达式允许参数可以是切片名称,并允许返回值包含来自多个记录元素的子元素。虽然该函数需要子程序声明和/或定义,但它的用法是作为可以帮助功能描述流程的表达式。一个函数可以在多个函数调用中使用,而生成语句是特定的。此外,生成语句将详细说明为块语句(14.5.3 生成语句)。一个真正有用的区别是函数调用可以在顺序赋值语句中使用(例如,在进程语句或子程序中)。
使用问题中的声明创建Minimal, Complete, and Verifiable example:
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:(报告说明): slv(1 down to 0) = 01
mytypes_slices.vhdl:52:9:@0ms:(报告说明): slv1(1 downto 0) = 01
我们可以看到函数调用也可以很灵活。对slv 的赋值使用一个函数调用,该函数调用的返回值被切片(8.1“某些形式的名称(索引和选定名称、切片名称和属性名称)包括一个前缀,即名称或函数调用。”)。数组类型参数值也可以切片。两个表达式提供相同的值。
您还可以注意到切片名称的方向与它们各自数组类型的声明方向相匹配。问题 OP 包含一个额外的错误:
slv(0 to 1) <= mt(0 to 1).one;
如果允许前缀是一个切片 mt(0 to 1) 将是一个空切片(8.5“如果离散范围是空范围,则切片是一个 空切片。如果离散范围的方向与切片名称前缀表示的数组的索引范围的方向不同”,5.2 标量类型,5.2.1 第 3-6 段,5.3.2.2 索引约束和离散范围) .方向与mt 声明中的方向不匹配。