【问题标题】:Evaluate Assert First when Simulating模拟时先评估 Assert
【发布时间】:2018-02-06 02:40:50
【问题描述】:

我的 VHDL 代码中有一个断言,用于验证通过我的组件实体传递的泛型。断言的严重性设置为 FAILURE,因为如果泛型被滥用,我想退出模拟。当使用 Active-HDL(实际上是任何版本,但我专门使用版本 12-14a)进行仿真时,当泛型被滥用并且仿真在执行任何其他操作之前退出时,断言会被命中。然而,当使用 ModelSim DE(我只尝试过 10.6c,32 位)进行模拟时,断言不是要评估的第一件事,并且对于与值相关的不同数组长度的信号分配会出现不同的错误泛型(这就是断言存在的原因)。这是我的 MCVE:

example.vhd:

library ieee;
use ieee.std_logic_1164.all;

entity example is
  generic
  (
    INPUT_LEN : integer := 4;
    OUTPUT_LEN : integer := 5
  );
  port
  (
    my_input : in std_logic_vector(INPUT_LEN-1 downto 0);
    my_output : out std_logic_vector(OUTPUT_LEN-1 downto 0)
  );
end entity example;

architecture rtl of example is
begin
  -- We want this evaluated first.
  assert (INPUT_LEN = OUTPUT_LEN)
    report "INPUT_LEN and OUTPUT_LEN must be equal!"
    severity FAILURE;

  -- This is actually what is evaluated first.
  my_output <= my_input;
end architecture rtl;

如您所见,my_outputmy_input 受泛型值的影响,我希望断言首先发生,以便将有用的错误消息打印到控制台,而不是当前的 @ 987654326@.

我使用以下两个 ModelSim 命令进行编译和仿真:

vcom -work work example.vhd

vsim -c -lib work example

我的问题是,是否有针对 vsim 的指令强制 ModelSim 先评估断言? 或者更广泛地说,在执行任何其他操作之前会查找和评估断言的命令? 似乎 Active-HDL 默认会执行此操作,但 ModelSim 不会...我查看了 vsim 的文档,并尝试了 -immedassert 标志,但这并没有改变任何东西。

我还在使用在很多不同地方使用的非常旧的代码(显然比我的 MCVE 复杂得多),所以最好的解决方案不是是修改源代码。

感谢您的帮助。

【问题讨论】:

  • 并发语句彼此异步执行。根据执行顺序是不可移植的,SystemVerilog 标志将无济于事。包括为并发语句详细说明的所有过程都在初始化期间执行,执行顺序在详细说明期间定义。不能保证依靠执行顺序来生成通用常量不匹配的特定消息。在测试台中为两个泛型使用一个值,使用在仿真前检查的命令文件(Modelsim 不支持 VHPI,回调将在进程之前执行)。
  • 这不是minimal reproducible example 没有通用常量的默认表达式,很容易修复。如果您颠倒 MCVe 中两个并发语句(断言语句和信号赋值语句)的顺序,您可能会看到您想要的结果。这是否适用于所有 Modelsim 详细模型是另一个问题。 ghdl 具有所需的执行顺序,而您的 MCVe 未更改(正如您为 Active-HDL 报告的那样)。
  • 我认为如果不修改源代码就无法做到这一点。至少,如果断言在源代码中。理想情况下,代码不应该依赖于特定于编译器的怪癖:如果确实如此,则可以将其视为编码反模式。
  • @user1155120 实体中的语句是否比架构中的语句具有更高的执行优先级?如果是这样,可以尝试将断言移动到实体声明中。
  • @Paebbels - 没有优先级,所有进程都是并发的。作为实体语句部分元素找到的被动过程的顺序将取决于实现并且也是不可移植的。

标签: vhdl modelsim


【解决方案1】:

所有并发语句都在进程语句或进程语句和块语句中详细说明。两个并发语句,信号分配和断言没有保证的执行顺序。依靠实现定义的明显排序会导致不可移植的设计描述。

断言仍然可以排序。在细化过程中可能会得到断言。

这可以通过添加(在这种情况下)一个函数来证明,该函数返回一个布尔值作为一个对象的初始值,该对象从未碰巧被使用过(并且会在综合过程中被消除):

library ieee;
use ieee.std_logic_1164.all;

entity example is
  generic
  (
    INPUT_LEN : integer := 4;
    OUTPUT_LEN : integer := 5
  );
  port
  (
    my_input : in std_logic_vector(INPUT_LEN-1 downto 0);
    my_output : out std_logic_vector(OUTPUT_LEN-1 downto 0)
  );
end entity example;

