Subject: Re: Friday's Assertion Meeting
From: Adam Krolnik (krolnik@lsil.com)
Date: Wed Mar 06 2002 - 13:44:41 PST
Good afternoon all;
I would like to introduce myself to those I have not yet met.
I'm Adam Krolnik, the Verification Manager for LSI Logic Advanced DSP
Development.
I have been a verification engineer for 11 years on various processor
and
memory system/north bridge projects. I have been working with assertion
tools
and assertions themselves for 5 years. My feedback comes from this
experience
in developing an assertion language, tool, cookbook, motivational
presentations, etc.
Here is my thoughs on the review of the document.
0. General methodology
Assertions by default should report errors. Too many tool produce
warnings that
most engineers ignore. Errors should terminate the simulation soon
afterward unless
explicitly directed to do differently.
1. Immediate assertions.
I like the format of the default message (except for the severity.) It
provides
a standard format that tools (and people) can utilize to obtain the
required
information to diagnose the problem. I would like to see a way to keep
(optionally?)
the default message and append more information from the engineer about
the
failure. E.g.
If I do give a message with extra information, say
$error("ISU sent PC that is out of range %h", isu_currentpc_fd[23:0]);
It is still helpful to see a message like:
ASSERT fail 'InvalPC' on cycle 34,
coretb.zsp600.pfu.ASSERT_00000_block from
file design/pfu/rtl/pfu.v, line 284.
ASSERT fail Message: ISU sent PC that is out of range ffff53
Rather than just the message only, or the message only because the
engineer
forgot to include the hierarchical name and time in his message.
I also like the several severities of messages, $fatal, $error, $warn,
$info.
But I don't like to talk about $fatal in the context of assertions. I
see
the use for $fatal more for something at the simulation level - a data
file
is missing, or a file can't be written. We should have $warning because
some
assertions may be written to find interesting events. Rather than report
an
error, the interesting point is noted and the simulation continues. I
have
used warnings and errors to find these interesting events (error was
used
because we couldn't find the interesting event, so we decided to make
the
test fail and obviously show where the event was.)
Please expand on the statement, "The simulator could count the number of
errors
and warnings." I feel that there needs to be a mechanism to do this. I
have
implemented a control module that tracks errors and will abort the
simulation
after a defined error threshold is reached. The threshold is settable by
the simulation and by +arg. E.g. +ERROR_LIM=2.
This allows one to keep assertions as errors and yet give control to the
engineer
to not terminate a simulation when the first error is reached.
2. Strobed/Clocked/Clocked strobed assertions.
We have found that the easiest way to clock assertions is like this:
assign #1 assert_clk = `CLK;
This allows both block, nonblocking and assign statements to evaluate to
their
proper values and then run the assertions. They then report in the same
cycle that
their inputs become active. This has prevented the questions like, "why
is the
assertion failing in the next clock". Yes, this requires a design
methodology that
does not include delays on signals and a clock period that exceeds #1.
3. Clocked Immediate assertions
If one writes, assert (a) assert @(posedge clock) (b; c);
Doesn't the default else statement occur if 'a' is not true?
I ask this because sometimes you want to find something using assertions
and don't want an error if the event is not found.
The last paragraph says, "A clocked assertion may also be re-triggered
at the
next clock cycle , before the sequence has expired."
This is good and bad. It is good if I have a bus that can start two
transactions
before the first on will complete. I call this a pipelined transaction.
This is
also bad if I want to ignore subsequent cycles until the sequence does
expire.
There are these cases:
1. sequence must complete before allowing retriggering.
2. it is an error if the sequence can retrigger before the first on is
complete.
3. I want to allow up to N retriggerings before a sequence can complete,
but
no more than N - report an error if more.
4. Any number of retriggerings can occur.
The OVL assertions allow for 1, 2, 4 I believe, Harry is this correct?
The first three are very useful for common assertion forms.
4. More Expression sequences
This is a sequence:
assert (a; 1; 1; c)
The ';' character is a sequence separator. This is following the specman
E
language for temporal expressions. There is a problem with this kind of
sequence separation. It excludes the degenerate case of 0 clock cycles
between the two expressions.
The ability to include or exclude this degenerate case of 0 cycles is
very
important in maintenance of assertion code. Engineers frequently change
their
mind (and code) as time goes on. Having to rewrite assertions when small
changes occur is not the best use of time. For example.
An engineer says "B follows A by 2 cycles." The assertion is:
assert (A; 1; B);
The engineer the corrects himself, "Oh, B follows A by 1 or 2 cycles.".
How do
you modify the assertion? In my language, I could say:
assert (A; [0:1]; B);
The engineer then gets his timing report and decides that B can move
earlier
still. "B follows A by 0, 1 or 2 cycles.". How do you modify the
assertion?
I would write:
A -> B {0:2}
With specman, you would have to write:
(A && B || {A ; [0:1]; B);
With 'A' and 'B' for equations, it's pretty easy to do and see the
difference.
When the equations are a line long, it's not as easy...
5. Antecedent and consequent
The keyword 'triggers' seems to be a little heavy - why not the
implication
arrow '->'?
6. Resetting assertions
It says, "Rejection means that the assertion fails and the fail
statement
is executed." Should this really say that the pass statement is
executed?
The language I have uses the keyword 'forbid' to express an opposite.
E.g.
assert (!error) === forbid (error)
I presume this is the use of 'reject'
assert (!error) ?== assert reject (error)
7. Controlling assertions.
It is good to have these controls. We normally have assertions on
unless it is changed by the testbench. The normal adjustment to the
enabling of assertions is this:
assert_run = coretb.rst_n && !scp.shutting_down;
E.g. the testbench is not being reset and we are not going to terminate
the simulation (due to an error, or the end of the testcase.)
8. Controlling the steps.
The example in here is not a good example. Assertions (most) should be
disabled (reset) when the system is reset so that they do not fire
erroneously
when the system comes out of reset. I.e.
If you say, "each request must be followed by a grant."
And you start a request, then issue a reset. You will not get a grant...
9. Further enhancements
The $onehot expression is good, having an easy onehot or zero is equally
beneficial. I would recommend that the $in() have these abilities.
1. Accept don't care symbols for the member, list.
This is useful when you want to compare an expression to a set
of constants, etc. These constants can include don't care symbols
when a particular bit is not part of the spec. This can occur for
state machines, and for commands of a control bus. E.g.
$in({addr[1:0], type, size},
2'b00, 2'b0, 2'b0, // cache line size.
2'bxx, 2'b01, 2'b00, // word size
2'bx0, 2'b01, 1'b10, // dword size.
...);
2. Return the number of matches.
This is useful if you are trying to match various expressions to
a value. E.g.
$in(6'b01_0000, // writing result 0
{unit1_we, unit1_addd}, // from unit1
{unit2_we, unit2_addr}, // from unit2
...);
Having a posedge/negedge primitive would be useful if the expression
being
checked doesn't change exactly at the same time the assertions run at.
We found it useful to have a function called isunknown() because too
often
people thought they could write a proper expression to detect X's. I.e.
Too often people mistake ^sig == 1'bx as correct instead of ^sig ===
1'bx.
Lastly, we found that having a function that could store state based on
an antecedent's success was helpful. I.e. When request is asserted,
store
the tag and use it to check the tag when the data is ready. We did
something
like:
request implies data_ready within 1 to 30 cycles
implies triggered(request_tag) == data_tag (on the current
cycle.)
The function triggered would register the request tag when the signal
'request'
was asserted and would store the value for comparison when the data
ready
signal occurred.
10. How does/will this body of work mesh with the formal validation
group?
Is this intended as separate language, or are they seen to be merging?
Thanks all.
Adam Krolnik
Verification Mgr.
LSI Logic Corp.
Plano TX. 75074
This archive was generated by hypermail 2b28 : Wed Mar 06 2002 - 13:46:14 PST