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 使用。
我想知道这个或类似的东西是否可行:
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 GeneralAn 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 使用。