architecture rtl of example is
    function is_it_safe return boolean is
    begin
        assert (INPUT_LEN = OUTPUT_LEN)
          report "INPUT_LEN and OUTPUT_LEN must be equal!"
          severity FAILURE;
        return TRUE;
    end function;
    constant safe:    boolean := is_it_safe;
begin

    -- We want this evaluated first
    assert (INPUT_LEN = OUTPUT_LEN)
      report " ORIGINAL INPUT_LEN and OUTPUT_LEN must be equal!"
      severity FAILURE;

  -- This is actually what is evaluated first.
  my_output <= my_input;

end architecture rtl;

为泛型添加的默认值允许独立分析、阐述和模拟代码(作为最小、完整和可验证的示例)。

原始断言中的报告消息已更改,以便在任何实现不包含行号的情况下轻松识别。

因为两个泛型具有不同的默认值,所以肯定会导致断言:

ghdl -a example.vhdl
ghdl -e example
ghdl -r example
example.vhdl:20:9:@0ms:(assertion failure): INPUT_LEN and OUTPUT_LEN must be equal!
./example:error: assertion failed
./example:error: error during elaboration

第 20 行在函数 is_it_safe 中。

Modelsim 的顺序将保持不变,因为对象在仿真初始化之前就已详细说明(此时会出现一个错误或另一个错误)。请参阅 IEEE Std 1076-2008 14.4 声明的详细说明、14.4.2.5 对象声明和 14.7 模型的执行、14.7.5.2 初始化。

这里的想法是建立一个断言的有序单次执行,该断言最初是一个并发语句(详细说明为一个没有敏感列表的过程和一个没有子句的最终等待语句,请参阅 11.5 并发断言语句)。

请注意,到目前为止,没有任何答案可以回答有关如何影响 Modelsim 中的流程执行顺序的狭隘问题。

应该不可能命令并发语句执行。在模拟开始(14.7.5.2)之前执行的所有进程列表的顺序将是实现定义的且不可移植。原始海报已经证明了这一点。

在细化期间使用的函数中移动断言或提供新副本可以保证断言语句在初始化期间的任何赋值语句之前执行。

还请注意,正如 JHBonarius 评论的那样,测试相同类型的两个常量的值是否相等的断言的想法在某种程度上可以被视为一种反模式。一种从编程中采用的修复程序,与硬件描述几乎没有关系,仅用于在缺乏标准化错误消息时生成特定消息。

VHDL 已经在原始代码中发现了错误,尽管需要熟悉 VHDL 或工具实现。

通过提供对象值的函数中的断言,可以消除并发断言语句。

【讨论】:

    【解决方案2】:

    VHDL 是一种强类型语言。我不确定Modelsim 的构造是否让您首先运行断言。

    您可以尝试将 my_output my_output <= std_logic_vector(my_input),这将让 Modelsim 模拟您的设计,但一旦您尝试 RUN 您的设计,它将引发错误。

    如果没有类型转换,它甚至不会让您模拟您的设计。

    【讨论】:

      【解决方案3】:

      你可以通过把它放在一个进程中来实现顺序处理。示例:

      library ieee;
      use ieee.std_logic_1164.all;
      
      entity example is
          generic (
              INPUT_LEN : integer := 5;
              OUTPUT_LEN : integer := 6);
          port (
              my_input : in std_logic_vector(INPUT_LEN-1 downto 0);
              my_output : out std_logic_vector(OUTPUT_LEN-1 downto 0));
      end entity;
      
      architecture rtl of example is
      begin
          assign_my_output: process(my_input) begin
              assert (INPUT_LEN = OUTPUT_LEN)
                  report "INPUT_LEN and OUTPUT_LEN must be equal!"
                  severity FAILURE;
      
               my_output <= my_input;
          end process;
      end architecture rtl;
      

      vcom -work 工作示例.vhd

      vsim work.example

      运行 1 ns

      # ** 失败:INPUT_LEN 和 OUTPUT_LEN 必须相等!

      【讨论】:

      • 是的,我知道我正在编译库工作,而我一直在抱怨这个 modelsim 的“功能”。这种方式最简单:P
      • 有一些方法只能修改并发信号分配的等效过程。例如process begin wait for 0 ns; my_output &lt;= my_input; wait on my_input; 在分配 my_output 之前添加增量周期延迟以允许执行断言,my_input 可以分配给 my_output 分配中使用的中间信号,my_output 分配可以是块语句中的受保护信号分配,...跨度>
      猜你喜欢
      • 2020-03-29
      • 2020-06-06
      • 1970-01-01
      • 2020-05-20
      • 2015-07-26
      • 2014-03-31
      • 2017-03-24
      • 2017-08-11
      • 2016-07-21
      相关资源
      最近更新 更多