【问题标题】:Recursive 'type' declaration in VHDLVHDL中的递归“类型”声明
【发布时间】:2015-09-25 05:51:46
【问题描述】:

我想知道这或类似的事情是否可能:

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

感谢任何帮助。

【问题讨论】:

  • 这不起作用,因为包中不允许使用 for 循环。其次,每个迭代都会覆盖array_type2
  • 要建议一个替代解决方案,你能告诉它的预期用途吗,例如是仿真还是综合,constant_array2是怎么用的?
  • 希望我想用它来合成。它应该是一个在液晶显示器上呈现这些句子的模块

标签: recursion vhdl


【解决方案1】:

来自 IEEE 标准 1076-2008:

5.3.2 数组类型
5.3.2.1 常规

数组对象是由具有相同子类型的元素组成的复合对象。

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

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

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

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

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

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): 大家好,我叫 Doron,我是这个项目的开发者。
my_package.vhdl:38:9:@0ms:(报告说明): my_string0'length = 61
my_package.vhdl:40:13:@0ms:(report note):另外一句,共47个字符。
my_package.vhdl:41:13:@0ms:(报告说明): my_string(1) 长度 = 46
my_package.vhdl:40:13:@0ms:(report note): 所以它的范围是 '1 到 47'。
my_package.vhdl:41:13:@0ms:(报告说明): my_string(2) 长度 = 27
my_package.vhdl:40:13:@0ms:(report note): 而这句话的范围是:'1 to '。
my_package.vhdl:41:13:@0ms:(报告说明): my_string(3) 长度 = 75
my_package.vhdl:9:13:@0ms:(断言错误): my_string(4) 提供了一个 大于 my_constant 的元素范围
my_package.vhdl:40:13:@0ms:(报告说明):
my_package.vhdl:9:13:@0ms:(断言错误): my_string(4) 提供的元素范围大于 my_constant
my_package.vhdl:41:13:@0ms:(report note): my_string(4) length = 7

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

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

冒险猜测,您无需集中定义一些可以索引以用于特定用途的字符串。上面的函数可以做到这一点。

使用恒定长度字符串数组

如果您要设置一个字符串数组,其最大长度为最长常量字符串,您可以使用函数将返回字符串缩减为长度:

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;

运行时,这将产生与第一个示例基本相同的输出,尽管不同报告语句的标准输出中的行号和字符指针不同。

【讨论】:

  • 谢谢user1155120,我有一个问题:一般在VHDL中,是否可以创建一个带有数组类型声明的包,它的范围将根据放入的值的数量自动确定它?就像在 C+ 和其他串行语言中一样..
  • 未绑定的数组类型定义可以在声明该类型的对象时提供索引约束(参见 5.3.2.1)。来自包装标准,type STRING is array (POSITIVE range &lt;&gt;) of CHARACTER;。在声明这样一个对象时,您可以根据提供的值提供子类型指示 - constant c1: STRING := B"1111_1111_1111"; RHS 上的表达式是类型的值并提供索引约束(1 到 12),其中 1 是 POSITIVE 中最左边的值, (下划线不是位串值的一部分)。
【解决方案2】:

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

另一种选择是使用冻结字典类型here,它是一个带有键/值对的字符串

"key1 : value1, key2 : value2"

这允许您通过键而不是使用索引来获取字符串。下面是一个显示/验证这一点的 VUnit 测试平台。如果您想了解有关这些软件包的更多信息,可以查看他们的测试平台 herehere

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>

【讨论】:

    【解决方案3】:

    正如其他人所说,没有一个简单的解决方案允许创建不规则数组的数组(具有不同大小的第二维)。

    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 中,CoveragePkg.vhd 使用 MessagePkg.vhd。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-11-29
      • 2011-07-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-11-04
      • 1970-01-01
      • 2017-06-18
      相关资源
      最近更新 更多