Portable stimulus helps bring advanced verification capabilities to a C-based high-level verification environment.
A little over a decade ago, electronic system-level (ESL) methodologies were all the rage, and there were a number of language options that promised to raise the abstraction level for both design and verification, with C/C++, SystemC, and SystemVerilog being the dominant ones. While C/SystemC are the most prevalent languages for abstract hardware and system modeling, SystemVerilog has standardized the necessary features needed for advanced verification; such as constrained random stimulus and functional coverage.
At the same time, many high-level synthesis (HLS) users have been looking for more efficient ways to describe stimulus, specifically looking for ways to expand the number of verification scenarios that can be automated from a compact description. They also seek to improve the efficiency of the test generation process. A rule/graph based approach provides these capabilities, and because rule-based models are independent of the target language, they have always been a portable stimulus solution.
HLS users often state that one of the major benefits they receive by moving to C++/SystemC for design is better performance for verification, because it enables them to run substantially more tests. A portable stimulus solution allows them to leverage these tests downstream when the RTL is wrapped in SystemVerilog.
This article describes a methodology where, a stimulus model can be defined (and refined) to help reach 100% code coverage of the C++ HLS DUT, and then reused in a SystemVerilog or UVM testbench with the synthesized RTL. Given a truly common model, it is also possible to maintain random stability between the two environments, allowing some issues to be found in one domain and then debugged in the other.
The common stimulus model
The rule-based stimulus model is created hierarchically from a main top-level rule file—which typically varies very little from a default template—and one or more modular rule segment files (Figure 1).
Figure 1 Hierarchical rule code architecture
Both top-level rule files (at the top left and top right) import a common hierarchy of rule segment files that actually define behavior; e.g., the test_data_gen.rseg file defines the rule for the scenarios that the graph can generate. By keeping all the definitions of the rules hierarchy in common files, the compiled graph models will behave identically.
The test_data object itself, declared as a struct in the rule language, is defined in a separate rule segment file, to allow for modularity and reuse.
The integration of the portable stimulus model into the C testbench is quite simple. The architecture is similar to SystemVerilog randomization or the method used in SystemC/SCV; i.e., an instance of the data structure is passed as an argument to a graph method called ifc_fill.
At this stage, the portable stimulus model adds the ability to randomize several numeric values, while obeying any algebraic constraints defining their relationships.
An additional value of the rule-based approach is that another type of input can be overlaid on the stimulus model, which is termed a coverage strategy. This strategy can be considered somewhat analogous to a SystemVerilog covergroup, in that it defines the variables of interest, desired bins of these values, as well as crosses of these variables. The difference is that this is an input to the randomization process that alters the random distribution to more efficiently cover the goals in the strategy.
Rule-based tools can include utilities that create coverage strategies from a variety of inputs, including automated strategies of pre-defined types, custom strategies defined using a CSV file or spreadsheet, and a graphical editor.
On an example multiplier RTL DUT, an automated strategy can be used that targets each stimulus variable in isolation; i.e., no crosses. After running this automated strategy to completion on the multiplier, the code coverage result was 100% (the results from the initial pure random test approach were about 20% lower).
Portable stimulus with random stability
When running in the C simulation, a seed for the stimulus model can be defined by a user or simply output to a file. Then the SystemVerilog wrapped version of the stimulus model can be dropped into an SystemVerilog testbench to drive the RTL DUT in the same way, picking up the same seed. When the SystemVerilog testbench was run, the code coverage produced for the RTL DUT was also high—97.11% in this case—as shown in Figure 2.
Figure 2 SystemVerilog code coverage result
Of course additional tests are always likely to be needed for the RTL version of the DUT to handle the additional behavior added to the synthesized RTL. This is because the HLS process adds additional structures that do not exist in the untimed C++ source description; such as stallable interface protocols, control FSMs, and clock and reset logic. However, by closing 100% coverage on the C++ using a portable stimulus model, we are guaranteed to get the same coverage of the design functionality when running RTL verification. Then it is simply a matter of adding additional tests to cover the remaining structures added by HLS.
Portable stimulus solutions help bring advanced verification capabilities to a C-based high-level verification environment. They also allow reuse of the investment in the stimulus models and coverage information at other levels of abstraction. For the HLS user, portable stimulus gives them a standards-based methodology to predictably and quickly close coverage from C to RTL.