我正在尝试构建一个测试平台,每个测试用例由一个记录表示,该记录包含测试用例的所有参数,例如:输入文件名,用于DUT实例化的泛型& cetera。这个想法是只需要更改一个分配以在不同的测试用例之间切换。
type string_ptr is access string;
type test_case_t is record
input_file : string_ptr;
...
end record;
shared variable test_case_1 : test_case_t := (
input_file => new string'("path to input file 1")
...
);
shared variable TEST_CASE : test_case_t := test_case_1;
dut: my_module
generic map (
file_name => TEST_CASE.input_file.all
);
...
字符串指针用于input_file
,因为在记录类型声明中不允许使用无约束数组(在本例中为VHDL-2008之前的版本)。
由于test_case_t
中的字符串指针,我必须为test_case_1使用共享变量
但是,当我尝试在Xilinx ISE / ISim 14.4中模拟此测试平台时,模拟器会继续使用泛型的默认值,而不是我在测试平台中传递给它的值(我假设这是一个错误)。
我尝试用
来解决这个问题constant INPUT_FILE : string := TEST_CASE.input_file.all;
dut: my_module
generic map (
file_name => INPUT_FILE
);
...
这基本上是使用共享变量的初始值作为常量的初始值。但是,在模拟开始之前,这个任务将使Xilinx编译器崩溃(我假设的另一个错误)。
此时我根本不再相信Xilinx工具
我的问题是,如果共享变量可用于将通用值传递给模块,如上所示(第一个代码片段)?
此外,这种共享变量的使用是否适用于测试平台?我会使用test_case_1
的常量或信号,但由于在string_ptr
中使用test_case_t
类型,这似乎不允许。
答案 0 :(得分:2)
(总结并从评论中扩展......)放弃尝试将泛型映射到变量(或信号)。在运行时,泛型是常量。他们的价值观在精心制作时确定。
您是正确的,常量不能保持访问类型,并且您不能在记录中保存可变长度字符串。这是VHDL从Ada简化得太远的一个领域 - 后者具有区分记录,可以无缝处理可变长度字符串,无需访问类型。
一种方法是创建一个字符串表(字符串数组 - 或者如果您需要可变长度字符串,访问字符串数组)并将索引保存在记录中。
避免间接是好的。滥用变量需要常量......不太好。我的怪癖是避免访问类型的倾向,除非有充分的理由使用它们。
例如,在这里,我可以将空格填充的固定长度字符串直接存储在记录中," pad"用于从任意字符串填充记录成员的函数,以及" trim"功能在他们的使用点。与字符串表相比,这将删除两个间接级别。
subtype filename is string(1 to 100);
type test_case_t is record
input_file : filename;
...
end record;
function pad (name : string ) return filename;
function trim (name : filename ) return string;
constant test_case_1 : test_case_t := (
input_file => pad("path to input file 1"),
...
);
file_open(f, trim(test_case_1.input_file));
并且泛型可以是(子)类型文件名。因此,上面的大多数声明通常都在一个包中,在主测试平台和使用这种通用的任何实体中都使用。
答案 1 :(得分:1)
您可以将任何固定长度的字符串表达式作为通用常量的值作为通用映射中的实际值与具有未绑定子类型指示的类型字符串的形式相关联。
要理解为什么会这样,我们转向详细阐述仿制药。
IEEE Std 1076-2008(LRM):
14.3详细说明块,包或子程序标题
14.3.2通用条款
通用条款的详细说明包括按照给定的顺序详细说明该条款中包含的每个等效单一通用声明。通用声明的详细说明确定随后可以引用泛型。
6.5.6.2通用条款(第5段)
泛型类型表示的子类型由通用关联列表中的对应实际指定。如果没有为给定的正式泛型类型指定这样的实际值,则会出错(因为正式泛型是无关联的,或者因为实际是打开的)。
(并注意泛型的实际是一个表达式,关联列表是通用映射。另请注意,这并不符合Brian对字符串的子类型指示如何作为泛型的期望是什么根据他的Ada背景确定。)
这意味着:
entity my_module is
generic ( constant file_name: string := "default_string");
end entity;
architecture foo of my_module is
begin
UNLABELED:
process
begin
report "generic file_name = " & file_name;
wait;
end process;
end architecture;
entity foo is
end entity;
architecture fum of foo is
type string_ptr is access string;
type test_case_t is
record
input_file : string_ptr;
end record;
shared variable test_case_1 : test_case_t :=
(input_file => new string'("""path to input file 1"""));
shared variable TEST_CASE : test_case_t := test_case_1;
component my_module is
generic (
constant file_name: string := "default string"
);
end component;
begin
dut: my_module
generic map (
file_name => TEST_CASE.input_file.all
);
end architecture;
是合法的VHDL:
ghdl -a my_module.vhdl
ghdl -e foo
ghdl -r foo
my_module.vhdl:10:9:@ 0ms :(报告说明):generic file_name ="输入文件1的路径"
以及:
architecture fuu of foo is
-- type string_ptr is access string;
-- type test_case_t is
-- record
-- input_file : string_ptr;
-- end record;
-- shared variable test_case_1 : test_case_t :=
-- (input_file => new string'("""path to input file 1"""));
-- shared variable TEST_CASE : test_case_t := test_case_1;
component my_module is
generic (
constant file_name: string := "default string"
);
end component;
begin
dut: my_module
generic map (
file_name => """some other string""" -- TEST_CASE.input_file.all
);
end architecture;
给出了:
ghdl -a my_module.vhdl
ghdl -e foo
ghdl -r foo
my_module.vhdl:10:9:@ 0ms :(报告说明):generic file_name ="其他一些字符串"
所以这告诉我们一些事情。
ISIM在实现泛型方面并不完全符合标准。根据两种体系结构的不同,我们可以看到您的特定ISIM版本可能无法根据上面引用的6.5.6.2确定实际的子类型,并指出您正在尝试处理字符串子类型(长度)。 (如果有人指出Xilinx会修复它,你会发现它。)
您可以尝试不在实体声明的generic子句中提供默认表达式(注意组件声明应该匹配)。见6.5.6.2第4段:
通用常量的值可以由通用关联列表中的对应实际值指定。如果没有为给定的正式泛型常量指定这样的实际值(因为正式泛型不相关或因为实际是打开的),并且如果为该泛型指定了默认表达式,则此表达式的值是泛型的值。如果没有为给定的形式通用常量指定实际值并且相应的接口元素中不存在默认表达式,则会出错。如果复合形式通用常量的某些子元素已连接而其他子元素未连接或未关联,则会出错。
这是一种情况,如果它都不是错误。
还传播顶级常量或通用(由工具实现支持)需要通过每个连续分层块元素的泛型传递每个唯一值。这将需要正确实现支持6.5.6.2。 (见上文关于6.5.6.2第4段的内容)。
如果你非常聪明并且模拟和综合实现正确地支持配置声明,那么可能通过配置做一些事情(提供两个不同的使用子句和两个不同的包提供具有两个不同实际的组件声明通用子句 - 这也要求VHDL实现也支持6.5.6.2,也参见上面的第4段)。此方法允许您为不同的实际值集合模拟不同的配置。
答案 2 :(得分:0)
就像Brian说的那样,对于泛型,每次模拟运行都会遇到一个文件。这对于输出文件是可以的,但是,对于输入文件,您可能想要读取一个,然后读取另一个,依此类推。
我喜欢在模型中使用共享变量/受保护类型对象,如下所示:
library osvvm ;
architecture Test1 of Model1 is
use osvvm.NamePkg.all ;
shared variable FileName : NamePType ;
file TestFile : TEXT ;
begin
Functionality : process
begin
WaitForTransaction(. . .) ;
case ModelRec.Operation is
. . .
when OPEN_NEW_FILE =>
file_close(TestFile) ;
file_open(Status, TestFile, FileName.Get, READ_MODE);
然后,在将文件传递给此模型的测试台部分中,我使用外部名称来访问该文件:
architecture Test_Model1_1 of TestCtrl is
alias Model1FileName is <<variable
.tbmemio.U_Model1.FileName : NamePType>> ;
begin
. . .
Model1TestProc : process
begin
. . .
Model1FileName.set("Test1.txt") ;
. . .
NamePkg位于OSVVM库中,可以从http://osvvm.org/下载。