Check Library User Guide¶
Introduction¶
The check library is an assertion library for VHDL providing the more commonly used assertions as a number of check procedures and functions.
Architecture¶
Most check subprograms are conditional log messages. If the condition represents a failing check then an error message is issued using the VUnit log package.
Every check you perform is handled by a checker. There is a default checker that is used when none is specified but you can also create multiple custom checkers. For example
check(re = '1', "Expected active read enable at this point");
will use the default checker while
check(my_checker, re = '1', "Expected active read enable at this point");
will use the custom my_checker
. A custom checker is just a variable or constant initialized with the new_checker
function.
constant my_checker : checker_t := new_checker("my_checker");
All subprograms presented in this user guide are available for both the default checker and custom checkers. The
difference is the first checker
parameter which only exists for custom checker subprograms. To make the user guide
more compact, we present this as an optional parameter using square brackets. For example
impure function check_false(
[constant checker : in checker_t;]
constant expr : in boolean;
constant msg : in string := result(".");
constant level : in log_level_t := null_log_level;
constant path_offset : in natural := 0;
constant line_num : in natural := 0;
constant file_name : in string := "")
return boolean;
The full verbose API description can always be found in check_api.vhd and checker_pkg.vhd.
Checker Creation¶
Since a check is a conditional log, it uses a logger from the logging library described in the logging user guide internally.
A checker is created based on the logger to use or the name of that logger. If the named logger doesn’t exist, it will
be created. Additionally, there is also a default_log_level
parameter that can be used to specify the default log
level of failing checks.
impure function new_checker(logger_name : string;
default_log_level : log_level_t := error) return checker_t;
impure function new_checker(logger : logger_t;
default_log_level : log_level_t := error) return checker_t;
Check¶
The check library provides a basic check
procedure which is similar to the VHDL assert
statement:
check(re = '1', "Expected active read enable at this point");
The first parameter is the boolean expression to be evaluated, and the second parameter is the error message that will be issued if the expression is false. Assuming this check fails, and you haven’t changed the default settings for the default checker, the error message will be:
10000 ps - check - ERROR - Expected active read enable at this point
If you wish to have a log level other than the one set by default via the new_checker
function, you can override
this for each check call. For example,
check(re = '1', "Expected active read enable at this point", failure);
A failing check is always counted as a failure, no matter the severity level specified. However, the level determines
whether the simulation stops, which is controlled by the stop level for the internal logger. The stop level can be
changed by retrieving the logger and then use the set_stop_level
procedure as described in the logging user
guide. For example,
set_stop_level(get_logger(my_checker), warning);
Note that when using the VUnit Python test runner, the default checker stop level is set to error
when calling
test_runner_setup
. This is because the Python test runner has the capability to restart the simulation with the next
test case, ensuring that the error state of the failing test case won’t be propagated into subsequent tests. If the
Python test runner isn’t being used, then the stop level is set to failure
, allowing for continued execution on
error
, but without the assurance that the error state won’t be passed on.
Logging Passing Checks¶
The provided message in a check call is logged when the check passes, allowing for the creation of a debug trace to help
investigate what occurred before a bug. This feature uses the pass
log level, which is not visible by default, but can
be made visible for any log handler.
show(get_logger(default_checker), display_handler, pass);
The difference between a passing check log message and a failing check log message is the log level used. A passing check like this
check(re = '1', "Checking that read enable is active");
will result in a log entry like this
1000 ps - check - PASS - Checking that read enable is active
Note that a message that reads well for both the pass and the fail cases was used.
A number of check subprograms perform several checks for every call, each of which can fail and generate an error
message. However, there will only be one pass message for such a call to avoid confusion. For example, check_stable
checks the stability of a signal for every clock cycle in a window. If the window is 100 clock cycles there will be 100
checks for stability but there will only be one pass message, not 100, if the signal is stable.
Message Format¶
In the previous examples the outputs from passing and failing checks were the messages provided by the user with the
addition of a timestamp, the logger name and the log level. If we change the log format to raw
there would be no
additions at all, just the user message. However, the check subprograms may also add information to the user message
before the log format additions are applied. For example, checking a pixel value after an image processing operation can
be done like this:
check_equal(output_pixel, reference_model(x, y), "Comparing output pixel with reference model");
Resulting in an error message like this:
1000 ps - check - ERROR - Comparing output pixel with reference model - Got 1111_1010 (250). Expected 249 (1111_1001).
The last part of the message provides an error context to help debugging. Such a context is only given if that provides
extra information. In the case of a failing check
we know that the input boolean is false so there is no need to
provide that information. The context may also be different between pass and error messages. For example, a pass message
from check_equal
looks like this:
1000 ps - check - PASS - Comparing output pixel with reference model - Got 1111_1010 (250).
Redundancy is avoided by excluding the expected value which is the same as the value received.
So far we’ve used a message that reads well in both the passing and the failing case. The check library also provides
another way of doing this using the result
function. The call
check_equal(output_pixel, reference_model(x, y), result("for output pixel"));
gives the following messages:
1000 ps - check - ERROR - Equality check failed for output pixel - Got 1111_1010 (250). Expected 249 (1111_1001).
and
1000 ps - check - PASS - Equality check passed for output pixel - Got 1111_1010 (250).
The result
function prepends the provided string with the check type (equality check in this case) and assigns
either a passed or failed label based on the result. This function is also used as the default argument for all check
calls. For example,
check_equal(output_pixel, reference_model(x, y));
gives the following messages:
1000 ps - check - ERROR - Equality check failed - Got 1111_1010 (250). Expected 249 (1111_1001).
and
1000 ps - check - PASS - Equality check passed - Got 1111_1010 (250).
If you look at the default value for the user messages in the check subprogram APIs, you will see that the result
function isn’t used. This is a workaround for one of the supported simulators which exposes the internal implementation
of the result
function (a magic constant prepending the user message). You shouldn’t use the magic constant yourself
since that implementation may change at any time. For that reason we’re also keeping the result
function in the APIs
presented in this user guide.
Check Location¶
The check
subprograms described in the previous sections have three additional parameters, path_offset
,
line_num
and file_name
. These parameters allow the location of a failing chaeck to be included in the error
message. This is furter described in the log user guide.
procedure check(
[constant checker : in checker_t;]
constant expr : in boolean;
constant msg : in string := result(".");
constant level : in log_level_t := null_log_level;
constant path_offset : in natural := 0;
constant line_num : in natural := 0;
constant file_name : in string := "");
Acting on Failing Checks¶
The check
subprogram described so far doesn’t reveal whether the check passed or failed. If you want that
information to control the flow of your test, and your testbench is setup to continue on a failing check, you have a
number of options. You can use the check functions which return true
on a passing check and false
when they
fail.
impure function check(
[constant checker : in checker_t;]
constant expr : in boolean;
constant msg : in string := result(".");
constant level : in log_level_t := null_log_level;
constant path_offset : in natural := 0;
constant line_num : in natural := 0;
constant file_name : in string := "")
return boolean;
Or you can use check procedures with a boolean pass
output returning the same information.
procedure check(
[constant checker : in checker_t;]
variable pass : out boolean;
constant expr : in boolean;
constant msg : in string := result(".");
constant level : in log_level_t := null_log_level;
constant path_offset : in natural := 0;
constant line_num : in natural := 0;
constant file_name : in string := "");
Or you can use any of the following subprograms to get more details.
impure function get_checker_stat[(
constant checker : in checker_t);]
return checker_stat_t;
procedure get_checker_stat (
[constant checker : in checker_t;]
variable stat : out checker_stat_t);
checker_stat_t
is a record containing pass/fail information:
type checker_stat_t is record
n_checks : natural;
n_failed : natural;
n_passed : natural;
end record;
Note that a check subprogram with multiple internal checks may generate multiple error messages if it’s configured not
to stop on error. Each of these errors will result in the values of both n_checks
and n_failed
increasing by
one. However, if the check passes, n_checks
and n_passed
will only be increased by one. The rationale behind
this is identical to that of the single-pass message approach, which seeks to prevent any discrepancies between the
number of passing check subprogram calls and the associated statistical data.
Managing Checker Statistics¶
A checker will continuously update its statistics counters as new check subprograms are called. If you want to collect
the statistics for parts of your test you can make intermediate readouts using the get_checker_stat
subprograms and
then reset the counters to zero using:
procedure reset_checker_stat [(
constant checker : in checker_t)];
Another way of collecting statistics for different parts is to use several separate checkers.
Variables of type checker_stat_t
can be added to or subtracted from each other using the normal -
and +
operators. There is also a to_string
function defined to allow for logging/reporting of statistics, for example
info(to_string(get_checker_stat));
Postponed Check Actions¶
The action taken on a failing check is usually to create a log, as demonstrated in the preceding chapters. It is also possible to postpone the action by separating it from the fail/pass analysis of the check. Doing so provides us with an opportunity to complete other tasks before finalizing the check even if an error leads to a simulation stop.
This postponed approach is based on a check function which returns a check_result_t
type:
impure function check(
[constant checker : in checker_t;]
constant expr : in boolean;
constant msg : in string := result(".");
constant level : in log_level_t := null_log_level;
constant path_offset : in natural := 0;
constant line_num : in natural := 0;
constant file_name : in string := "")
return check_result_t;
The check_result_t
type contains all the necessary information to perform a log action at a later point in time.
This is achieved with the log
function, which takes the check_result_t
as its only parameter. As an example,
check_result := check(re = '1', "Checking that read enable is active");
-- Perform custom tasks
log(check_result);
In addition to the log action, another predefined action, notify_if_fail
, is available. This action triggers a
notification event when a check fails, allowing remote event observers to take appropriate actions. After raising this
notification, notify_if_fail
will then call log
on the result of the check.
notify_if_fail(check(re = '1', "Checking that read enable is active"), vunit_error);
For more information about how to use notify_if_fail
in your test, please refer to the event user guide.
When separating the action from the analysis there is a risk that the user forgets to call the action procedure after
the custom tasks have been performed. To prevent that such a mistake leads to an undetected error, VUnit keeps track of
all postponed actions that have yet to be handled. If, during the execution of a check, an error is detected and no
postponed action is performed, then the test_runner_cleanup
procedure will fail with an “unhandled checks” error.
Note
The postponed check action is currently available for a limited set of sequential checks. See the check API for the latest status.
Check Types¶
In addition to the basic check
subprograms the check library also provides a number of more specialized checks.
These checks can be divided into four different types:
Point checks
Relation checks
Sequential checks
Unconditional checks
These types and the checks belonging to each type are described in the following chapters.
Point Checks¶
Common to all point checks is that the condition for failure is evaluated at a single point in time, either when the
subprogram is called as part of sequential code or synchronous to a clock in a clocked, usually concurrent procedure
call. There are six unclocked versions of each point check, corresponding to the two boolean functions and four
procedures previously described for check
. The only difference in the respective parameter lists is that the boolean
expr
parameter is replaced by one or more parameters specific to the point check.
The unclocked procedures have the following format. The four variants comes from the different combinations of using the two first optional parameters.
procedure check<_name>(
[constant checker : in checker_t;]
[variable pass : out boolean;]
<specific parameters>
constant msg : in string := result<(".")>;
constant level : in log_level_t := null_log_level;
constant path_offset : in natural := 0;
constant line_num : in natural := 0;
constant file_name : in string := "");
The boolean functions have the following format.
impure function check<_name>(
[constant checker : in checker_t;]
<specific parameters>
constant msg : in string := result<(".")>;
constant level : in log_level_t := null_log_level;
constant path_offset : in natural := 0;
constant line_num : in natural := 0;
constant file_name : in string := "")
return boolean;
The clocked procedures follow a format with and without the optional checker
parameter. These procedures are also
available for check
.
procedure check<_name>(
[constant checker : in checker_t;]
signal clock : in std_logic;
signal en : in std_logic;
<specific parameters>
constant msg : in string := result<(".")>;
constant level : in log_level_t := null_log_level;
constant active_clock_edge : in edge_t := rising_edge;
constant path_offset : in natural := 0;
constant line_num : in natural := 0;
constant file_name : in string := "");
edge_t
is an enumerated type:
type edge_t is (rising_edge, falling_edge, both_edges);
The condition for failure is continuously evaluated on the clock edge(s) specified by active_clock_edge
, so long as
en = '1'
. For constant evaluation of the check procedure, you can tie the en
input to the predefined check_enabled
signal.
The figure below shows an example using the concurrent version of check
.
expr
is evaluated on every rising clock edge, except when en
is low on edge 3. This means the check will pass
despite the false expr
in the third clock cycle.
(True) Check (check and check_true)¶
Specific Parameter |
Type |
---|---|
expr |
boolean or std_logic |
check_true
is a more verbose alternative to check
which clearly expresses the expectation that the expr
evaluates to true
, 1
, or H
. The extra verbosity is also present when the result
function is used.
check(false, result("for my data.");
will result in
1000 ps - check - ERROR - Check failed for my data.
while
check_true(false, result("for my data.");
will result in
1000 ps - check - ERROR - True check failed for my data.
False Check (check_false)¶
Specific Parameter |
Type |
---|---|
expr |
boolean or std_logic |
check_false
passes when expr
is false
, 0
, or L
.
Implication Check (check_implication)¶
Specific Parameter |
Type |
---|---|
antecedent_expr |
boolean or std_logic |
consequent_expr |
boolean or std_logic |
The unclocked subprograms use boolean
parameters while the clocked procedures use std_logic
.
check_implication
checks logical implication and passes unless antecedent_expr
is true
, 1
, or H
when
consequent_expr
is false
, 0
, or L
.
Not Unknown Check (check_not_unknown)¶
Specific Parameter |
Type |
---|---|
expr |
std_logic_vector or std_logic |
check_not_unknown
passes when expr
contains none of the metavalues U
, X
, Z
, W
, or -
.
Zero One-Hot Check (check_zero_one_hot)¶
Specific Parameter |
Type |
---|---|
expr |
std_logic_vector |
check_zero_one_hot
passes when expr
contains none of the metavalues U
, X
, Z
, W
, or -
and
there are zero or one bit equal to 1
or H
.
One-Hot Check (check_one_hot)¶
Specific Parameter |
Type |
---|---|
expr |
std_logic_vector |
check_one_hot
passes when expr
contains none of the metavalues U
, X
, Z
, W
, or -
and there is
exactly one bit equal to 1
or H
.
Relation Checks¶
Relation checks are used to check whether or not a relation holds between two expressions, for example if (a + b) =
c
. They support the following six unclocked formats.
procedure check_<name>(
[constant checker : in checker_t;]
[variable pass : out boolean;]
<specific parameters>
constant msg : in string := result;
constant level : in log_level_t := null_log_level;
constant path_offset : in natural := 0;
<preprocessor parameters>);
impure function check_<name>(
[constant checker : in checker_t;]
<specific parameters>
constant msg : in string := result;
constant level : in log_level_t := null_log_level;
constant path_offset : in natural := 0;
<preprocessor parameters>)
return boolean;
Equality Check (check_equal)¶
Specific Parameter |
---|
got |
expected |
The got
and expected
parameters can have the following combinations of types:
got |
expected |
---|---|
unsigned |
unsigned |
natural |
unsigned |
unsigned |
natural |
natural |
std_logic_vector |
std_logic_vector |
natural |
std_logic_vector |
std_logic_vector |
std_logic_vector |
unsigned |
unsigned |
std_logic_vector |
signed |
signed |
integer |
signed |
signed |
integer |
integer |
integer |
std_logic |
std_logic |
boolean |
std_logic |
std_logic |
boolean |
boolean |
boolean |
time |
time |
string |
string |
character |
character |
Preprocessor Parameter |
Type |
Default Value |
---|---|---|
line_num |
natural |
0 |
file_name |
string |
“” |
check_equal
passes when got
equals expected
. When comparing std_logic
values with boolean
values
1
equals true
and all other std_logic
values equal false
. Note that the std_logic
don’t care (-
)
only equals itself. If you want an equality like "0011" = "00--"
to pass, you should use check_relation
with the
matching equality operator (?=
) or check_match
instead.
If a check fails you will get a context on the following format.
Got <got value>. Expected <expected value>.
When you compare bit vectors, integer
, and natural
type of values, the error message will output the values on
both formats. For example, here is a context when a check_equal
between an integer
and a signed
value fails.
Got 17 (0001_0001). Expected 0001_0000 (16).
Real value checks¶
Exact comparison of real values is often not desirable; therefore, there is a variant of check_equal
, which takes an
argument max_diff
. If the absolute difference between the received and expected values is larger than max_diff
,
then the check fails.
check_equal(0.1, 0.2, max_diff => 0.1); -- Passes
check_equal(0.1, 0.2, max_diff => 0.05); -- Fails
Equality check passed - Got abs (0.1 - 0.2) <= 0.1.
Equality check failed - Got abs (0.1 - 0.2) > 0.05.
Relation Check (check_relation)¶
Specific Parameter |
Type |
---|---|
expr |
boolean, std_ulogic, or bit |
Preprocessor Parameter |
Type |
Default Value |
---|---|---|
context_msg |
string |
“” |
line_num |
natural |
0 |
file_name |
string |
“” |
expr
is intended to be a relational expression and three different types are supported. In case a matching
relational operator is used, the relation will return a std_ulogic
or bit
depending on the operands. All other
relations will return a boolean
.
check_relation
passes when expr
evaluates to true
in the boolean case and to 1
in the std_ulogic
and
bit
cases. This means that the boolean
case behaves just like check
and check_true
. The additional value
of this check comes when you enable the check preprocessor in your VUnit run script.
ui = VUnit.from_argv()
ui.add_vhdl_builtins()
ui.enable_check_preprocessing()
The check preprocessor scans your code for calls to check_relation
and then parses expr
as a VHDL relation. From
that it will generate a context (context_msg
parameter) describing how the relation failed. For example, the check
check_relation(real_time_clock <= timeout, "Response too late");
will generate the following error message if it fails.
1000 ps - check - ERROR - Response too late - Expected real_time_clock <= timeout. Left is 23:15:06. Right is 23:15:04.
This works for any type of relation between any types as long as the operator and the to_string
function are
defined for the types involved. In the example above the operands are of a custom clock_t
type for which both the
<=
operator and the to_string
function have been defined.
Note that context_msg
is the empty string by default, so without the check preprocessor, the error message will only
be the msg
provided by the user.
Relations with Side Effects¶
The left and right hand sides of the relation are evaluated twice: once when the relation is initially evaluated, and again to create the error message. Let’s say you have a call like this:
check_relation(counter_to_verify = get_and_increment_reference_counter(increment_with => 3));
The reference counter will be incremented with 6, which is not what is expected from looking at the code.
Conclusion: Do not use impure functions in your expression. If you have an impure function you should call it once and
assign the value to a temporary variable before calling check_relation
:
ref_cnt := get_and_increment_reference_counter(increment_with => 3);
check_relation(counter_to_verify = ref_cnt);
In this case, where we have an equality relation, we can also use check_equal
. This procedure has the left and right
hand operands separated in the call itself, thus eliminating the need for a second evaluation in order to create the
error message.
Fooling the Parser¶
The check preprocessor has a simplified parser to determine what the relation operator in the expression is, and what
the left and right hand operands are. For example, it knows that this is an inequality since /=
is the only relational
operator on the “top-level”:
check_relation((a = b) /= (c = d));
It also knows that this isn’t a relation since there’s no relational operator on the top-level:
check_relation((a = b) and c);
Such a call will result in a syntax error from the check preprocessor:
SyntaxError: Failed to find relation in check_relation((a = b) and c)
However, its knowledge about precedence is limited to parenthesis so it will not understand that this identical expression isn’t a relation:
check_relation(a = b and c);
If this logical expression returns false, the check will generate an error message claiming that a relation failed and
that a
was the left value and b and c
was the right value.
Conclusion: Use check_relation
for relations as intended!
It should also be noted that the parser can handle that there are relational operators within the check call but outside
of the expr
parameter. For example, it won’t be fooled by the relational operators appearing within strings and
comments of a call.
Match Check (check_match)¶
Specific Parameter |
---|
got |
expected |
The got
and expected
parameters can have the following combination of types
got |
expected |
---|---|
unsigned |
unsigned |
std_logic_vector |
std_logic_vector |
signed |
signed |
std_logic |
std_logic |
Preprocessor Parameter |
Type |
Default Value |
---|---|---|
line_num |
natural |
0 |
file_name |
string |
“” |
check_match
passes when got
equals expected
but differs from check_equal
in that a don’t care (-
)
bit equals anything.
Sequence Checks¶
Sequence checks are checks that use several clock cycles to determine whether or not the desired property holds.
Stability Check (check_stable)¶
check_stable
supports four different clocked formats. The expr
parameter can be std_logic
or
std_logic_vector
and the call can be made with or without the initial custom checker parameter.
procedure check_stable(
[constant checker : in checker_t;]
signal clock : in std_logic;
signal en : in std_logic;
signal start_event : in std_logic;
signal end_event : in std_logic;
signal expr : in std_logic or std_logic_vector;
constant msg : in string := result;
constant level : in log_level_t := null_log_level;
constant active_clock_edge : in edge_t := rising_edge;
constant allow_restart : in boolean := false;
constant path_offset : in natural := 0;
constant line_num : in natural := 0;
constant file_name : in string := "");
check_stable
passes if the expr
parameter is stable in the window defined by the start_event
and
end_event
parameters. The window starts at an active (as per active_clock_edge
) and enabled (en = '1'
)
clock edge for which start_event = '1'
and it ends at the next active and enabled clock edge for which end_event =
'1'
. expr
is sampled for a reference value at the start event and is considered stable if it keeps that reference
value at all enabled and active clock edges within the window, including the clock edge for the end event. Bits within
expr
may change drive strength (between '0'
and 'L'
or between '1'
and 'H'
) and still be considered
stable. Below is an example with two windows that will pass.
Here are two examples of failing checks. Note that any unknown value (U
, X
, Z
, W
, or -
) will cause
the check to fail even if the unknown value is constant. The check will also fail if either start_event
or
end_event
has an unknown value in the active window.
check_stable
can handle one clock cycle windows and back-to-back windows.
When allow_restart
is false
, check_stable
will ignore additional start events in the window. When
allow_restart
is true
a new window is started if a new start event appears before the end event. The previous
window is implicitly closed in the clock cycle before the new start event. An end event will still close the window if
it appears before a second start event.
Next Check (check_next)¶
check_next
supports two different formats. One with and one without the initial custom checker parameter.
procedure check_next(
[constant checker : in checker_t;]
signal clock : in std_logic;
signal en : in std_logic;
signal start_event : in std_logic;
signal expr : in std_logic;
constant msg : in string := result;
constant num_cks : in natural := 1;
constant allow_overlapping : in boolean := true;
constant allow_missing_start : in boolean := true;
constant level : in log_level_t := null_log_level;
constant active_clock_edge : in edge_t := rising_edge;
constant path_offset : in natural := 0;
constant line_num : in natural := 0;
constant file_name : in string := "");
check_next
passes if expr = '1'
num_cks
active (as per active_clock_edge
) and enabled (en = '1'
)
clock edges after a start event. The start event is defined by an active and enabled clock edge for which start_event
= '1'
. Below is an example of a passing check. The start event is sampled at clock edge two and expr
is expected
to be high four enabled clock edges after that which is at clock edge seven due to en
being low at clock edge five.
When allow_overlapping
is true
, check_next
will allow a new start event before the check based on the
previous start event has been completed. Here is an example with two overlapping and passing sequences.
In case allow_overlapping
is false
, check_next
will fail at the second start event.
When allow_missing_start
is true
, check_next
will allow expr = '1'
when there is no corresponding start
event. When allow_missing_start
is false
, such a situation will lead to a failure. Here is an example where
expr
is at '1'
for one cycles with no corresponding start event.
Any unknown value (U
, X
, Z
, W
, or -
) on start_event
will cause an error.
check_next
will handle the weak values L
and H
in the same way as 0
and 1
, respectively.
Sequence Check (check_sequence)¶
check_sequence
supports two different formats. One with and one without the initial custom checker parameter.
procedure check_sequence(
[constant checker : in checker_t;]
signal clock : in std_logic;
signal en : in std_logic;
signal event_sequence : in std_logic_vector;
constant msg : in string := result;
constant trigger_event : in trigger_event_t := penultimate;
constant level : in log_level_t := null_log_level;
constant active_clock_edge : in edge_t := rising_edge;
constant path_offset : in natural := 0;
constant line_num : in natural := 0;
constant file_name : in string := "");
check_sequence
checks whether a series of events, represented by the bits in the event_sequence
parameter, are
activated (with bit values of '1'
or 'H'
) in order at consecutive active (as per active_clock_edge
) and
enabled (en = '1'
) clock edges. Furthermore, the behavior of the procedure can be changed based on the argument
trigger_event
which has three distinct options for operation.
first_pipe
- The sequence is started when the leftmost bit ofevent_sequence
is activated. This will also triggercheck_sequence
to verify that the remaining bits are activated at the following active and enabled clock edges.check_sequence
will also verify new sequences starting before the first is completed.
The figure below shows two overlapping sequences that pass:
In this example the sequence is started but not completed and the check fails:
first_no_pipe
- Same asfirst_pipe
with the exception that only one sequence is verified at a time. New sequences starting before the previous is verified will be ignored.
In this example we have two sequences: the first is completed while the second is interrupted. However, since only one sequence is handled at a time, the second is ignored and the check pass.
penultimate
- The difference with the previous modes is thatcheck_sequence
only verifies the last event (the rightmost bit) when all the preceding events in the sequence have been activated. This means that a started sequence that is interrupted before the second to last bit is activated will pass.check_sequence
will also verify new sequences starting before the first is completed.
The figure below shows two overlapping sequences which pass and then an early interrupted sequence that doesn’t cause a
failure in this mode (which it did in the example for the first_pipe
mode).
In this example the sequence is interrupted after the second to last bit is activated and the check fails.
Any unknown values (U
, X
, Z
, W
, or -
) in event_sequence
will lead to a an error. This is
regardless of the mode of operation.
Unconditional Checks¶
The check library has two unconditional checks, check_passed
and check_failed
, that have no expression
parameter to evaluate. They are used when the pass/fail status is already given by the program flow. For example,
if <some condition> then
<do something>
check_passed;
else
<do something else>
check_failed("This was not expected");
end if;
With no expr
parameter there are also fewer usable formats for these checkers.
procedure check_passed(
[constant checker : in checker_t;]
constant msg : in string := result(".");
constant path_offset : in natural := 0;
constant line_num : in natural := 0;
constant file_name : in string := "");
procedure check_failed(
[constant checker : in checker_t;]
constant msg : in string := result(".");
constant level : in log_level_t := null_log_level;
constant path_offset : in natural := 0;
constant line_num : in natural := 0;
constant file_name : in string := "");