VHDL 中的递归 'type' 声明

Recursive 'type' declaration in VHDL

我想知道这个或类似的东西是否可行:

package my_package is
  constant my_constant:integer:=4;
  type array_type1 is array(my_constant-1 downto 0)of integer;
  constant constant_array1:array_type1:=(62,47,28,76);
  --And here is the experimental part:
  for i in 0 to my_constnat-1 loop
    type array_type2 is array(my_constant-1 downto 0)of string(1 to constant_array1(i));
  end loop;
  constant constant_array2:array_type2:=(
    "Hello my name is Doron and I'm the developer of this project.",--62 characters.
    "Another sentence, with 47 characters at total.",
    "So it's range is '1 to 47'.",
    "And the range of this sentence is: '1 to <last-number-in-constant_array1>'."
  );
end my_package;

我的最终目的是创建一个字符串数组,每个字符串的长度都不同。希望这个数组将在项目的不同文件中使用,只需声明:

use work.my_package.all;

但我收到以下错误:

Error (10500): VHDL syntax error at txt-utilities.vhd(16) near text "for"; expecting "end", or a declaration statement

感谢任何帮助。

来自 IEEE 标准 1076-2008:

5.3.2 Array types
5.3.2.1 General

An array object is a composite object consisting of elements that have the same subtype.

子类型提供了约束。在作为数组约束的数组类型的上下文中(参见 6.3 子类型声明5.3.2 数组类型)这是一个范围。

因此作为数组元素的数组必须具有与任何其他元素相同的范围,并且您的方法无法工作(正如 Paebbels 指出的那样)。

至少有一种索引字符串的替代方法

如果类型标记是基类型,则函数可以 return 它的 return 类型的任何子类型的任何值。

这可以通过以下方式证明:

package my_package is
    constant my_constant:   integer := 4;
    function my_string (index: natural) return string;
end package;

package body  my_package is
    function my_string (index: natural) return string is
        begin
            assert index < my_constant 
                report "my_string(" & integer'image(index) &") provides a range of elements greater than my_constant"
                severity ERROR;
            case index is
                when 0 =>
                    return "Hello my name is Doron and I'm the developer of this project.";
                when 1 =>
                    return "Another sentence, with 47 characters at total.";
                when 2 => 
                    return  "So it's range is '1 to 47'.";
                when 3 => 
                    return "And the range of this sentence is: '1 to <last-number-in-constant_array1>'.";
                when others => 
                    return "<ERROR>";
            end case;
        end function;
end package body;

use work.my_package.all;

entity foo is
end entity;

