March 18, 2008
Migrating Complex Networking ASIC Verification Environment to SystemC and SystemVerilog
As the computer hardware industry strives to obey Moore’s Law, the telecommunication industry is following the even more rapid phenomena as described by Metcalfe’s Law: the potential number of contacts between each end computer increases rapidly, the effort to reduce the congestion at the network layer is greatly contributing to today’s system-on-chip (SoC) complexity. As more and more optimizations are added to the upper layer protocols, low layer complexity increases to facilitate overall system feasibility. Over the past decade, we have witnessed a dramatic increase in Gigabit Ethernet popularity. Today as we experience the deployment of 10Gig/Ethernet, the buzz indicates 100 Gig/Ethernet is likely in the near future.
Although technology has experienced steep growth, much of the success has resulted from too many short cuts. We now find ourselves working in a legacy verification environment that requires a severe makeover to make it applicable to the latest and greatest technology. As engineers witness rapid growth in both the computer and networking industries, we need to remind ourselves of the critical bottlenecks that will affect our future growth and make proper adjustments as a result. By following industry trends and adopting the latest advanced verification techniques, we will be able to make a positive impact on time to market. In this paper, we will explore how a legacy Vera-based ASIC environment evolved and re-invented itself - in the form of SystemC and SystemVerilog - in anticipation of future verification challenges.
The Legacy Code Phase-Out Process
It is important to note that migrating away from a legacy environment is not an overnight success. Often, the following questions keep legacy environments in existence:
- Is it necessary to completely move away from the legacy testbench?
- Why not keep the legacy environment and implement all future work with new methodologies?
Since a verification methodology closely resembles the software development process, in order to address the issues, it helps to understand Software Evolution’s 5th law – Conservation of Familiarity – which states that in general the growth rate of a system tends to decline. The research studies behind this law show that the “most likely principle source of declining incremental growth rates observed is increasing complexity as the system ages” . The cause of this declining growth can be attributed to “increasing internal interconnectivity and, hence, to deteriorating system structure, increasing disorder and complexity” . Here we see that the Law of Conservation of Familiarity serves as a good rationale for migrating away from a legacy environment.
Given the fact that the majority of the verification infrastructure gets carried over from one project to the next project, it is often hard - if not impossible – to completely and immediately break away from a legacy environment. In our case, we took a well-planned approach, phasing out the legacy environment over two years. Figure 1 depicts our approach towards the legacy environment phase-out process. Throughout this process, the two key objectives were to mitigate risk due to legacy code conversion and to bring added value to the overall productivity of the business unit.
Figure 1 Legacy Environment phase out process
In order to mitigate risk and to quantify porting success, we relied heavily on functional coverage. A great deal of effort was put into ensuring that Vera functional coverage was strictly correlated to that of the converted code base. Section 6 of this article is devoted to this topic.
In terms of value creation, a cost-benefit analysis was conducted to gauge whether a mixed SystemC-SystemVerilog environment would out-perform the benefit of having a homogenous SystemVerilog verification environment. The key consideration for the mixed SystemC-SystemVerilog environment was to minimize the verification team’s involvement with co-simulation. In an organizational structure where verification resources are far fewer as compared to its counterparts (i.e. the software team), it becomes highly evident that any effort to minimize the verification team’s involvement in co-simulation would greatly promote the business unit’s overall productivity. Ultimately this productivity gain matrix justified the additional complexity incurred due to mixed language debug.
In order to achieve co-simulation benefits in a shorter time frame, the decision was made to only convert the reference model into SystemC. An interim Vera-SystemC environment existed during the phase out period to verify the ported SystemC reference model's accuracy and the SystemVerilog convergence effort. A new SystemVerilog based testbench and additional test cases were written in parallel to ensure full functional coverage.
The remainder of this paper will detail our experience during reference-model conversion from Vera to SystemC. We will also talk about why SystemVerilog was chosen for the remaining verification infrastructure. However, since we did not perform Vera to SystemVerilog conversion, none of the porting challenges on that frontier will be discussed.
Evaluation and Measurement of Legacy Code Complexity
In projects, we often find that a complete, object-oriented, large-scale verification environment is maintained by many engineers with different coding styles and levels of expertise. Therefore, allocating sufficient time to do a proper, well planned legacy code-complexity assessment is the first critical step to conversion success. We have divided the legacy code assessments into two tasks:
- Language complexity categorization and correlation with respect to the new language of choice
- Data type/method access across the three major environment components (reference model, testbench and test cases.)
Language complexity categorization
During the language complexity classification stage of the code assessment, the use of various Vera language constructs were analyzed and categorized based on their level of difficulty. The assignment of difficulty level was based on whether a corresponding construct was supported in SystemC. Table 1 shows the mapping of various Vera constructs to SystemC. For Vera constructs that did not easily lend themselves to a trivial SystemC mapping, human judgment was required during conversion. Due to the fact that a script could not complete the conversion of these constructs, a high level of difficulty was assigned. Section 5 discusses various issues that may arise due to the use of human judgment and Section 6 discusses how functional coverage was used to verify porting success.
Data type/method access across the three major environment components
During the phase of complexity analysis, the focus was to identify data access across major environment components (reference model, testbench, and tests). For the purpose of porting, any cross-model access is marked and categorized as a red flag item. Two of the major porting issues found were:
- Tests were written with hierarchical access into the reference model
- Events were used to synchronize the test with respect to the reference model
Figure 2 Vera verification environment
Ultimately all data accesses across verification component boundaries were handled via Direct Programming Interface (DPI). For example, a test may use a set of DPI “import” functions to perform configuration and post-simulation statistics on the SystemC-based reference model.
Figure 3 SystemC & SystemVerilog based verification environment
New languages of choice: SystemC and SystemVerilog
Over the past few years, supporting software co-simulation was an enormous task with the Vera-based environment. A significant portion of co-simulation debug effort was focused on coaching a large number of software engineers on the intricate details of Vera constructs. As discussed in Section 2, based on value creation analysis, going forward the decision was made to choose a language that most software engineers are easily adaptable to. This gave rise to reference model implementation using SystemC. The goal is to integrate a SoC’s reference models as the final co-simulation environment to hand over to software teams for co-simulation debug.
Using SystemC for reference-model implementation does have a few caveats. For hardware engineers with little or no C++ language experience, the learning curve may effect scheduling. However, we considered this a one-time imposition, determined the investment would be worth the co-simulation returns in the long run.
Although SystemC shares many of the features of other Object Oriented languages, the two genuine concerns that we face today are difficulty during debug and poor randomization.
(i) Debugging simulation core dumps can be a tedious and daunting task. Furthermore, developers need to avoid common C/C++ pitfalls such as pointer manipulation, dangling pointers, memory leaks, etc. during the implementation. Debugging solutions to these problems are not supported by all EDA vendors. However, open source software such as Valgrind and Purify do offer solutions in this area.
(ii) SystemC provides limited random constructs and may leave engineers with Vera/e backgrounds feeling handicapped.
In an era where random testing is a decisive factor for successful silicon validation, one may not simply learn to live with the limitations imposed by SystemC. To address this issue, our methodology employs SystemVerilog for the construction of the remaining verification components – testbench, stimulus library and testcases. Unlike SystemC, SystemVerilog is rich in terms of random constructs and has a lot in common with Vera constructs. Engineers with Vera/Verilog background find a SystemVerilog transition easy, and SystemVerilog’s functional coverage is the pillar to our porting success. SystemVerilog’s DPI enables it to "call" C/C++/SystemC functions, and vice versa, making SystemVerilog the language to enable efficient co-simulation of SystemVerilog and SystemC blocks. We made use of the DPI to extend SystemC’s capability to perform functional coverage of SystemC reference models. For more information see Section 6.
In summary, the SystemC language is defined for verification from concept to implementation in both hardware and software. SystemVerilog is defined for hardware description and verification. Both SystemC and SystemVerilog are needed to verify a complex system due to coverage, randomization, and the ability to leverage existing C infrastructure.
Migrating from Vera to SystemC
Given the similarities between Vera and SystemC, an obvious migration methodology is translation. Source-to-source translation might have some issues depending on how close the languages are in their syntax and semantics. The simplest discrepancies are keyword clashes, unsupported constructs and user comments. Source-to-source translator script requirements are somewhat stringent. The script is limited by the output language and is required to produce semantically equivalent constructs. Manually converting thousands of lines of Vera code to SystemC is time consuming so we decided to write scripts in Perl. We wrote a script to map Vera to SystemC constructs wherever it was possible. There are constructs for which it was not possible to write a script, e.g. converting Vera mailbox and fork-join constructs. When extracting these constructs, one needs to be extremely careful so we converted them manually.
Table 1 shows the mapping of Vera constructs to SystemC that can be converted using a script. Table 2 shows which constructs must be converted manually.
Table 1 – Mapping of Vera constructs to SystemC (conversion using scripts).
Table 2 – Mapping of Vera constructs to SystemC (manual conversion).
There is no equivalent construct for a Vera mailbox in SystemC. It cannot be mapped to sc_fifo because sc_fifo does not have copy_wait and copy_nowait methods. So we decided to create a mailbox in SystemC that could be used to convert a Vera mailbox to SystemC.
The following example shows the conversion of Vera fork–join all and fork join–any to SystemC. Join all is simple compared to join-any. Since there is no equivalent construct for join-any in SystemC , we had to make use of sc_events to notify the completion of a spawned process and wait for any of the events to occur before proceeding.
Minimizing post migration debug
Vera mailbox constructs do not easily map into SystemC constructs. Prior to creating our own mailbox in SystemC, our initial attempt was to port all mailboxes to sc_fifo. Our Vera mailboxes are unbound, so in porting to sc_fifo an estimated depth was assumed. In some instances, the depth assumptions were not accurate and created functional misbehavior. One way to avoid such failures is to use the sc_fifo’s num_free() built-in function check prior to sc_fifo writes.
Unlike Vera, SystemC does not use the same semantics for bit access and bit-range access. Recall from Section 5 that SystemC uses the square bracket for bit access but for bit-range accesses SystemC uses parentheses. Our environment uses a large number of macro definitions to describe the bit and bit-range values. It is a tedious task to decide case-by-case whether the macro in question is describing a bit or a bit-field and then use either the square bracket or the parentheses. Improper usage may result in simulation core dump or worse yet, may result in incorrect behavior. In order to eliminate such issues, we incorporated the bit vs. bit-field bracket substitution as part of our porting script.
Porting Vera “case” statements to SystemC’s “switch-case” must also be reviewed if case conditions contain non-integer values (such as a sc_lv, sc_bv or bit-field extraction from one of these). In such an event, use of to_uint() is required since switch statements take expressions of type integer.
Verify porting success via Functional Coverage
To ensure porting success, we decided to implement and measure functional coverage between the Vera and SystemC testbenches. This comparison was made to ensure that the testcases are testing the intended scenario. SystemC has limited functional coverage capability; it doesn’t have in-built functional coverage constructs to directly measure the functional coverage of our SystemC reference model.
SystemVerilog's functional coverage extensions address these shortcomings by providing language constructs for easy specification of functional coverage models. SystemVerilog provides two unique constructs to answer the question of what is being tested: the first command group is coverage property and second is the covergroup. We made use of SystemVerilog's functional covergroup to capture points of interest in the SystemC reference model using DPI.
We started by defining coverage groups that contain cover points for the variables and expressions needing to be covered. The following example shows the definition of a SystemVerilog coverage group, used to cover the variable “enable”. Since the clocking event is not specified in the coverage group, we will trigger coverage collection using the sample() method.
The SystemC reference model instantiates scsv_fcov, which defines DPI calls to trigger the SystemVerilog functional coverage group. As shown in the example below, fcov->sample is called from SystemC with the value of the variable to be sampled. This call to sample ENABLE_SIG in turn calls ENABLE_CGI.sample() in SystemVerilog. After simulation runs, we merged the simulation results to see the functional coverage achieved. We had some testcases that were doing functional coverage query during run time. We made use of SystemVerilog's get_coverage method to map coverage in those scenarios.
Challenges and unresolved issues
As discussed in Section 4, debugging the SystemC code base – especially in the event of a core dump - can be onerous. A SystemC and SystemVerilog mixed language environment further complicates the debug effort. In the past, VCS’ Discovery Visualization Environment (DVE) suffered stability issues and developers resorted to the traditional C/C++ style of debugging. However, in more recent releases of DVE (VCS 2006.06-SP1), C-Bug shows better stability and we found DVE offered a viable solution for mixed language debug.
The verification engineers are moving towards SystemC and SystemVerilog as the languages of choice. Given the complexity of legacy verification environments, the process of creating a new yet comparable verification environment requires proper planning, code segregation and the use of appropriate languages. Converted code’s credibility can only be assured if proper functional coverage metrics are implemented. Mixed language testbenches impose even more difficulty during debug and reliable EDA tools such as DVE are crucial for productivity. With all such factors considered, we have been highly successful in converting multiple Vera-based legacy environments into robust SystemC/SystemVerilog mixed-language environments.
We would like to thank Shankar Hemmady for his valuable feedback
- Looking forward to 100G by William Jackson
- Practical methods in coverage-oriented verification of the merom microprocessor by Alon Gluska
- Rules and Tools for Software Evolution Planning and Management by MM Lehman
- Verification IP reuse for complex networking ASICs using a hybrid SystemVerilog/SystemC environment by Benjamin Chen