如何通过超时停止模拟?

时间:2016-02-09 21:05:45

标签: vhdl simulation

我已经设法在VHDL中实现模拟超时。如果流程的运行时间更长,则MaxRuntime会被“杀死”。

不幸的是,这不相反。如果我的模拟在MaxRuntime之前完成,那么一切都在等待MaxRuntime上的最后一个等待语句。

我发现可以将wait onwait forwait 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。

  • 如何退出/取消等待声明?
  • 为什么我不能等变量?

我不想使用命令行开关为模拟器设置最长执行时间。

4 个答案:

答案 0 :(得分:4)

因此,您可能希望在超时或超时之前完成测试时终止模拟。当事件队列为空时,模拟器将停止是正确的,但是这也是非常高的,正如您所经历的那样。

VHDL-2008在std.env包中引入了stopfinish,用于停止或终止模拟。

在VHDL-2002中,一种常见的方法是使用assert severity FAILURE停止模拟:

report "OK   ### Sim end: OK :-) ###   (not actual failure)" severity FAILURE;

此模拟停止方法基于以下事实:当assert出现severity FAILURE时,模拟器(例如ModelSim)通常会停止模拟。

答案 1 :(得分:3)

  • 如何退出/中止wait语句?
  • 为什么我不能等变量?

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;

http://www.edaplayground.com/x/VBK

答案 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后由看门狗终止,以便第二个可以运行。

Time-out

在强制测试台停止使用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处调用。

Premature exit

因此需要同步test_runneranother_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;

Exit lock

任何数量的进程都可以对某个阶段进行锁定,并且在所有锁定解锁之前阻止相变。您还可以使用get_phase函数获取当前阶段,这在某些情况下可能很有用。

如果您正在开发可重复使用的组件,则可能不应该使用此技术。它为您节省了一些代码,但它也使您的组件依赖于VUnit而不是每个人都使用VUnit。正在努力: - )

免责声明:我是VUnit的作者之一。