The Portable Stimulus Specification (PSS) is all about reusing commonly used test atoms to create new scenarios more quickly. It saves us from wasting precious time recreating the same test information to verify the same functions throughout a single project or multiple projects.
Because the specification was developed to align with SystemVerilog constructs and principles, we can even extract data structures and constraints from our existing SystemVerilog environments to quickly build our stockpile of reusable test atoms.
Identifying existing formats and information within your organization that can be leveraged to create portable stimulus models flattens the adoption curve and boosts test-creation productivity. SystemVerilog classes and constraints are one such source of verification information you already have in-house.
In this article, we will reveal which SystemVerilog constructs are most easily reused in a Portable Stimulus Specification, and provide coding guidelines to make reuse simple and reliable.
Mapping a Path to Automation and Portability
Portable Stimulus allows test intent to be reused from the block level to the subsystem level to the SoC level (Fig. 1). It also enables a Portable Stimulus tool to create tests appropriate for the various test platforms on which that verification is carried out; typically, SystemVerilog for block and subsystem level and C tests for SoC level.
1. Portable Stimulus allows test intent to be reused from the block level to the subsystem level to the SoC level.
However, Portable Stimulus enables more than just test portability. It enables a high degree of automation in the test creation process. Furthermore, it lets the user describe tests at a far higher level of abstraction than is possible with techniques like SystemVerilog and UVM.
The mechanism behind this lies in the fundamental nature of Portable Stimulus: It’s a modeling language—not a programming language—and this is what enables much of its expressive power. One way to illustrate the distinction between a programming (implementation) language and a modeling language is to compare navigating with a paper map to navigating with a mapping program.
With a paper map, we spend most of our time dealing with how to get from our starting location to the destination. What highways should we take? Are there tolls involved? What is traffic inclined to be like when we drive through (although the paper map doesn’t give us traffic congestion data)? This is akin to a programming language, where we’re generally focused on implementing a given algorithm.
With a digital mapping program, we’re free to focus almost entirely on the what—where are we starting, where are we going, and what preferences do we have. The mapping program is able to analyze multiple options based on the wealth of data it has available and provides one or more good options for routing.
Portable Stimulus enables exactly this type of productivity boost over creating tests by hand. It allows a test writer to focus on modeling the rules that govern legal tests, and then specify preferences and goals around the specific tests that must be generated. Automation subsequently takes over and, much like a mapping program, generates tests that adhere to the rules about what constitutes a legal test and satisfies the goals and preferences expressed by the user. PSS encourages us to think about what we need to test and lets automation deal with how to create those tests. This allows us to make better use of test-creation automation.
SystemVerilog to PSS Reuse Flow
When it comes to reuse of SystemVerilog content in a Portable Stimulus Specification description, a high degree of automation is key. The source SystemVerilog description is fluid and will change over the lifetime of the project. Requiring a human to identify modifications to the relevant SystemVerilog source and update the PSS representation is labor-intensive, as well as being error-prone.
A typical SystemVerilog-to-PSS reuse diagram looks something like Figure 2. The primary source for shared data structures and constraints on those data structures is maintained in SystemVerilog. PSS representations of those data structures and constraints are derived directly and automatically from the SystemVerilog representation. This generated PSS description is then leveraged in user-created PSS descriptions.
2. This is a typical SystemVerilog to Portable Stimulus Reuse flow.
Given that the bulk of verification today is done using SystemVerilog, it makes sense to find what elements of your existing SystemVerilog descriptions can be easily and reliably reused in a PSS description.
Restructuring SystemVerilog for Portable Stimulus
Now we’ll use coding examples to present best practices for restructuring SystemVerilog for reuse. Specifically, we will share basic practical concepts and coding guidelines that make SystemVerilog classes, constraints, and covergroups more amenable to automated reuse in a PSS description.
Because so much content has already been created in SystemVerilog, leveraging portions of SystemVerilog-based descriptions you already have in-house will accelerate creation of PSS descriptions, delivering immediate productivity benefits.
The guidelines presented in this article for structuring SystemVerilog for reuse reflect a preference for a fully automated flow to reuse information that’s captured. They reflect best practices that evolved from the experience of users of the Questa “inFact” Portable Test tool from Mentor.
Focus on the Constructs
SystemVerilog is a fully featured language for register-transfer level (RTL) design and verification. As such, it includes constructs inherited from the Verilog language for describing hardware constructs. It also includes object-oriented programming constructs as well as constructs for automated stimulus generation and functional coverage collection. These are used for verification of a hardware description.
The PSS language is predominantly a declarative language, with a few procedural constructs. In contrast, SystemVerilog is predominantly a procedural language with a few declarative constructs.
Due to the declarative nature of PSS, the declarative constructs in a SystemVerilog description are easiest to reuse as part of a PSS description; specifically, data structures and constraints on the fields of those data structures, as well as covergroups, used to model functional coverage goals. In general, design patterns that negatively impact reuse of SystemVerilog descriptions are those that blend procedural and declarative description or affect encapsulation of a declarative description.
In most cases, the best practices that enable reuse are also simply good SystemVerilog coding practices that result in well-encapsulated code. Of course, there are cases where it’s pragmatic or necessary to use constructs and patterns that limit reuse. Even with these cases, a little foresight can maintain a sensible balance between reusable constructs and pragmatic design patterns.
The goal in structuring SystemVerilog for reuse is to create self-contained elements that can be extracted from the SystemVerilog description and added to the PSS description. Let’s now take a detailed look at some of these elements individually to see how this can be done.
Inline Randomization Constraints
SystemVerilog allows inline constraints to be specified when an object is randomized. This can be a handy way to customize random transactions to create directed-random test sequences. Figure 3 contains a directed-random test that leverages an existing transaction class and inline constraints to perform a series of reads and writes.
3. Directed-random tests can leverage an existing transaction class and inline constraints to perform a series of reads and writes.
While this design pattern in a SystemVerilog testbench can be very useful, it does limit reuse. The inline constraints are introduced in a procedural block and often will include references to variables within that procedural block. Consequently, reusing these inline constraints is difficult if not impossible.
Inline constraints can also be abused, of course. The author has worked with testbench environments where up to 100 lines of inline constraints were specified simply to ensure valid relationships between class fields. Worse, these large blocks of inline constraints were copied across multiple tests, resulting in a maintenance headache when these base constraints needed to be adjusted.
You can increase code maintainability and reuse by factoring common constraints out of inline constraint blocks. Figure 4 shows how the read/write inline constraint is factored out by creating a read transaction and a write transaction class. This increases test readability and maintainability, and it provides more specific elements that can be reused in a PSS description.
4. The read/write inline constraint is factored out by creating a read transaction and a write transaction class.
Dynamic Enabling/Disabling of Constraint Blocks
Another interaction between SystemVerilog procedural code and declarative constraints is support for dynamically enabling and disabling constraint blocks. Under ideal circumstances, dynamically disabling constraints is used in very limited cases to do things such as enabling generation of illegal transactions.
A highly problematic use of dynamic constraint-block control is where at least one block must be disabled for randomization to complete successfully. Figure 5 is an operation sequence-item class that specifies two conflicting constraints—one that sets "normal" operating modes, and another that sets "extended" operating modes. The user of this class must know to disable at least one of the normal_mode_c or ext_mode_c constraints prior to randomizing the object.
5. An operation sequence-item class specifies two conflicting constraints—one that sets “normal” operating modes, and another that sets “extended” operating modes.
From a reuse perspective, the use of dynamically controlled constraints presents two challenges. The current PSS language doesn’t provide facilities for dynamically controlling constraints. So, at a minimum, additional changes will be required in the PSS description to adapt the description imported from SystemVerilog. Second, the use of conflicting constraints presents a usability challenge in both SystemVerilog and PSS descriptions. Valid combinations of enabled/disabled constraint blocks must be documented somewhere. At best, the valid enabled/disabled constraint blocks will be captured as a comment that will likely not propagate to the PSS description. At worst, the valid combinations of enabled/disabled constraint blocks are “tribal knowledge” captured in working test sequences.
Using class hierarchy and constraint overloading instead of dynamic constraint enable/disable results in SystemVerilog sequence items that are easier to use, and a SystemVerilog description that’s easy to reuse as part of a PSS.
There are two equivalent approaches to structuring a class hierarchy to handle cases often implemented using dynamic constraint enable/disable. The first approach, additive constraint refactoring, is written in Figure 6. Using this method, derived classes add in just the constraints needed to achieve their intended purpose.Therefore, the normal_op_item class adds constraints to ensure that only “normal” modes are produced, while the ext_op_item class adds constraints to ensure that only “extended” modes are produced. This approach is a good general approach.
6. With the additive constraint refactoring approach, derived classes add in just the constraints needed to achieve their intended purpose.
The second approach, subtractive constraint refactoring, is more often used to create exceptional use cases, such as error injection. Taking the example used thus far, let’s assume that “normal” modes are the ones used most of the time.
Figure 7 presents the definition of the normal_op_item class with constraints that enforce “normal” operation. To create the “exceptional” condition that could be created by disabling the ‘normal_mode_c’ constraint, the ext_op_item class overrides the normal_mode_c constraint with an empty constraint, effectively disabling this constraint in a declarative way.
7. Subtractive constraint refactoring is more often used to create exceptional use cases, such as error injection.
Using class hierarchy and constraint refactoring results in more-reusable classes in SystemVerilog environments. It also results in SystemVerilog descriptions that are reusable in a PSS description by moving controls from the procedural description into the declarative portion of the description.
Reusable Functional Coverage
SystemVerilog covergroups provide an exceptionally flexible construct for monitoring and aggregating testbench data. However, the exceptional flexibility of the construct impacts its reusability.
In Figure 8, we have a SystemVerilog covergroup structured in a way that's ideal for reuse in a PSS description. All of the coverpoints and cross-coverpoints reference the config_item class field item specified as a parameter to the covergroup. This ensures that the covergroup is self-contained.
8. Configuration class and functional coverage of SystemVerilog covergroups are ideal for reuse in a PSS description.
In addition, the class monitored by the covergroup is the same class used to generate stimulus. Thus, configurations can be generated that efficiently satisfy the coverage goals without the user providing additional directives to relate the stimulus-generation class to the class used to capture coverage data.
The PSS standard allows a single representation of test stimulus, expected results, and coverage goals to be captured in a description that can be reused across test environments. Using the PSS language brings a range of benefits, including portability across verification levels and greater test-creation productivity. As we’ve seen in this article, reusing the wealth of existing SystemVerilog descriptions, such as transactions and device configuration classes, allows users to more quickly take advantage of the benefits of Portable Stimulus tools such as efficient closure on test goals and automated creation of tests.
Using the best practices for modularity and reuse described above helps enable reuse across SystemVerilog environments and PSS descriptions. To summarize, best practices include:
- Avoid use of inline constraints.
- Avoid enabling and disabling constraints from procedural code.
- Avoid referencing class-external variables from constraints.
- Structure functional coverage descriptions to explicitly reference a single class, ideally a stimulus-generation class.
Mentor’s Questa inFact can help achieve these benefits by providing support for developing scenario-level models with PSS. In addition, it allows you to reuse classes and covergroups from your SystemVerilog testbench and generate stimulus in a more-efficient manner.
Matthew Ballance is a Product Engineer and Portable Stimulus Technologist at Mentor, a Siemens Business.