SLIDE 1 Real life experiences of PSL
Magnus Björk
Hardware Description and Verificatoin 2009-03-26
SLIDE 2 Saab Space / RUAG Aerospace
Was owned by SAAB group Sold to RUAG Aerospace, summer 2008 Most interesting division: Digital products
hardware systems
ASIC
software systems
Other products: antennas, frequency
converters, separation systems
SLIDE 3 To be launched by ESA in 2011 Surveillance of:
Polar ice (thickness, coverage) Continental drift, earthquakes Pollution (oil leaks in oceans) Forest fires …
Synthetic Aperture Radar
Sentinel 1 satellite
SLIDE 4
Sentinel 1 satellite
SLIDE 5
RUAG’s formal verification approach
Want to save effort (money) on
testbenches and debugging
Start by using FV on some small
modules
Increase usage with experience
SLIDE 6
Case studies
Old modules One module under development
(memory interface for Sentinel 1 Thermal Control Unit)
SLIDE 7 PSL: harder than expected
How to express that the PWT is in a certain state?
What is the minimal delay between packets currently set
to?
PWT
DmaAddr DmaReq DmaAck DmaRdy DmaReadData DmaErr PwtClock PwtValid PwtData PwtReady BusClk Reset Addr Wr WrData DMA interface Packet wire interface Control interface
SLIDE 8 Clarification: Packet delays
PwtData PwtClock PwtValid BusClock End of packet Start of next packet Minimal delay configurable (in nr of PwtClocks) PwtClock speed configurable (divisor of BusClock)
SLIDE 9 Attempt in PSL
impure function WritePwtRegV(register:integer, value:integer) return BOOLEAN … impure function SetClkMultiplier(mul:integer) return BOOLEAN... sequence initialize is {WritePwtRegV(PWT_CMDCLR, 1); -- no manual control WritePwtRegV(PWT_DELAY, DELAY); -- set minimal packet delay SetClkMultiplier(MULT)}; -- set transmission speed impure function deinit() return boolean is begin return WritePwtReg(PWT_DELAY) or WritePwtReg(PWT_CLK) or WritePwtReg(PWT_CMDSET); end function deinit; sequence deinit_seq is {{deinit()} within {[*MULT*(DELAY+1)]}}; prop_delay: assert always ({{initialize; not deinit()[*]} && {[*]; PwtValid; not PwtValid}} |-> {{not PwtValid[*MULT*(DELAY+1)]} |{deinit_seq}});
SLIDE 10 VHDL observers
Implement an observer in VHDL which
keeps track of specific properties
E.g. listen to writes to the register controlling
minimal delays
SLIDE 11 Adding an observer for packet delay
PWT
DmaAddr DmaReq DmaAck DmaRdy DmaReadData DmaErr PwtClock PwtValid PwtData PwtReady BusClk Reset Addr Wr WrData DMA interface Packet wire interface Control interface
Delay observer
CurrentDelay
Trivial VHDL implementation (~10 lines)
SLIDE 12 A new property
prop_delay: assert always ({PwtValid; not PwtValid} |-> {not PwtValid[*CurrentDelay]});
Indexing over non- constants may not be supported by tool!
SLIDE 13 Doing more in the observer
PWT
DmaAddr DmaReq DmaAck DmaRdy DmaReadData DmaErr PwtClock PwtValid PwtData PwtReady BusClk Reset Addr Wr WrData DMA interface Packet wire interface Control interface
Delay observer
DelayOk
Simple VHDL implementation (~20 lines) prop_delay: assert always(DelayOk);
SLIDE 14 VHDL in properties
Either 20 lines of advanced PSL Or 20 lines of trivial VHDL
More general
No constants MULT and DELAY Initialization not fixed
Easier to write Easier for designers to understand Easier for tools to handle
SLIDE 15
Combining PSL and VHDL
VHDL can be embedded in PSL PSL can be embedded in VHDL You are supposed to mix them! Mix them if it makes the verification
clearer
SLIDE 16
Bottom line
PSL is very powerful in many cases In such cases, use PSL! In other cases, VHDL is better suited In such cases, use VHDL!
SLIDE 17 A note on verification libraries
Open verification library (OVL) Questa verification library (QVL)
Mentor’s extension of OVL, also open
source
Open source verification libraries Contains loads of ready observers
Ranging from simple and, prev, and fifo to
advanced ones like USB 2.0 and AMBA.
SLIDE 18 Designing with verification in mind
Transmission logic Register bank DMA interface Serial interface Control interface Control interface is easier to use in properties Easy to verify formally
SLIDE 19 Designing with verification in mind
Transmission logic Register bank DMA interface Serial interface Control interface Spend less effort
SLIDE 20
Reactions from staff
Quick feedback to designers Short counter examples easy to
understand
Very intricate bugs found Easy to use, once there infra structure
exists
Expect to continue and increase formal
verification usage
SLIDE 21 Lessons learned
Different tools interpret PSL differently
Jasper: ”assume” statements are local to
the respective vunit
Mentor: ”assume” statements are global
Different tools support different subsets
In this case: Jasper correct according to IEEE-1850
SLIDE 22 More lessons learned
CTL and LTL are like assembly language
Low level, close to the underlying mechanism
PSL might be compared to C
Introduces convenient notation for common
constructs
…but we really want the equivalent of high
level languages like C++, Java, or Haskell
State machines, hierarchical structures (matching
begin-end-constructs), consensus about interpretation
Future work!
SLIDE 23
More on PSL
some examples, some pitfalls Based on Mary Sheeran’s slides from 2008
SLIDE 24
start idle p1 p2 p3 continue continue done cancel cancel
FSM
SLIDE 25 Low level assertions
assert always ((state = idle and start) -> next (state = p1)); assert always ((state = idle and not start) -> next (state = idle)); assert always ((state = p1 and continue) -> next (state = p2)); and so on…
good, but very localised
SLIDE 26 Low level assertions
assert always ((state = idle and start) -> next (state = p1)); assert always ((state = idle and not start) -> next (state = idle)); assert always ((state = p1 and continue) -> next (state = p2)); and so on…
good, but very localised
Bit-vector
SLIDE 27 Low level assertions
assert always ((state = idle and start) -> next (state = p1)); assert always ((state = idle and not start) -> next (state = idle)); assert always ((state = p1 and continue) -> next (state = p2)); and so on…
good, but very localised
constant
SLIDE 28 Low level assertions
assert always ((state = idle and start) -> next (state = p1)); assert always ((state = idle and not start) -> next (state = idle)); assert always ((state = p1 and continue) -> next (state = p2)); and so on…
good, but very localised
Implicit self-loop
SLIDE 29
Higher level assertion
assert always (not (state = idle) -> eventually! (state = idle) Note: not a safety property!
Will also likely need to link the state machine to the system that it is controlling and check that the desired functionality is achieved Message: try to raise level of abstraction of properties (while keeping them short and simple)
SLIDE 30 Example: simple bus interface spec (1)
- 1. 2 commands, read and write (with corresponding
signals)
- 2. Command can be issued only after requesting the bus,
indicated by a pulsed assertion of signal bus_req, and receiving a grant, indicated by the assertion of signal gnt one cycle after the assertion of bus_req
- 3. If the bus was not requested, it shouldn’t be granted
- 4. Command is issued the cycle following receipt of grant
- 5. Either a read or a write can be issued, not both
simultaneously
SLIDE 31 Example: simple bus interface spec (2)
- 6. Reads and writes come with an address,
- n addr[7 downto 0], that should be valid in the
following cycle
- 7. Address validity is indicated by signal addr_valid
- 8. If a read is issued, then one pulse of data on
data_in[63 downto 0] is expected the following cycle
- 9. If a write is issued, then one pulse of data on
data_out[63 downto 0] is expected the following cycle
- 10. Valid read data is indicated by data_in_valid and valid
write data by data_out_valid
SLIDE 32 Example: simple bus interface low level checks
2, 4. assert always ((read or write) -> ended(bus_req; gnt; true))
Built in function Returns true when the SERE has just ended
SLIDE 33 Example: simple bus interface low level checks
- 3. assert always (not bus_req -> next (not gnt))
SLIDE 34 Example: simple bus interface low level checks
- 5. assert never (read and write)
SLIDE 35 Example: simple bus interface low level checks
part of 6,7. assert always ((read or write) -> next addr_valid) assert always (not (read or write)
SLIDE 36
Example: simple bus interface low level checks
10. assert always (read -> next data_in_valid) assert always (not read -> next (not data_in_valid)) assert always (write -> next data_out_valid) assert always (not write -> next (not data_out_valid))
SLIDE 37
Example: simple bus interface low level checks
Have checked the protocol but not mentioned the addr, data_in or data_out buses Need to think about overall functionality as well as low level details
SLIDE 38
Example: simple bus interface high level checks
Let’s assume two input signals get_data and put_data indicating that a read or write is needed Assume also we have a way to recognise, at the assertion of get_data or put_data, the data that needs to be read or written (from address get_addr[7 downto 0] to read_buffer[63 downto 0] or from write_buffer[63 downto 0] to address put_addr[7 downto 0]) Assume also a suitable memory
SLIDE 39 Example: simple bus interface high level checks
assert forall ADR[7 downto 0] in boolean: always ((get_data and get_adr[7 downto 0] = ADR[7 downto 0])
eventually! (read_buffer[63 downto 0] = mem[ADR[7 downto 0]])) Notes: have made some assumptions e.g. about memory not changing after read included to show some of the fancier PSL constructs and use of bus structures
SLIDE 40
Main message
Write both low level and high level checks Low level checks will be easier to write – often transcribed from spec. High level specs consider desired functionality, which may be implicit in the spec. Hard to write but high pay-off For one approach to a methodology for use of PSL, see the Prosyd Eu project web page (www.prosyd.org) Contains many interesting examples both small and large (including the following example) OVL and QVL may be helpful to write higher level properties.
SLIDE 41 Common PSL errors
Mixing up logical implication and suffix implication assert always {req; ack} -> {start;busy[*]; end} assert always {req; ack} |-> {start;busy[*]; end}
assert always {req; ack} |=> {start;busy[*]; end}
Source: the PSL book (Eisner and Fisman)
Probably meant suffix implication:
SLIDE 42 Confusing and with implication
Every high priority request (req and high_pri) should be followed immediately by an ack and then by a gnt assert always (req and high_pri) -> next (ack -> next gnt)
assert always (req and high_pri) -> next (ack and next gnt)
assert always (req and high_pri) |=> {ack; gnt} Which? Why?
First attempt really means: Every high priority request that is followed immediately by an ack should be followed by a gnt.
SLIDE 43 Confusing concatentation with implication
Are any of these equivalent? assert always {a; b; c} assert always( {a} |=> {b; c} ) assert always( {a;b} |=> {c} ) assert always ( a -> (next b -> next[2] c)) assert always ( a -> (next b and next[2] c))
At all points in time, the sequence {a; b; c} begins. Silly property. More likely: assert never {a; b; c} a is always followed by b and thereafter c. Whenever a is followed by b, c follows. If a and thereafter b, then thereafter c. Equivalent! Equivalent
SLIDE 44 Confusing concatentation with suffix implication
Are these equivalent? assert always {a; b[+]; c} |=> {d} assert always {a; b[+]; c; d} Same mistake as last slide. assert never {a; b[+]; c; not d}
Equivalent!
SLIDE 45 Using never with implication
req is always followed by ack: assert always (req -> next ack) Two consecutive reqs are not allowed: assert never (req -> next req)
assert always (req -> next (not req)) Or Assert never (req and next req)
assert never {req; req} Which? Why?
General rule: a -> b = (not a) or b never (a->b) = always (a and not b)
SLIDE 46 Negating implications
High priority req gives an immediate ack assert always ((high_pri and req) -> ack) Low priority requests never give an immediate ack assert never ((low_pri and req) -> ack) ???? What should it be? assert always ((low_pri and req) -> not ack) assert never (low_pri and req and ack)
SLIDE 47 Incorrect nesting of implications (1)
If a request (assertion of req) is acknowledged (assertion of ack the following cycle), then it must receive a grant (assertion of gnt) the cycle following ack assert always ((req -> next ack) -> next gnt) assert always (req -> (next ack -> next gnt)) assert always ((req and next ack) -> next gnt)
a -> (b -> c) = (a and b) -> c (a -> b) -> c = (a and not b) or c Almost never seen
SLIDE 48 Incorrect nesting of implications (2)
If there is a granted read request (assertion of req followed by ack followed by gnt), then if there follows a complete data transfer {start; data[*], end}, then the whole thing should be followed by an assertion of signal read_complete. assert always ({req; gnt; ack} |=> {start; data[*]; end}) | => {read_complete} ?? Fault? Nested sequence implications does not make sense. What should it be? assert always ({req; gnt; ack; start; data[*]; end}) |=> {read_complete}
SLIDE 49
Are you missing a ”first match” operator?
On the cycle after the first ack following a request, a data transfer should begin assert always ({req; [*]; ack} |=> {start; data[*]; end}) ?? Wrong: Demands a transfer after every assertion of ack after the req. assert always ({req; ack[->]} |=> {start; data[*]; end})
SLIDE 50
”Extraneous” assertions of signals
assert always {ack} |=> {start ; busy[*] ; done} ack start busy done
SLIDE 51
”Extraneous” assertions of signals
assert always {ack} |=> {start ; busy[*] ; done} ack start busy done
SLIDE 52 May wish to rule out some behaviours
assert always (ack -> not (start or busy or done)) assert always {ack} | => {start and not busy and not done ; {not start and busy and not done}[*]; not start and not busy and done}
assert never (busy and done); assert never (busy and start);