390 likes | 594 Views
Assertions. Jean-Michel Chabloz. Assertions basic Idea. We assert that a certain “thing” should be true. If it is true, fine If it is false, then we get an error/warning/etc. Pieces of code that continuously inspect the waveforms and signal whenever they find something strange. SVA.
E N D
Assertions Jean-Michel Chabloz
Assertions basic Idea • We assert that a certain “thing” should be true. • If it is true, fine • If it is false, then we get an error/warning/etc. • Pieces of code that continuously inspect the waveforms and signal whenever they find something strange
SVA • SVA stands for System Verilog Assertions • it is almost an independent language, often taught as stand-alone. • 150 pages of the LRM (CRSG and functional coverage are around 50 pages each)
Immediate assertions • are found inside procedural code: initial begin … assert(a==10) else $info(“a is not 10”); … end • We could do the same check with an “if” • The only advantages are: • we can give a name to the assertion, so we can deactivate it, monitor it, etc. • it can be inserted into RTL code, the synthesizer will automatically ignore it (it will not ignore an “if”) • Immediate assertions are found also in VHDL • Bottom line: nothing special
Concurrent Assertions • This is the powerful stuff. It allows us to do complex checks across many clock cycles. • has the keyword “property” • From now on in this lecture we use assertions as synonym of concurrent assertions • Example: checkOnReq: assert property (@(negedge clk) req |-> ##2 !req ##1 valid==1) else $error(“error found”);
Failure action In an assertion we specify what to do when the assertion fails, because that’s what interests us. checkOnReq: assert property (@(negedge clk) req |-> ##2 !req ##1 valid==1) else $error(“error found”); • we could write also what to do when the assertion succeeds, but normally this is not done because we are interested in the assertion failures only. • from now on in these slides we abbreviate • a.p. (req |-> ##2 !req ##1 valid==1) • for • assert property (@(negedge clk) req |-> ##1 !req ##1 valid==1)
Severity level assert property (…) else • $fatal(“…”); • close the simulation, the error was so bad that it is worthless to continue • $error(“…”); • stop the simulation – the user might continue if he so wishes • $warning(“…”); • like error, but can be disabled • $info(“…”); • just print a message to the console without stopping the simulation, this was not a real error, just want to print some info for us
Single-cycle assertions • Assertions that complete in a single cycle, no implication. • assert property (@(negedge clk) cond) • if cond is false the assertion fails • variable a should never be 3 • assert property (@(negedge clk) a!=3) • the value of a is checked on every negative edge of the clock • If ever a becomes 3 during the simulation the assertion will fail
Implication in Single-Cycle assertions • If a is one then b must be one • assert property (@(negedge clk) a |-> b) • Any alternatives?
Implication in Single-Cycle assertions • If a is one then b must be one • assert property (@(negedge clk) a |-> b) • Alternatives: accepted (a,b)=(0,0),(0,1),(1,1) • a.p. (!(a & !b)) • a.p. (!a | b) • a.p. (!b |-> !a)
Writing assertions • Often writing assertions consists in translating the rules in the specs from english to SVA. • Pay attention to all the words
Implication in Single-Cycle assertions • if cond2, then cond1 must be true • a.p. (cond2 |-> cond1) • cond1 can be true only if cond2 • a.p. (cond1 |-> cond2) • a.p. (!cond2 |-> !cond1); • If cond2, then cond1 can be true • same as the last example
Multicycle Assertions • a.p.(a==2 ##1 a==4) • a: 2 4 2 2 4 • c: 0 1 2 3 4 • one evaluation attempt is started in every cycle: the assertion fails as soon as it is determined that it cannot match. • In cycle 0: matches at 1 • In cycle 1: fails at 1 • at 1 we know the assertion will never match • In cycle 2: fails at 3 • at 2 we think the assertion may match • at 3 we realize we were wrong • In cycle 3: matches at 4
Multicycle assertions • We normally want to write assertions that are triggered by something • a.p.(req |-> ##1 grant) • one evaluation attempt is started in every cycle • if the enabling condition is false, then the attempt is aborted (no failure) • if the enabling condition matches, then we check if what is right of the implication matches
Overlapped and non-overlapped implication • |-> what is right must start in the same cycle as what is left ends • |=> what is right must start one cycle after what is left ends • equivalent to: |-> ##1
sampled functions • $rose(a): a is one and was zero in the past cycle • $fell(a): a is zero and was one in the past cycle • $stable(a): a has the same value as in the past cycle • $past(a): the value that a had in the past cycle • $past(a,7): the value that a had 7 cycles ago
sampled functions • a 0010111101000011001 • $rose(a) 0010100001000010001 • $fell(a) ?001000010100000100 • $stable(a) ?100011100011101010 • $past(a) ?001011110100001100 • $past(a,2) ??00101111010000110
Common error • check that grant rises three cycles after a request is issued • g: 0 0 0 0 0 0 0 1 1 1 • r: 0 0 0 0 1 1 1 1 1 1 • c: 0 1 2 3 4 5 6 7 8 9 • a.p. (r |-> ##3 $rose(g)) // wrong • the assertion will abort immediately at 0,1,2,3 because the enabling condition doesn’t match • the enabling condition matches at 4, 5, 6, 7… • The attempt started at 4 matches at 7 • All other attempts (5, 6, 7, …) fail
Common error • Grant rises three cycles after a request is issued • g: 0 0 0 0 0 0 0 1 1 1 • r: 0 0 0 0 1 1 1 1 1 1 • c: 0 1 2 3 4 5 6 7 8 9 • a.p. ($rose(r) |-> ##3 $rose(g)) //good • the assertion will abort immediately at 0,1,2,3,5,6,7,… because the enabling condition doesn’t match • the enabling condition matches at 4 • The attempt started at 4 matches at 7 • No failure
sequence in the enabling condition • a.p.(a ##1 !a ##1 a |-> ##1 grant ##1 !grant) • c: 0 1 2 3 4 5 6 7 8 9 • a: 0 1 0 1 0 1 0 0 0 1 • g: 0 0 0 0 1 0 0 0 1 0 • e.a. started at 0: aborted at 0 • e.a. started at 1: matches at 5 • e.a. started at 2: aborted at 2 • e.a. started at 3: fails at 6 (en.cond. matched) • e.a. started at 4: aborted at 4 • e.a. started at 5: aborted at 7
or • At least one between two or more sequences match • the sequence matches at all times in which at least one of the two sequences matches • example: a.p. ($rose(r) |-> (##1 !r) or (##1 g ##1 !g)) • the assertion will match as soon as it is determined that at least one of the two ORed sequences matches
or • a.p. (a ##1 !a ##1 a) or (a##1 !a ##1 !a ##1 a) • will match both 101 and 1001 • alternative syntax: • (a ##1 !a [*1:2] ##1 a)
or • (a ##1 !a [*1:$] ##1 a) • matches both 101, 1001, 10001, 100001, etc. • (a ##1 !a [*0:$] ##1 a) • matches both 11, 101, 1001, 10001, etc.
and • Both sequences should match • Example: • $rose(r) |-> (!g [*2:$] ##1 g) and (r [*2:$] ##1 !r) • If request rose, then grant should be zero for at least two cycles and then go to one; r should remain one for at least two cycles and then go to zero • e.a. started at 1 will succeed (at 6) in the following waveforms (grant sequence matches at 4, req sequence matches at 6) • c: 0 1 2 3 4 5 6 7 8 9 • r: 0 1 1 1 1 1 0 0 0 0 • g: 0 0 0 0 1 1 1 1 1 1
intersect • Both sequences should match at the same time • Example: • $rose(r) |-> (!g [*2:$] ##1 g) intersect (r [*2:$] ##1 !r) • If request rose, then grant should be zero for at least two cycles and then go to one; r should remain one for at least two cycles and then go to zero; the time at which r drops must be the time at which g rises. • e.a. started at 1 will fail (at 4) in the following waveforms (grant sequence matches at 4, req sequence matches at 5, at 4 it is determined that the two cannot match in the same cycle) • c: 0 1 2 3 4 5 6 7 8 9 • r: 0 1 1 1 1 1 0 0 0 0 • g: 0 0 0 0 1 1 1 1 1 1
ORed enabling sequences • When a certain sequence happens, then some other sequence should start • a ##1 !a [*0:$] ##1 b |-> c ##1 [*0:$] ##1 d • The sequence after the implication must match every time the enabling sequence matches • One evaluation attempt can result into two or more matches of the enabling condition at different times, the sequence after the implication should match for all of them
ORed enabling sequences • Normally you want to have enabling sequences that match only once – that doesn’t mean they can’t be ORed • Typical example: check that the first time a rises after reset, cond1 is satisfied • $rose(reset) ##1 !a [*0:$] ##1 a |-> cond1 • will match only once
ORed enabling sequences • sequence that match on the first occurrence of a == 1 after b was 1 • b ##1 !a [*0:$] ##1 a • c: 0 1 2 3 4 5 6 7 8 9 • b: 0 1 0 0 0 0 1 0 0 0 • a: 0 0 0 1 0 1 0 1 1 0 • The evaluation attempt started at 1 matches only at 3, not at 5, 7, 8 • The evaluation attempt started at 6 matches only at 7, not at 8 • all other evaluation attempts fail as soon as they start because b is not 1
range delay operator • There is also the operator ##[1:4] - equivalent to ##1 or ##2 or ##3 or ##4 • Can use the $: ##[1:$] • Easy to make mistakes with it: • c: 0 1 2 3 4 5 6 7 8 9 • b: 0 1 0 0 0 0 0 0 0 0 • a: 0 0 0 1 0 1 0 1 1 0 • b ##[1:$] a |-> cond1 • The evaluation attempt started at 1 will fail if condition 1 is false at 3, 5, 7, 8… every time a is 1 after a single issuing of b. After b has become one, the enabling condition will match every time a is one. • b ##1 !a [*0:$] ##1 a |-> cond1 is different – The evaluation attempt started at 1 will fail if condition 1 is false at 3 (first occurrence of a==1 after b). It will not fail if cond1 is false at 5, 7, 8. • Recommendation: do not use ##[n:m]– easy to make mistakes with it
Evaluation attempts • With concurrent assertions, one evaluation attempt is started in every cycle • An evaluation attempt will be aborted as soon as it is determined that the evaluation condition cannot match • The sequence at the right of the implication sign must match for all cycles in which the enabling condition matches • As soon as it is determined that it is so, the evaluation attempt succeeds • As soon as it is determined that it is not so, the evaluation attempt fails
Evaluation attempts • Three possible outcomes: • aborted • failed • matched • By probing the assertions as transactions, we can see on the waveforms all evaluation attempts: when they start and when they match or fail.
Stand-alone sequences • Sometimes it is efficient to define stand-alone sequences • sequence s1; • ##1 b [*0:$] ##1 b; • endsequence • sequence s2; • $fell(b) ##1 !b ##1 b; • endsequence • We can then write • a.p. (s1 |-> ##2 s2) • a.p. (a==0 |=> s1 or s2) • a.p. (s1 ##1 s2 |-> a==5) • 1.p. (s1 and s2 |=> b==1 ##1 b==0) • etc. etc. • Good for code reuse and for keeping a good coding style
Internal variables • The other big advantage of sequences is that they can have local variables • sequence s1; • int cnt; • (a==1, b=cnt) ##1 !a [*0:$] ##1 (a && b==cnt+1); • endsequence • the sequence corresponds to: if a is 1, save the value of b in cnt, then wait until a rises again and check that b is equal to cnt+1; • In other words: every time that a is 1, b must be one more compared to the last time a was 1
Internal variables • If a is one, then the next time a is one the value of b should be equal to the value that b had the last time a was one, plus one • a.p. (a |-> s1) • sequence s1; • int cnt; • (1, cnt=b) ##1 !a *[0:$] ##1 (a & b==cnt+1); • endsequence • since in the sequence we want to record the value cnt every time a is one, we don’t have a condition. But we cannot write • cnt=b ##1 !a *[0:... • We always need a condition, in case there is no condition then use the trivial condition “1” • You can have multiple assignments: • (1, cnt=b, cnt2=c) • Can even have function calls and $display – useful for debugging – example ##1 (a==1, $display(cnt))
throughout • Often the assertions take the form: • after r is one, then r will go to zero and remain at zero for at least one cycle cycles, then it will raise. Check that cond1 is true for all the cycles in which r is zero • a.p. (r |-> ##1 !r [*1:$] ##1 r) is the assertion that checks that r goes to zero for at least one cycle and then rises.
throughout • a.p. (r |-> cond1 throughout (##1 !r [*1:$] ##1 r)) • checks that cond1 is true from the cycle in which r is one to the next cycle in which r is one included
throughout • a.p. (r |-> ##1 (cond1 throughout (!r [*1:$] ##1 r))) • checks that cond1 is true from the cycle in which r goes to zero to the next cycle in which r is one included
throughout • a.p. (r |-> ##1 (cond1 throughout (!r [*1:$])) ##1 r) • checks that cond1 is true during all the cycles during which r is zero
Finishing a simulation with assertions on • When finishing a simulation with $finish, all evaluation attempts of the assertions for which the enabling condition has already met fail (the implied sequence will not match because the simulation is ended) • Good to add $assertkill before $finish, this kills all ongoing evaluation attempts.