After reading Stuart Sutherland’s paper “Who Put Assertions In My RTL Code? And Why? - How RTL Design Engineers Can Benefit from the Use of SystemVerilog Assertions”, I wondered where we can insert assertions in VHDL since the paper focuses on System Verilog.

You could of course study the Language Reference Manual and figure out that assertions can be both concurrent and sequential, and from that intuit where they can be placed. But I think an example conveys the information much better:

assert_tb.vhd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
package pkg is
  -- severity note is set on all assertions so the reports will show up without stopping
  constant severity_lvl: severity_level := note;

  procedure procedure_assert(fail: boolean; description: string);
  function function_assert(fail: boolean; description: string) return boolean;

  constant something_to_assert: boolean := false;

  -- Can't assert directly here:
  -- assert something_to_assert report "entity" severity severity_lvl;
end package pkg;

package body pkg is
  -- Internal function to avoid circular dependency of function_assert and procedure_assert.
  function function_assert_internal(fail: boolean; description: string) return boolean is
  begin
    assert fail report description & " function internal" severity severity_lvl;
    return fail;
  end function;

  procedure procedure_assert(fail: boolean; description: string) is
    variable function_assert_result: boolean := function_assert_internal(
      fail, description & " procedure variable declaration"
    );
  begin
    assert fail report description & " procedure" severity severity_lvl;
  end procedure;

  function function_assert(fail: boolean; description: string) return boolean is
  begin
    procedure_assert(fail, description & " function procedure call");
    assert fail report description & " function" severity severity_lvl;
    return fail;
  end function;
end package body;

  use work.pkg.all;

entity dut is
  generic(
    a_generic: boolean := function_assert(something_to_assert, "generic declaration")
  );
  port(
    input: in boolean := function_assert(something_to_assert, "in port declaration");
    output: out boolean := function_assert(something_to_assert, "out port declaration");
    inoutput: inout boolean := function_assert(something_to_assert, "inout port declaration")
  );
  constant C_FUNCTION_ASSERT_RESULT_ENTITY: boolean := function_assert(
    something_to_assert, "entity constant declaration"
  );
  -- shared variables of protected types allowed too
  -- Can't assert directly here:
  -- assert something_to_assert report "entity" severity severity_lvl;
begin
  procedure_assert(something_to_assert, "entity");
  procedure_assert(
    function_assert(
      something_to_assert, "entity procedure call"
    ),
    "entity function"
  );
  assert something_to_assert report "entity" severity severity_lvl;
end;

architecture none of dut is
  constant C_FUNCTION_ASSERT_RESULT_ARCHITECTURE: boolean := function_assert(
    something_to_assert, "architecture constant declaration"
  );
  signal function_assert_result: boolean := function_assert(
    something_to_assert, "architecture signal declaration"
  );
  -- Can't assert directly here:
  -- assert something_to_assert report "entity" severity severity_lvl;
begin
  g: if true generate
    procedure_assert(something_to_assert, "generate assign");
    assert something_to_assert report "generate" severity severity_lvl;
  else generate
    assert something_to_assert report "not generated" severity severity_lvl;
  end generate;

  procedure_assert(something_to_assert, "concurrent");
  function_assert_result <= function_assert(something_to_assert, "concurrent");
  assert something_to_assert report "concurrent" severity severity_lvl;

  p: process is
    variable v_function_assert_result: boolean := function_assert(
      something_to_assert, "process declaration"
    );
  begin
    procedure_assert(something_to_assert, "process");
    v_function_assert_result := function_assert(something_to_assert, "process assign");
    assert something_to_assert report "process" severity severity_lvl;
    wait;
  end process;
end;

library vunit_lib;
  context vunit_lib.vunit_context;

  use work.pkg.all;

entity generic_assert_tb is
  generic(runner_cfg: string);
end;

architecture test of generic_assert_tb is
  signal stop_test: boolean:= false;
  signal clk: boolean:= false;
begin
  i: entity work.dut
    generic map(
      a_generic => function_assert(something_to_assert, "generic map asssign")
    )
    port map(
      input => function_assert(something_to_assert, "port map assign"),
      output => open,
      inoutput => open
    );

  main: process is
  begin
    test_runner_setup(runner, runner_cfg);
    test_runner_cleanup(runner);
  end process;
end;
Listing 1:

The output may be interesting too, since we can see the evaluation order of GHDL:

