我已经设法在VHDL中实现模拟超时。如果流程的运行时间更长,则MaxRuntime会被“杀死”。
不幸的是,这不相反。如果我的模拟在MaxRuntime之前完成,那么一切都在等待MaxRuntime上的最后一个等待语句。
我发现可以将wait on
,wait for
和wait until
语句合并为一个。
我目前在代码段中的代码。一个完整的例子很长......
package sim is
shared variable IsFinalized : BOOLEAN := FALSE;
procedure initialize(MaxRuntime : TIME := TIME'high);
procedure finalize;
end package;
package body sim is
procedure initialize(MaxRuntime : TIME := TIME'high) is
begin
-- do init stuff
if (MaxRuntime = TIME'high) then
wait on IsFinalized for MaxRuntime;
finalize;
end if;
end procedure;
procedure finalize;
begin
if (not IsFinalized) then
IsFinalized := TRUE;
-- do finalize stuff:
-- -> stop all clocks
-- write a report
end if;
end procedure;
end package body;
entity test is
end entity;
architecture tb of test is
begin
initialize(200 us);
process
begin
-- simulate work
wait for 160 us;
finalize;
end process;
end architecture;
如果IsFinalized
发生更改,则不会退出等待语句。我的模拟运行大约160 us。如果我将MaxRuntime
设置为50 us,模拟将停止在大约50 us(加上一些额外的循环,直到每个过程都注意到停止条件)。当我将MaxRuntime
设置为200 us时,模拟将退出200 us,而不是162 us。
我不想使用命令行开关为模拟器设置最长执行时间。
答案 0 :(得分:4)
因此,您可能希望在超时或超时之前完成测试时终止模拟。当事件队列为空时,模拟器将停止是正确的,但是这也是非常高的,正如您所经历的那样。
VHDL-2008在std.env
包中引入了stop
和finish
,用于停止或终止模拟。
在VHDL-2002中,一种常见的方法是使用assert
severity FAILURE
停止模拟:
report "OK ### Sim end: OK :-) ### (not actual failure)" severity FAILURE;
此模拟停止方法基于以下事实:当assert
出现severity FAILURE
时,模拟器(例如ModelSim)通常会停止模拟。
答案 1 :(得分:3)
的
VHDL中的所有顺序语句都是原子的。
等待语句恰好等到恢复条件满足,等待信号事件,信号表达或模拟时间。
如果您可以退出/中止,您将使用什么来选择进程恢复的语句?它会恢复吗?您无法执行语句序列。 VHDL不进行异常处理,它是事件驱动的。
这里值得记住的是,在模拟中执行的所有操作都是一个过程,函数调用是表达式,并且并发语句(包括过程调用)可能会在过程中通过限制范围的超级块语句转移到进程中
变量和信号之间存在这种基本差异(IEEE Std 1076-2008附录I术语表):
信号:具有过去历史记录值的对象。信号可能有多个驱动程序,每个驱动程序都有一个当前值和预计的未来值。术语信号是指由信号声明或端口声明声明的对象。 (6.4.2.3)
变量:具有单个当前值的对象。 (6.4.2.4)
你不能等待没有未来价值的东西,或者更简单的变量不发信号(来自字典 - 提供指定事件的冲动或机会的事件或陈述。
模拟由信号事件驱动,具体取决于未来的值。它定义了模拟时间的进展。时间是离散事件模拟的基础。
现在你可能想知道,如果他们声称VHDL是一种通用编程语言,有人会告诉你真相。如果你有能力任意破坏和恢复一个进程,那么如何通过离散时间事件保持正式指定硬件操作的能力呢?
所有这些告诉你,你可能会考虑使用信号而不是共享变量。
莫顿的停止和完成程序见于std.env。
答案 2 :(得分:3)
由于user1155120给出的原因,您不能等待变量。所以,你需要使用一个信号。 (包中的信号是全局信号)。
不幸的是,即使全局信号在范围内,它仍然需要是程序的输出参数,这是丑陋的。不仅如此,在您的代码中,您将从多个位置驱动信号,此全局信号需要是已解析的类型,例如std_logic。这也有点难看。
以下是代码的一个版本,其中共享变量由信号替换,布尔类型由std_logic替换,全局信号作为输出参数添加:
library IEEE;
use IEEE.std_logic_1164.all;
package sim is
signal IsFinalized : std_logic := '0';
procedure initialize(signal f : out std_logic; MaxRuntime : TIME := TIME'high);
procedure finalize (signal f : out std_logic);
end package;
package body sim is
procedure initialize(signal f : out std_logic; MaxRuntime : TIME := TIME'high) is
begin
-- do init stuff
if (MaxRuntime = TIME'high) then
wait on IsFinalized for MaxRuntime;
finalize(f);
end if;
end procedure;
procedure finalize (signal f : out std_logic) is
begin
if (IsFinalized = '0') then
f <= '1';
-- do finalize stuff:
-- -> stop all clocks
-- write a report
report "Finished!";
end if;
end procedure;
end package body;
use work.sim.all;
entity test is
end entity;
architecture tb of test is
begin
initialize(IsFinalized, 200 us);
process
begin
-- simulate work
wait for 160 us;
finalize(IsFinalized);
wait;
end process;
end architecture;
答案 3 :(得分:1)
从测试自动化的角度来看,使用停止/结束/断言失败可以强制测试停止是非常重要的。即使你的意图是通过不产生更多事件来使一切都终止,也存在导致一切都挂起的错误的风险。如果在较长的夜间测试中你的第一次测试中发生这种情况,你就会浪费很多时间。
如果你使用VUnit,它会像这样工作
library vunit_lib;
context vunit_lib.vunit_context;
entity tb_test is
generic (runner_cfg : runner_cfg_t);
end tb_test;
architecture tb of tb_test is
begin
test_runner : process
begin
test_runner_setup(runner, runner_cfg);
while test_suite loop
if run("Test that hangs") then
-- Simulate hanging test case
wait;
elsif run("Test that goes well") then
-- Simulate test case running for 160 us
wait for 160 us;
end if;
end loop;
test_runner_cleanup(runner); -- Normal forced exit point
end process test_runner;
test_runner_watchdog(runner, 200 us);
end;
挂起的第一个测试用例在200 us后由看门狗终止,以便第二个可以运行。
在强制测试台停止使用test_runner_cleanup
过程时可能遇到的问题是,当test_runner
进程到达test_runner_cleanup
进程时,您有一个或多个额外的测试进程需要做更多的事情{1}}程序调用。例如,如果你有这样的过程
another_test_process: process is
begin
for i in 1 to 4 loop
wait for 45 us;
report "Testing something";
end loop;
wait;
end process;
不允许运行所有四次迭代。最后一次迭代应该在180 us处运行,但test_runner_cleanup
在160 us处调用。
因此需要同步test_runner
和another_test_process
进程。您可以使用全局解析信号创建一个包来修复此问题(如前所述),但VUnit已经提供了一个可以用来节省时间的信号。 runner
是一个记录,其中包含VUnit测试平台的当前阶段。当调用test_runner_cleanup
时,它进入具有相同名称的阶段,然后移动到强制模拟停止的test_runner_exit
阶段。任何进程都可以通过放置临时锁来阻止VUnit进入或退出其阶段。更新后的another_test_process
会阻止VUnit退出test_runner_cleanup
阶段,直到完成所有迭代。
another_test_process: process is
begin
lock_exit(runner, test_runner_cleanup);
for i in 1 to 4 loop
wait for 45 us;
report "Testing something";
end loop;
unlock_exit(runner, test_runner_cleanup);
wait;
end process;
任何数量的进程都可以对某个阶段进行锁定,并且在所有锁定解锁之前阻止相变。您还可以使用get_phase
函数获取当前阶段,这在某些情况下可能很有用。
如果您正在开发可重复使用的组件,则可能不应该使用此技术。它为您节省了一些代码,但它也使您的组件依赖于VUnit而不是每个人都使用VUnit。正在努力: - )
免责声明:我是VUnit的作者之一。