Subject: Re: Friday's Assertion Meeting
From: Peter Flake (flake@co-design.com)
Date: Sun Mar 10 2002 - 11:51:08 PST
Hi Adam,
Thanks for your valuable comments. I have inserted some replies.
At 03:44 PM 3/6/02 -0600, Adam Krolnik wrote:
>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.
Should the default severity be tool-dependent?
>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.
If we append text with $info/warning/error then I think we need a severity
which will suppress the message e.g. $quiet.
>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.
The fail statement can be used to increment a counter or to call a function
which behaves as you wish.
However I think that any automatic tracking should be tool-dependent and
not part of the language.
>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.
I think strobed assertions meet your requirement.
>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?
Yes it occurs.
>I ask this because sometimes you want to find something using assertions
>and don't want an error if the event is not found.
Use $quiet?
>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.
Would providing a function to count the number of activations of the
assertion meet your needs?
If ($num(a1) == 0) a1:assert ...
a2: assert( ($num(a2) == 1) && ....
a3: assert($num(a3) < N+1) && ....
>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.
Given that [1] waits 1 cycle, we could allow [0] to wait 0 cycles:
(a; [1];[1];[0];c)
>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);
I suggest A;[0:2];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 '->'?
We are already using -> in SUPERLOG for pointer access to a structure
member, like in C.
Also I think it is an important low-precedence operator, so better as a
keyword.
>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?
No, acceptance executes the pass statement.
>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)
No, because reject cannot take a sequence.
>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...
The example should be changed.
>9. Further enhancements
>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.
SystemVerilog and SUPERLOG have the enhancement that an expression can be
an assignment, like in C.
So you can write:
assert ((request && (tag = request_tag))
triggers(!data_ready*[1:30]) triggers (tag == data_tag))
Peter.
This archive was generated by hypermail 2b28 : Mon Mar 18 2002 - 08:05:01 PST