assert_tb.vhd:18:5:@0ms:(assertion note): generic map asssign function procedure call procedure variable declaration function internal
assert_tb.vhd:27:5:@0ms:(assertion note): generic map asssign function procedure call procedure
assert_tb.vhd:33:5:@0ms:(assertion note): generic map asssign function
assert_tb.vhd:18:5:@0ms:(assertion note): in port declaration function procedure call procedure variable declaration function internal
assert_tb.vhd:27:5:@0ms:(assertion note): in port declaration function procedure call procedure
assert_tb.vhd:33:5:@0ms:(assertion note): in port declaration function
assert_tb.vhd:18:5:@0ms:(assertion note): port map assign function procedure call procedure variable declaration function internal
assert_tb.vhd:27:5:@0ms:(assertion note): port map assign function procedure call procedure
assert_tb.vhd:33:5:@0ms:(assertion note): port map assign function
assert_tb.vhd:18:5:@0ms:(assertion note): out port declaration function procedure call procedure variable declaration function internal
assert_tb.vhd:27:5:@0ms:(assertion note): out port declaration function procedure call procedure
assert_tb.vhd:33:5:@0ms:(assertion note): out port declaration function
assert_tb.vhd:18:5:@0ms:(assertion note): inout port declaration function procedure call procedure variable declaration function internal
assert_tb.vhd:27:5:@0ms:(assertion note): inout port declaration function procedure call procedure
assert_tb.vhd:33:5:@0ms:(assertion note): inout port declaration function
assert_tb.vhd:18:5:@0ms:(assertion note): entity constant declaration function procedure call procedure variable declaration function internal
assert_tb.vhd:27:5:@0ms:(assertion note): entity constant declaration function procedure call procedure
assert_tb.vhd:33:5:@0ms:(assertion note): entity constant declaration function
assert_tb.vhd:18:5:@0ms:(assertion note): architecture constant declaration function procedure call procedure variable declaration function internal
assert_tb.vhd:27:5:@0ms:(assertion note): architecture constant declaration function procedure call procedure
assert_tb.vhd:33:5:@0ms:(assertion note): architecture constant declaration function
assert_tb.vhd:18:5:@0ms:(assertion note): architecture signal declaration function procedure call procedure variable declaration function internal
assert_tb.vhd:27:5:@0ms:(assertion note): architecture signal declaration function procedure call procedure
assert_tb.vhd:33:5:@0ms:(assertion note): architecture signal declaration function
assert_tb.vhd:18:5:@0ms:(assertion note): process declaration function procedure call procedure variable declaration function internal
assert_tb.vhd:27:5:@0ms:(assertion note): process declaration function procedure call procedure
assert_tb.vhd:33:5:@0ms:(assertion note): process declaration function
assert_tb.vhd:18:5:@0ms:(assertion note): entity procedure variable declaration function internal
assert_tb.vhd:27:5:@0ms:(assertion note): entity procedure
assert_tb.vhd:18:5:@0ms:(assertion note): entity procedure call function procedure call procedure variable declaration function internal
assert_tb.vhd:27:5:@0ms:(assertion note): entity procedure call function procedure call procedure
assert_tb.vhd:33:5:@0ms:(assertion note): entity procedure call function
assert_tb.vhd:18:5:@0ms:(assertion note): entity function procedure variable declaration function internal
assert_tb.vhd:27:5:@0ms:(assertion note): entity function procedure
assert_tb.vhd:66:3:@0ms:(assertion note): entity
assert_tb.vhd:18:5:@0ms:(assertion note): generate assign procedure variable declaration function internal
assert_tb.vhd:27:5:@0ms:(assertion note): generate assign procedure
assert_tb.vhd:81:5:@0ms:(assertion note): generate
assert_tb.vhd:18:5:@0ms:(assertion note): concurrent procedure variable declaration function internal
assert_tb.vhd:27:5:@0ms:(assertion note): concurrent procedure
assert_tb.vhd:18:5:@0ms:(assertion note): concurrent function procedure call procedure variable declaration function internal
assert_tb.vhd:27:5:@0ms:(assertion note): concurrent function procedure call procedure
assert_tb.vhd:33:5:@0ms:(assertion note): concurrent function
assert_tb.vhd:88:3:@0ms:(assertion note): concurrent
assert_tb.vhd:18:5:@0ms:(assertion note): process procedure variable declaration function internal
assert_tb.vhd:27:5:@0ms:(assertion note): process procedure
assert_tb.vhd:18:5:@0ms:(assertion note): process assign function procedure call procedure variable declaration function internal
assert_tb.vhd:27:5:@0ms:(assertion note): process assign function procedure call procedure
assert_tb.vhd:33:5:@0ms:(assertion note): process assign function
assert_tb.vhd:97:5:@0ms:(assertion note): process


Comments? You are welcome to start a discussion on Github.