如何 return 从函数中使用不受约束的二维数组进行记录

How to return record with unconstrained 2d array from a function

我有一个记录类型 (REC),它包含一个类型为 VECTOR 的元素,它是 STD_LOGIC:

的无约束二维数组

package TEST is

    type VECTOR is array (NATURAL range <>, NATURAL range <>) of STD_LOGIC;

    type REC is record

        data : VECTOR;

    end record REC;

    function con(
        a : REC;
        b : REC)
        return REC;

end package TEST;

在声明 con 函数的主体时,我想指定 REC.data 数组的大小,如下所示:


package body TEST is

    function con(
     a : REC;
     b : REC)
        return REC is variable r : REC(
            data(a.data'length(1) + b.data'length(1) - 1 downto 0, a.data'length(2) - 1 downto 0));

        begin

            -- . . . do things

    end function con;

end package body TEST;

但在我尝试设置数据大小的行中,Vivado 抛出以下错误:

Sliced name is allowed only on single-dimensional arrays

这是否意味着我不能在记录中进行不受约束的 2d 提审,或者是否有不同的方法在 con 函数中定义它的大小?

---- 编辑----

既然我现在明白在这种情况下不可能使用二维数组,我应该使用什么方法来创建一个函数:

这是PoC's vectors package, see lines starting at 359行列合并的定义:

    function slm_merge_rows(slm1 : T_SLM; slm2 : T_SLM) return T_SLM is
        constant ROWS     : positive    := slm1'length(1) + slm2'length(1);
        constant COLUMNS  : positive    := slm1'length(2);
        variable slm      : T_SLM(ROWS - 1 downto 0, COLUMNS - 1 downto 0);
    begin
        for i in slm1'range(1) loop
            for j in slm1'low(2) to slm1'high(2) loop         -- WORKAROUND: Xilinx iSIM work-around, because 'range(2) evaluates to 'range(1); see work-around notes at T_SLM type declaration
                slm(i, j)   := slm1(i, j);
            end loop;
        end loop;
        for i in slm2'range(1) loop
            for j in slm2'low(2) to slm2'high(2) loop         -- WORKAROUND: Xilinx iSIM work-around, because 'range(2) evaluates to 'range(1); see work-around notes at T_SLM type declaration
                slm(slm1'length(1) + i, j)    := slm2(i, j);
            end loop;
        end loop;
        return slm;
    end function;

    function slm_merge_cols(slm1 : T_SLM; slm2 : T_SLM) return T_SLM is
        constant ROWS     : positive    := slm1'length(1);
        constant COLUMNS  : positive    := slm1'length(2) + slm2'length(2);
        variable slm      : T_SLM(ROWS - 1 downto 0, COLUMNS - 1 downto 0);
    begin
        for i in slm1'range(1) loop
            for j in slm1'low(2) to slm1'high(2) loop         -- WORKAROUND: Xilinx iSIM work-around, because 'range(2) evaluates to 'range(1); see work-around notes at T_SLM type declaration
                slm(i, j)   := slm1(i, j);
            end loop;
            for j in slm2'low(2) to slm2'high(2) loop         -- WORKAROUND: Xilinx iSIM work-around, because 'range(2) evaluates to 'range(1); see work-around notes at T_SLM type declaration
                slm(i, slm1'length(2) + j)    := slm2(i, j);
            end loop;
        end loop;
        return slm;
    end function;

T_SLM的定义是:

type T_SLM is array(natural range <>, natural range <>) of std_logic;

目前,我认为将此代码嵌套在另一层(如您的无约束记录)没有问题。


编辑:

以上代码需要在 Vivado 中启用 VHDL 2008。

When VHDL files are added to Vivado, it's by default set to use VHDL 93, but not 2008. Go to the property Window and change the file type from VHDL to VHDL 2008``.
The printed error message is misleading and points to a false feature being used. The correct message should be it's a VHDL-2008 feature, please enable it.

user1155120 I don't think I fully understand what you are trying to say. Are you saying my code is not
a minimal reproducible example, because except for me forgetting to include the STD_LOGIC library
the code reproduces the problem when I paste it into Vivado, and it is about as minimal as I can get it.
Or are you saying that the code you linked as this works works for you, because at least in my
Vivado it still throws the same error ? – Mercury 4 hours ago

原评论是给 Tricky 的。函数 con 中缺少 return 语句,这会阻止在示例中使用。

不清楚 Vivado 模拟器是否支持记录约束(-2008 功能)。在Vivado Synthesis Guide UG901 2020.1中,我们看到了记录类型的各种精彩用法,从一切到推断ram到记录类型的记录元素。 Xilinx 一直很忙。

如果支持记录类型声明中的无约束元素但不支持记录约束,这似乎很奇怪(它们几乎是一揽子交易,双关语)。请注意评论称其为 -2008 功能。

记录约束仅限于提供不受约束类型(通常为数组)的元素或子元素的约束。 VHDL 一直能够提供多维数组约束。基于语法的灵活性,标准的语言是特定的。

此代码符合 VHDL -2008 标准并提供您的记录约束:

library ieee;                  -- ADDED for MCVe
use ieee.std_logic_1164.all;   -- ADDED

package TEST is
    type VECTOR is array (NATURAL range <>, NATURAL range <>) of STD_LOGIC;

    type REC is record
        data: VECTOR;
    end record REC;
    
    function con (a: REC; b: REC) return REC;
end package TEST;

package body TEST is
    function con (a: REC; b: REC) return REC is 
        variable r: 
            REC (         -- record constraint:
              data (
                natural range a.data'length(1) + b.data'length(1) - 1 downto 0,
                natural range a.data'length(2) - 1 downto 0
              )
          );
    begin
        -- . . . do things 
        return r;     -- ADDED required return statement
    end function con;
end package body TEST;

您会注意到您对记录约束的更改是在元素数据约束的每个范围之前添加 natural range

来自 IEEE Std 1076-2008 5.3.3 记录类型:

record_constraint ::=
    ( record_element_constraint { , record_element_constraint } )

record_element_constraint ::= record_element_simple_name element_constraint

来自 6.3 子类型声明:

element_constraint ::=
      array_constraint
    | record_constraint

这里的元素数据是一个数组,所以array_constraint是合适的。

从 5.3.2 数组类型,5.3.2.1:

array_constraint::=

    index_constraint [ array_element_constraint ]
    | ( open ) [ array_element_constraint ]

因为元素数据数组元素是标量(枚举类型STD_LOGIC)所以我们遵循index_constraint.

index_constraint ::= ( discrete_range { , discrete_range } )

discrete_range ::= discrete_subtype_indication | range

上面显示的代码对元素数据维度的索引范围使用离散子类型指示并成功分析(编译)。

从 5.2.2 标量类型,5.2.2.1:

range ::=
      range_attribute_name
    | simple_expression direction simple_expression

direction ::= to | downto

问题中的约束使用了一个具有简单表达式和方向的范围。

那么为什么会出现关于多维切片的错误信息呢?

在9. Expressions, 9.1 BNF, simple_expression -> term -> factor -> primary -> name.

在 8. Names, 8.1 name -> slice_name, 只有多维切片在 8.5 语义上是不允许的 BNF 告诉我们它在语法上有效的切片名称:

slice_name ::= prefix ( discrete_range )

The prefix of a slice shall be appropriate for a one-dimensional array object. The base type of this array type is the type of the slice.

并且在语义上前缀 data 不适合一维数组对象。

这些评论为问题提供了更多背景信息,但不清楚您在报告的最终成功中使用了哪个版本的记录约束:

@Mercury when you add a (VHDL) file to Vivado, it's by default set to use VHDL 93, but not 2008. Go
to the property Window and change the file type from VHDL to VHDL 2008. I'm not sure why it
prints the wrong error message in your case. (Vivado likes to confuse users with wrong error messages
...). Anyhow, it should have reported your feature is only supported in 2008 mode. – Paebbels 3 hours
ago

@Paebbels Thank you, that fixed the problem, maybe add it as a sub note to your response so I can
mark it as accepted answer. You just saved me hours of frustration. And I'm already getting familiar with
Vivado's shenanigans, my Favorit one of which is "ERROR close to ..." which has to be one of the most
useless error messages I have experience in a long time :) – Mercury 3 hours ago

就检测-2008来源而言,无论是主单元还是副单元,都没有-1993语法错误,也没有-2008新的保留字、定界符、分隔符或图形字符。

这让你任由失败的语义分析摆布。您还可能注意到,在分析包声明期间未报告不受约束的记录元素。它发生在评估变量 r 期间。所有声明的对象都需要被约束。 VHDL 不包含所有功能,语义也可能具有限制性。在某些地方拥有不受约束的元素和对象是合法的。

将标准文本中的语义规则与特定声明或声明的文本元素相关联可能很困难,而且吱吱作响的轮子会得到润滑剂。记录约束对于 VHDL 实现来说相对较新。

问题似乎是对工具的熟悉程度。