Managing code coverage to achieve verification closure in low-power SoCs
A look at some of the key techniques needed to ensue good code coverage during the verification of low-power SoC designs.
Low-power SoC designs use multiple coding styles and include complex power-aware and non-power aware macro models. They have multiple power domains, each of which may have multiple operating modes, dynamic voltage levels, and power management units that sequence the actions of power-control sub-systems. This article, adapted from a 2018 DVCon presentation given by members of the verification team at Mentor, a Siemens business, explores issues surrounding the verification of low-power SoCs.
In a typical low-power simulation, power-aware cells and power-control logic are added to the design RTL, which means that the RTL which gets simulated is different to what the designer wrote. Verifying the design’s functionality therefore means generating test vectors to exercise the original code, the additional power elements, and the interactions between the two sets of functions.
There isn’t a standard way to ensure good coverage of low-power designs, because neither the Unified Power Format (UPF) Language Reference Manual nor the Accellera Unified Coverage Interoperability Standard covers the issue. Instead, many verification engineers take an ad-hoc approach, building on the UPF standards and the facilities of verification tools. However, it is still difficult, error-prone and time-consuming to develop effective RTL code coverage for a low-power design.
A power-intent specification and the basic concepts of UPF
The IEEE’s 1801-2015 UPF standard enables designers to specify their power intent for a design. It is based on Tcl and provides concepts and commands for describing the power- management requirements for IP blocks and SoCs.
A power-intent specification in UPF is used throughout the design flow, and may be refined at any point in the design cycle. Some of the key concepts and terminology include:
- Soft macro: An instance that is represented by the original RTL and UPF. Ancestor power-intent objects are not available for use within the scope of the instance.
- Hard macro: A block that has been completely implemented and can be used as it is in other blocks. This can be modelled by a hardware description language (HDL) module for verification or as a library cell for implementation.
- Corruption semantics: The rules defining the behavior of logic in response to the reduction or disconnection of power to that logic.
- Power state: The state of a supply net, supply port, supply set, or power domain. This is an abstract representation of the voltage and current characteristics of a power supply, and of the operating mode of the elements of a power domain or of a module instance e.g., on, off, sleep.
Basic concepts of code coverage
Code coverage is a way to assess the progress of functional verification. It helps verification engineers understand how well a design has been verified and which areas need more work.
Code coverage metrics are collected automatically by verification tools and tell the user how thoroughly a design’s HDL has been exercised by its testbench during simulation.
Functional coverage measures how well a design’s functionality has been covered by a testbench. Users have to define the functionality to be measured using covergroup and assertion constructs. Functional coverage done using covergroups or assertions does not have much impact due to low-power semantics and can be achieved in low-power designs easily.
There are different categories of code coverage:
- Statement coverage/line coverage: This indicates how many statements (lines) are covered in the simulation, by excluding lines such as module, endmodule, comments, timescale etc. Statement coverage includes procedural statements, continuous assignment statements, conditional statements, and branches for conditional statements. It has to reach 100% for verification closure.
- Conditional/expression coverage: This indicates how well variables and expressions (with logical operators) in conditional statements are evaluated. Conditional coverage is the ratio of number of cases evaluated to the total number of cases present.
- Branch/decision coverage: In branch coverage or decision coverage reports, conditions such as if-else, case, and the ternary operator (? : ) statements are evaluated in both true and false cases.
Achieving 100% code coverage in low-power designs
Verification engineers used to have standard and low-power versions of a design, each with its own regression set-up. Users would rely on the code coverage of the standard design and the power object’s coverage of the design’s low-power version to reassure themselves that they were achieving full design coverage. Now all designs have to be power-aware so the code-coverage metric needs to be collected on the low-power design as well.
A regression setup for a low-power design still has two parts. The first focuses on verifying the non-power aware functionality of the design, as if everything within it is always on. The second focuses on verifying the low-power functionality of the design. Typically, in a low-power design, some of the RTL is covered by the non-power aware regression and the rest is only covered when low-power regressions are completed. Together, they achieve full structural code coverage of the design.
Typically, the RTL model of a low-power SoC consists of soft macros, hard macros, power controller logic, a testbench and checker/coverage modules. Hard macros can only be simulated if they have been supplied with models that define their behaviour. Ideally these should have power-aware behaviour models with a power management interface, because code coverage of these models will not be affected by power artefacts introduced by UPF. Test vectors for voltage-controlling logic, such as that within the power management controller, should be modelled in the testbench.
Challenges in code coverage of low-power instrumented designs
In a low-power simulation, the RTL design code is passed to the tool along with a UPF file. The tool inserts isolation, level-shifting and other power-management cells into the design RTL, and may also add logic to enable power-aware simulation. As a result, the original RTL may not be the same as viewed in the source file. This creates challenges in low-power code coverage including:
Controlling PA logic inside ifdef
In some designs the power-aware (PA) logic is modelled inside a block with “ifdef PA”. That is, the block only gets activated and covered when low-power simulations are run.
- Use the ifdef PA method to guard the low-power functionality and avoid enabling the PA code in non-PA runs.
Functional coverage measures how well the functionality of the design has been covered by your testbench. The user defines the functionality to be covered, in two forms:
- Coverage of assertions (checker logic): In a low-power simulation run, assertions can be triggered when the power is turned off. This creates false alarms, which simulation tools should avoid by disabling the assertions and coverage of the assertions during the powerdown period.
- Covergroup-based coverage: Functional coverage done using covergroups does not have any impact and can be easily achieved in low-power designs.
Power control logic: power-aware coverage
In a low-power design, it is important that the power control unit creates complete test vectors to verify all power elements and the complex interactions between these elements, at a higher level of abstraction. Achieving closure for a low-power design involves ensuring that all its power objects are covered in all possible states and transitions.
Challenges in coverage of low-power designs with hard macros: power-aware behavior model
Low-power designs that use hard macros need access to models that describe the macro’s power-aware behaviour in a way that is only visible when the UPF connections are made. These behavioral models:
- Don’t include the power pins in the portlist, but do declare them as wires.
- Declare the input power supplies as registers, and initialize them to their definitive logical values.
module ana_mac(… ip1, ..) … wire vdd = 1; wire vss = 0; always @(vdd, vss, clk) begin if (vdd === 1’b1 && vss === 1’b0) d = clk & a1; else d = 1’bx; end
The simulation tool makes UPF connections to the Vdd and Vss supply pins, and does not insert any power-aware logic into the model.
The following items need to be considered to ensure good code coverage of such models in a low-power design:
- RTL code coverage is handled as normal user RTL, because the tool does not insert any PA logic instrumentation within these blocks.
- Toggle coverage of supply pins (Vdd, Vss) is not considered because these are covered in PA coverage.
- Use ‘PA BehaviorModel’ or ‘All pins model’ approach to do macro modeling of hard IPs.
- Use //coverage off pragmas on UPF supplies modelled in RTL, because toggle coverage is not expected on these signals.
Soft macros: RTL modelling of IPs
In a low-power simulation, RTL code is passed to the tool along with a UPF file, which inserts isolation, level-shifting and other cells into the design. It may also insert some logic to enable power-aware simulation. This modifies the original RTL.
Consider this simple combinatorial logic:
always @(*) out = in1 & in2;
Normally, whenever ‘in1’ or ‘in2’ changes, the statement is reached. If, in a low-power simulation, power to this part of the design is Off, then the statement is not reached, and the signal ‘out’ will get a value ‘x’. When the power is enabled, the assign statement will get triggered. Moreover, the number of times this statement gets triggered now also depends on the block’s power status, along with ‘in1’ and ‘in2’.
There is no way in RTL code coverage to capture the activity in the block because of new powering logic.
Coverage of inserted code
Verification tools add statements to design RTL so they can simulate its power-aware behaviour. These additional lines change the numbering of the design RTL statements, creating inconsistencies between the original design code and the power-aware code which mean that code-coverage analyses produce incorrect results. We can see this in Figure 1, below:
Figure 1 The impact on line numbering of adding PA logic to a D flipflop
In addition to introducing new lines/statements into RTL logic, some power logic gets inserted into RTL statement in case of expressions. Consider the following example:
Actual RTL expression:
assign c = a&b;
Power-aware instrumented RTL expression:
assign c = (PWR) ? (a&b) : 1’bx;
The input terms for the original expression are a and b. Once power logic has been added to the RTL, the input terms that need to be addressed for code coverage become PWR, a and b. This means that the code coverage results for the two expressions will be inconsistent.
Verification tools may insert new branches into the design RTL as part of making it power aware. This also leads to inconsistent code coverage results for standard and power-aware versions of the design, as the insertion of branch statements affects line numbering.
Insertion of low-power logic also affects toggle coverage. Toggle coverage is used to report how many times signals and ports are toggled during a simulation run. If power logic is inserted into the design RTL, many signals and ports are likely to toggle more often, once again invalidating code coverage results. Consider Figure 2:
Figure 2 Change in sensitivity list can affect Toggle coverage
The always block is triggered whenever there is an activity on the PWR signal, even though there is no activity on signal a. With no activity on signal a, toggle coverage for signal t will be zero in the case of a standard simulation. Once power logic has been added, whenever there is an activity on the PWR signal, signal t will toggle, thus achieving 100% toggle coverage for signal t.
Finite state machine coverage reports identify whether a simulation run could reach all of the states and cover all possible transitions, or arcs, in a given state machine. In a standard simulation, the user assumes the design is powered throughout the simulation run and defines the states and conditions required for an object to reach a particular state. During a low-power simulation, when power is removed the object is left in an arbitrary state. Verification tools reflect this uncertainty by adding new states to the state machine, for example xx. Once again, the tool’s efforts to reflect the impact of adding power-management features to a design is to undermine the code coverage metrics. Consider Figure 3:
Figure 3 Adding PA instrumentation introduces a new state to an FSM
When the power goes down in the low-power version of the FSM logic, the value of the state becomes 2’hx. Since the user’s RTL design does not define a state associated with that value, verification tools create a new state (say, xx) to ensure the object is in some state during the simulation run. Since FSM coverage reports show how many states and transitions in between these states are hit during the simulation run, the introduction of the new xx state gives improper results.
Addressing the challenges of code coverage in low-power designs
How do we visualize code coverage results for low-power designs, given these issues?
For line coverage, one way of handling the mismatch of code line numbers before and after the insertion of power-management logic is to simply exclude the coverage of the resultant new lines and statements. In Figure 1, this would involve excluding coverage of the statements on lines 2, 3, and 4. Another approach is to set the line numbers of the statements to a very high or negative number so that they don’t affect the line numbers of the original design RTL.
Look again at this example code from earlier in the white paper:
Actual RTL expression:
assign c = a&b;
Power-aware instrumented RTL expression:
assign c = (PWR) ? (a&b) : 1’bx;
The power-aware instrumented RTL expression has been modified to include power logic without introducing any new lines/statements. But the modification has increased the number of input terms to the expression and therefore expression coverage metrics will not give the same results as on the design RTL.
To fix the problem, one can exclude the new input terms and so ensure that the expression coverage will only depend on the design RTL.
The issue with calculating branch coverage is that adding power-aware logic to a design I introduces new branches, which changes the line numbers of the original RTL and also gets included in branch coverage.
The solution is to exclude coverage of these new branches. In Figure 1, for example, this would mean excluding branch coverage for newly added branches on lines 2 and 9. As before, another approach is to set the line numbers of the statements to a very high or negative number so that they don’t affect the line numbers of the original design RTL.
Adding power logic to the design RTL can cause signals and ports which are either unused or unchanging in the design RTL to start toggling, creating false toggle coverage results.
As we can see in Figure 2, the always block can get triggered whenever there is activity on the PWR signal, even though there is no activity on signal a. This makes signal t toggle. Since there is no way in RTL code coverage to exclude toggling activity caused by the addition of power logic, there will always be a difference in toggle coverage results between the design RTL and the power-aware version.
Introducing new states to an FSM because of the insertion of power-aware logic, for example to ensure that an object is in a particular state (e.g. xx) during a simulation run, will create different coverage results to those for the original design RTL. One way to tackle this issue is to exclude these states.
Complex power-aware instrumentation
In practice, it may not be as straightforward to apply the techniques discussed above to preserve the validity of coverage metrics on complex designs. Consider the example in Figure 4, below, in which a retention strategy has been applied to a simple D-flipflop:
Figure 4 PA instrumentation of restore and save processes on the output of a D-flipflop
To ensure the state of each register in this example is retained during power cycling, its behaviour has to be modified. This leads to a change in the process sensitivity list and the body of the process for each register. An additional process is also created for the saved state.
Working out what to exclude from the modified code is complex and therefore demands meticulous analysis and the development of further tool support.
Achieving coverage closure in low-power designs
Achieving verification closure of design takes both full code coverage and full functional coverage, of both the original design and its low-power variant. Low-power coverage data helps to ensure that regression suites adequately test the power-aware elements of the design, including dynamic power-aware checks and power-aware states and transitions, as created through the UPF file with the add_power_state, add_port_state and add_pst_state commands.
The SystemVerilog construct “Covergroups” help in sampling signal/property activities at desired sampling points through coverpoints and bins. These are used to collect coverage numbers of states and their transitions. A low-power coverage methodology that combines UPF 3.0 HDL functions with SystemVerilog coverage constructs can also help the user to write fast and reliable low-power coverage infrastructure.
Power/port/PST states capture how the designer wants the low-power design to operate, and hence have a huge impact on the functionality. It is therefore essential to verify the occurrence of various states and their transitions to ensure the proper operation of a low-power design as well as to achieve verification closure for it.
Low-power coverage metrics include:
- Power/port/PST state coverage, which ensures that all the states are exercised during verification.
- Power/port/PST transition coverage, which ensures that all valid transitions are covered and that any illegal state transitions can be identified.
- Cross-state coverage, used to verify the interactions of multiple interdependent power domains and therefore the placement of power-management cells.
- Sim mode coverage, which ensures that all specified sim states of supply sets and their transitions are covered during verification.
- Save/restore event coverage, which ensures that a proper save/restore event happens for each power-management strategy at least once during verification.
- Switch_port coverage, which ensures that all the states on the control_ports and ack_ports of power switches and their transitions are covered during verification.
- Isolation_signal coverage, which ensures that the Isolation signal is toggled during verification.
It’s possible to define other coverage metrics, based on different properties of upf objects and design requirements, to calculate a low-power coverage metric which, when combined with code coverage, results in the full verification closure needed for low-power SoC designs.
Webinar: Automating Code Coverage Closure with Questa CoverCheck
This webinar introduces the Questa CoverCheck methodology that automates and accelerates the process of code coverage closure.
Webinar: Injecting Automation into Verification – Code Coverage
This webinar introduces the use of code coverage in today’s HDL design and verification flows.
Whitepaper: Unveil the Mystery of Code Coverage in Low-Power Designs: Achieving Power Aware Verification