1

I have an assert in my VHDL code that validates generics passed through the entity of my component. The severity of the assert is set to FAILURE, because I want to quit the simulation if the generics are misused. When simulating with Active-HDL (really any version, but I've specifically used versions 12-14a), the assert is hit when the generics are misused and the simulation exits before doing anything else. When simulating with ModelSim DE (I've only tried 10.6c, 32-bit), however, the assert is not the first thing to be evaluated, and a different error appears for a signal assignment of different array lengths, related to the values of the generics (which is why the assert exists). Here is my 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;

As you can see, my_output and my_input are affected by the values of the generics, and I want the assert to happen first so that a helpful error message will be printed to the console, instead of the current Fatal: (vsim-3420) Array lengths do not match. Left is 32 (31 downto 0). Right is 8 (7 downto 0)..

I compile and simulate using the following two ModelSim commands:

vcom -work work example.vhd

vsim -c -lib work example

My question is, is there a directive for vsim that forces ModelSim to evaluate asserts first? Or more broadly, a command that will look for and evaluate asserts before doing anything else? It seems Active-HDL does it by default, but ModelSim doesn't... I've looked through the documentation for vsim and I've tried the -immedassert flag but that didn't change anything.

I'm also working with very old code that gets used in a lot of different places (and is obviously way more complex than my MCVE), so the best solution would not be to modify the source code.

Thanks for any help.

ezgoodey
  • 97
  • 1
  • 13
  • Concurrent statements execute asynchronously to each other. Depending on execution order is non-portable, SystemVerilog flags won't help. All processes including those elaborated for concurrent statements are executed during initialization, execution order implementation defined during elaboration. Counting on execution order to produce a specific message that generic constants don't match can't be guaranteed. Use one value in your testbench for both generics, use commands files that check before simulation (Modelsim doesn't support VHPI, callbacks would execute before processes). –  Feb 03 '18 at 03:28
  • It's not a [mcve] without default expressions for your generic constants, easy to fix. If you reverse the order of the two concurrent statements (the assertion statement and the signal assignment statement) in your MCVe you might see the results you desire. Whether or not that translates to all Modelsim elaborated models is another question. ghdl has the desired execution order with your MCVe unchanged (as you report for Active-HDL). –  Feb 03 '18 at 03:44
  • I don't think you can do this without modifying the source code. At least, if the asserts are in the source code. Ideally code should never depend on compiler-specific quirks: if it does that can be considered a coding anti-pattern. – JHBonarius Feb 04 '18 at 10:50
  • @user1155120 Have statements in the entity a higher execution priority than statements in the the architecture? If so, one could try to move the assert into the entity declaration. – Paebbels Feb 04 '18 at 17:30
  • @Paebbels - No priority all processes are concurrent. The order of passive processes found as entity statement part elements would be implementation dependent and also non-portable. –  Feb 04 '18 at 19:32

3 Answers3

2

All concurrent statements are elaborated in process statements or process statements and block statements. The two concurrent statements, the signal assignment and assertion have no guaranteed execution order. Counting on implementation defined apparent ordering results in a non-portable design description.

The assertion can still be ordered. It's possible to get assertions during elaboration.

This can be demonstrated by adding (in this case) a function that returns a boolean as an initial value for an object that never happens to get used (and would be eliminated during synthesis):

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;

The added default values for the generics allow the code to analyzed, elaborated and simulated stand alone (as a Minimal, Complete and Verifiable example).

The report message in the original assertion has been changed for easy identification in case any implementation doesn't include line numbers.

Because the two generics have different default values it's is guaranteed to cause an assertion:

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

Line 20 is in the function is_it_safe.

The ordering will hold for Modelsim because objects are elaborated before simulation initialization (where one error or the other occurs now). See IEEE Std 1076-2008 14.4 Elaboration of a declaration, 14.4.2.5 Object declarations and 14.7 Execution of a model, 14.7.5.2 Initialization.

The idea here is to establish an ordered single execution of an assertion that was originally a concurrent statement (which is elaborated into a process with no sensitivity list and a final wait statement with no clauses, See 11.5 Concurrent assertion statements).

Note no answer so far answers the narrow question on how to affect process execution order in Modelsim.

It should not be possible to order concurrent statement execution. The order of the list of all processes executed until they suspend at the beginning of simulation (14.7.5.2) would be implementation defined and non-portable. That's already been demonstrated by the Original Poster.

Moving the assertion or providing a new copy in a function used during elaboration can guaranteed the assertion statement is executed before any assignment statement during initialization.

Also note the idea of an assertion testing the equality of the values of two constants of the same type could be viewed as an anti-pattern somewhat as JHBonarius commented. A fix adopted from programming which has little to do with hardware description and only serves to produce a particular message in the face of a lack of standardized error messages.

VHDL will already catch the error in the original code albeit requiring VHDL or tool implementation familiarity.

With the assertion in a function providing an object value the concurrent assertion statement can be eliminated.

0

VHDL is a strongly typed language. I am not sure about the construct of Modelsim that let you run the assertions first.

All you can try is type cast the my_output <= my_input as my_output <= std_logic_vector(my_input) this will let Modelsim simulate your design but as soon as you try to RUN your design, it will throw an Error.

Without the type-casting, it won't let you even simulate your design.

Tushar
  • 415
  • 2
  • 16
0

You can realize sequential processing by putting it in a process. Example:

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 work example.vhd

vsim work.example

run 1 ns

# ** Failure: INPUT_LEN and OUTPUT_LEN must be equal!

JHBonarius
  • 10,824
  • 3
  • 22
  • 41
  • yes, I know I'm compiling in the library work, while I'm always complaining about this modelsim 'feature'. It's just easiest this way :P – JHBonarius Feb 04 '18 at 10:44
  • 1
    There are ways of only tinkering with the equivalent process for the concurrent signal assignment. e.g. `process begin wait for 0 ns; my_output <= my_input; wait on my_input;` adding a delta cycle delay before assigning my_output allowing the assertion to execute, my_input could be assigned to an intermediary signal used in the my_output assignment, the my_output assignment could be a guarded signal assignment in a block statement, ... –  Feb 04 '18 at 14:27