architecture fum of foo is
    constant my_string0: string (my_string(0)'range) := my_string(0);
begin 
    process
    begin
        report my_string0;
        report "my_string0'length = " &integer'image(my_string0'length);
        for i in 1 to my_constant loop  -- this will provide a call out of range
            report my_string(i);
            report "my_string(" &integer'image(i) &") length = " &integer'image(my_string(i)'length);
        end loop;
        wait;
    end process;
end architecture;

封装和演示VHDL代码分析、阐述和运行产生时:

ghdl -r foo
my_package.vhdl:37:9:@0ms:(report note): Hello my name is Doron and I'm the developer of this project.
my_package.vhdl:38:9:@0ms:(report note): my_string0'length = 61
my_package.vhdl:40:13:@0ms:(report note): Another sentence, with 47 characters at total.
my_package.vhdl:41:13:@0ms:(report note): my_string(1) length = 46
my_package.vhdl:40:13:@0ms:(report note): So it's range is '1 to 47'.
my_package.vhdl:41:13:@0ms:(report note): my_string(2) length = 27
my_package.vhdl:40:13:@0ms:(report note): And the range of this sentence is: '1 to '.
my_package.vhdl:41:13:@0ms:(report note): my_string(3) length = 75
my_package.vhdl:9:13:@0ms:(assertion error): my_string(4) provides a range of elements greater than my_constant
my_package.vhdl:40:13:@0ms:(report note): <ERROR>
my_package.vhdl:9:13:@0ms:(assertion error): my_string(4) provides a range of elements greater than my_constant
my_package.vhdl:41:13:@0ms:(report note): my_string(4) length = 7

my_string0 的常量声明显示了如何在对象声明中使用函数调用。

您可能会注意到您对字符串长度的期望似乎与 VHDL 不匹配,您一直说它们长了 1。VHDL 没有字符串信号的带内结束。

大胆猜测,您正在集中定义一些可以为特定用途编制索引的字符串。上面的函数可以做到这一点。

使用常量字符串数组

如果要设置最长常量字符串的最大长度的字符串数组,您可以使用函数将 return 字符串缩减为以下长度:

package my_package is
    constant my_constant:   natural := 4;
    constant LONGEST_STRING: natural := 75;

    function my_string (index: natural) return string;
end package;

package body my_package is
    type array_type1 is array(0 to my_constant - 1) of integer;

    constant constant_array1: array_type1 := (62, 47, 28, 76);

    type array_type2 is array (natural range 0 to my_constant - 1) of string (1 to LONGEST_STRING);

    constant constant_array: array_type2 := (
        0 => ("Hello my name is Doron and I'm the developer of this project."
               & string'(constant_array1(0) to LONGEST_STRING => ' ')),
        1 => ("Another sentence, with 47 characters at total."
               & string'(constant_array1(1) to LONGEST_STRING => ' ')),
        2 => ("So it's range is '1 to 47'." 
            & string'(constant_array1(2) to LONGEST_STRING => ' ')),
        3 => ("And the range of this sentence is: '1 to <last-number-in-constant_array1>'.")
    );

    function my_string (index: natural) return string is
    begin
        assert index < my_constant 
            report "my_string(" & integer'image(index) &") provides a range of elements greater than my_constant"
            severity ERROR;
        if index >= my_constant then
            return "<ERROR>";
        else
            return constant_array(index)(1 to constant_array1(index) - 1);
        end if;
    end function;
end package body;

use work.my_package.all;

entity foo is
end entity;

architecture fum of foo is
    constant my_string0: string (my_string(0)'range) := my_string(0);
begin 
    process
    begin
        report my_string0;
        report "my_string0'length = " &integer'image(my_string0'length);
        for i in 1 to my_constant loop  -- this will provide a call out of range
            report my_string(i);
            report "my_string(" &integer'image(i) &") length = " &integer'image(my_string(i)'length);
        end loop;
        wait;
    end process;
end architecture;

当 运行 这产生与第一个示例基本相同的输出,尽管在来自各种报告语句的标准输出中具有不同的行号和字符指针。

一种可能性是将所有字符串存储在一个 "super string" 中,并用一些魔术字符或字符串(在下面的示例中为 |)将它们分隔开。然后,您可以使用 string_ops package from VUnit(我是作者之一)将该长字符串拆分为其组件。

另一种选择是使用冻结字典类型 here,它是一个包含 key/value 对

的字符串
"key1 : value1, key2 : value2"

这允许您通过键而不是使用索引来获取字符串。下面是一个 VUnit testbench showing/verifying 这个。如果您想了解有关这些软件包的更多信息,可以查看它们的测试平台 here and here.

library vunit_lib;
context vunit_lib.vunit_context;

package my_package is
  constant my_strings : string := "Hello my name is Doron and I'm the developer of this project.|" &
                                  "Another sentence, with 47 characters at total.|" &
                                  "So it's range is '1 to 47'.|" &
                                  "And the range of this sentence is: '1 to <last-number-in-constant_array1>'.";

  constant my_dictionary : frozen_dictionary_t := "who am I : Hello my name is Doron and I'm the developer of this project.," &
                                                  "foo : Another sentence,, with 47 characters at total.," &
                                                  "bar : So it's range is '1 to 47'.," &
                                                  "spam : And the range of this sentence is:: '1 to <last-number-in-constant_array1>'.";
end package my_package;

library vunit_lib;
context vunit_lib.vunit_context;

use work.my_package.all;

entity tb_test is
  generic (
    runner_cfg : runner_cfg_t);
end tb_test;

architecture tb of tb_test is

begin
  test_runner : process
    variable string_list : lines_t;
  begin
    test_runner_setup(runner, runner_cfg);

    while test_suite loop
      if run("Test that variable length strings can be stored in a super string") then
        string_list := split(my_strings, "|");
        assert string_list(0).all = "Hello my name is Doron and I'm the developer of this project.";
        assert string_list(1).all = "Another sentence, with 47 characters at total.";
        assert string_list(2).all = "So it's range is '1 to 47'.";
        assert string_list(3).all = "And the range of this sentence is: '1 to <last-number-in-constant_array1>'.";
      elsif run("Test that variable length strings can be stored in a dictionary") then
        assert get(my_dictionary, "who am I") = "Hello my name is Doron and I'm the developer of this project.";
        assert get(my_dictionary, "foo") = "Another sentence, with 47 characters at total.";
        assert get(my_dictionary, "bar") = "So it's range is '1 to 47'.";
        assert get(my_dictionary, "spam") = "And the range of this sentence is: '1 to <last-number-in-constant_array1>'.";
      end if;
    end loop;

    test_runner_cleanup(runner);
    wait;
  end process test_runner;
end;

d:\examples\array_of_variable_strings>python run.py
Starting lib.tb_test.Test that variable length strings can be stored in a super string
pass (P=1 S=0 F=0 T=2) lib.tb_test.Test that variable length strings can be stored in a super string (1.0 seconds)

Starting lib.tb_test.Test that variable length strings can be stored in a dictionary
pass (P=2 S=0 F=0 T=2) lib.tb_test.Test that variable length strings can be stored in a dictionary (0.9 seconds)

==== Summary =========================================================================================
pass lib.tb_test.Test that variable length strings can be stored in a super string (1.0 seconds)
pass lib.tb_test.Test that variable length strings can be stored in a dictionary   (0.9 seconds)
======================================================================================================
pass 2 of 2
======================================================================================================
Total time was 1.9 seconds
Elapsed time was 1.9 seconds
======================================================================================================
All passed!

d:\examples\array_of_variable_strings>

正如其他人所说,没有一个简单的解决方案可以创建参差不齐的数组(具有不同大小的二维)。

OTOH,有很多创造性的解决方案。我在 OSVVM 中做的是使用一个指向字符串的指针数组。以下是作为 OSVVM 一部分的 MessagePkg 的简化版本。有关比下面的代码具有更多功能的完整示例,请参阅 http://osvvm.org

package MessagePkg is
  type MessagePType is protected
    procedure Set (MessageIn : String) ;
    impure function Get (ItemNumber : integer) return string ; 
    impure function GetCount return integer ; 
  end protected MessagePType ;
end package MessagePkg ;

package body MessagePkg is
  type MessagePType is protected body
    variable MessageCount : integer := 0 ; 
    constant MAX_MESSAGES : integer := 16 ; 
    -- type line is access string ; -- from std.textio
    type LineArrayType is array (natural 1 to MAX_MESSAGES) of line ; 
    variable MessageVar : LineArrayType ; 

    ------------------------------------------------------------
    procedure Set (MessageIn : String) is
    ------------------------------------------------------------
    begin
      MessageCount := MessageCount + 1 ; 
      assert MessageCount <= MAX_MESSAGES report "too many messages" severity FAILURE ; 
      MessageVar(MessageCount) := new string'(MessageIn) ;
    end procedure Set ; 

    ------------------------------------------------------------
    impure function Get (ItemNumber : integer) return string is
    ------------------------------------------------------------
    begin
      assert ItemNumber > 0 and ItemNumber <= MessageCount report "Get Index out of range" severity FAILURE ; 
      return MessageVar(ItemNumber).all ; 
    end function Get ; 

    ------------------------------------------------------------
    impure function GetCount return integer is 
    ------------------------------------------------------------
    begin
      return MessageCount ; 
    end function GetCount ; 
  end protected body MessagePType ;
end package body MessagePkg ;

要使用 MessagePType,您需要创建一个共享变量:

shared variable Message : MessagePType ; 
. . .
Message.Set("MessagePkg is part of OSVVM.");
Message.Set("OSVVM is a library of packages that provide next generation");
Message.Set("verification capabilty");
Message.Set("While the library implements constrained random and functional coverage, just like other languages");
Message.Set("It also implements a portable intelligent testbench capability that works in different simulators - something that Accellera is still working on");

要打印消息,您可以执行以下操作:

 for i in 1 to Message.GetCount loop 
   write(OUTPUT, message.get(i) & LF) ;
 end loop ; 

在OSVVM中,常量MAX_MESSAGES被一个变量代替,当超出时,内部存储会自动调整大小。在 OSVVM 中,MessagePkg.vhd 被 CoveragePkg.vhd 使用。