United Business Media EE Times


Search

HOMEMARKET INTELLIGENCE UNITFORUMSDESIGNNEW PRODUCTSCAREERSBLOGSCONTACTEVENTSSIGN UP!RSSMost Popular contentTrusted Sources

 



design flow

Practical Approaches to Improving ASIC Verification Efficiency

Code coverage analysis can simplify developing test benches as well as verify them. It can help order tests as well.

by Stuart Riches and Martin Abrahams


Statistics show that software coding, even when done well, has 1 to 3 defects per 100 statements. That's too many errors for any application, let alone for ASIC design, in which undetected errors become embedded in the final product. It's not surprising, therefore, that software verification is a major aspect of ASIC development, accounting for more than half of the end product's labor costs.

One of the reasons for the high cost of testing, as E.W. Djikstra of the University of Texas, Austin, neatly put it in 1960, is that "testing can only show the presence of errors and not their absence." It's not possible to tell when the design code is free from defects, so you never really know when it's safe to stop. As a result, the tendency is to overtest, raising costs with constantly diminishing returns.

In usual practice, ASIC design and verification teams concentrate on using simulation tools to develop test benches for their designs. Their main way of doing that is to use the functional testing approach--that is, they develop test data based on documents that specify the behavior of the hardware, with little regard for its internal logical structure (see "Test Techniques"). Introducing some additional testing techniques can increase the effectiveness of that test approach, thereby reducing both the cost of and the time required for testing (see the figure).

In particular, measuring code coverage, which is now standard practice in our ASIC design handoff, can be used for more than just verification. Code coverage analysis reduces the design cycle time and provides the design engineer with fine-grained insight of simulation behavior. Once the data are close at hand, it becomes possible to make time- and labor-saving optimizations in the design cycle.

Up-front code coverage
In designing local-area network devices at Texas Instruments' Network Business Unit, TransEDA's VHDLcover code coverage measurement tool has been used so effectively that the design team proposes to make up-front code coverage analysis its standard approach. Moreover, it has plans to examine further applications for code coverage data in two nontraditional ways: first, to reduce the effort required to develop the test bench, and second, to produce an optimal ordering of tests to execute, which increases the likelihood of finding errors earlier in the process.

Accelerating test bench development
A typical test bench used at the Network Business Unit consists of a VHDL wrapper inside which the complete VHDL model for the design is instanced. The wrapper itself is programmable, its function being determined by a VHDL package body. The package body is obtained by selecting one entry from a test suite--that is, a library of test cases. Each test case in the suite is written to exercise an independent function of the design.

The process used for developing test cases relies heavily on translation of the design specification. Usually the scope of the test suite is defined at a brainstorming meeting, which produces an initial list of required tests. Individual tests have to be written and debugged, and periodically--as the design itself is constantly modified by adding new features, fixing bugs, or both--the entire test suite must be simulated to validate the status of the design VHDL; that is, it must be regression-tested (see "Test Approaches"). Code coverage analysis is normally not performed until the final regression is run, just prior to handoff.

Figuring out a priori what test cases are required is far from easy. For one thing, the initial list of tests typically covers only half the requirement. Test cases may target the right areas but lack sufficient detail to completely exercise the functionality. Worse, specification changes during the design cycle may be captured in the design itself but omitted from the test cases. The sign-off requires only statement coverage, so frequently little attention is paid to more detailed measures. Time pressures force patching of the test suite rather than structured design.

Figure A project verification review mechanism

The regular project approach to functional testing has been augmented with structural testing using code coverage and a directed approach to code inspection.

Making code coverage analysis a regular checkpoint during the design cycle reduces some of those effects and lessens the time it takes to produce a complete test bench. During the design of the TNETE223 mixed-signal transceiver, the design team used VHDLcover to provide regular feedback to both the design engineers and to the test bench developers. The information was intended to complement what was already known about the testing requirements. The TNETE223 was chosen because a very tight design schedule required an alternative approach to ensure both functionality and completeness. Another motivation was that many of the test case writers were unfamiliar with the design, and there are few ways to encourage familiarity that are better than undertaking a code coverage analysis.

Independent testing
It's important that the test case writers haven't contributed to the writing of the design VHDL itself. Such independent testing ensures that the test cases are written to find errors and not to demonstrate that the design is wonderful. It also follows, therefore, that a third, independent group should perform code coverage analysis because it has the responsibility to find errors in both the design and the test suite.

Table 1 Test case evaluation
tc1 tc2 tc3 tc4 tc5 tc6 tc7 tc8
file1 10 10 10 10 10 10 10 10
file2 5 100 5 5 5 5 5 5
file3 5 5 5 5 5 5 100 5
file4 5 5 5 5 5 5 100 5
file5 5 100 5 5 5 5 5 5
file6 5 100 5 5 5 5 5 5
file7 60 70 50 20 20 10 10 10

In practice, starting from a point at which approximately half of the design VHDL had been written and at which there had been just a few test cases, the team ran coverage analysis biweekly. In recording the missing tests, it devised a simple tabular format to assist feedback of information. The table had two columns with untested functionality in the left column and tested items on the right. With subsequent regressions, the detail in the table was seen to increase. Initially, whole entities and processes were reported in the table; but as coverage improved, so did the detail, and three clear benefits of the feedback emerged.

First, they saved time developing the test bench because the code coverage analysis enabled the team to quickly identify omissions without having to fully understand the required functionality. Second, the team made use of all code coverage types--something that wasn't previously required. Doing that undoubtedly improved the quality of the tests. Third, the periodic analyses provided a useful metric toward completion and an impression of the delay that could be expected in completing the design through VHDL coding to handoff, which aided scheduling.

Test bench optimization
A full regression test suite can contain hundreds of individual test cases, so simulating all of them may require several days. While numerous solutions are available to reduce the time required--hardware accelerators, formal verification, and simulation on parallel machines, to name a few--such solutions are typically expensive and therefore not usually available to the ASIC designer. Code coverage analysis, though, may provide a solution.

The TNETE223 project revealed some interesting trends in test case development. In particular, it became apparent that test case authors tended to create new test cases when they identified small holes in coverage rather than to modify existing tests. The knowledge that the test suite contained groups of similar tests indicated that a regression might involve a large degree of redundant simulation.

Each sequence of test cases contributes incrementally to cumulative coverage. Using the TNETE223 test suite, the design team performed a test case sort, searching for the test cases that provided the most coverage. Using this ordering as the execution order in the regression run would improve the potential for finding errors earlier in the regression. Further, knowing that a certain level of coverage could be reached after a given time through the regression testing, the designers could be confident that there were no design errors, and it wouldn't be necessary to wait for regression testing to be completed before moving to handoff. This approach is a simple application of Pareto's law, which states that 80 percent of the problem can be solved using just 20 percent of the effort.

Test Techniques
Testing techniques can be roughly divided into four groups: functional, structural, error-oriented, and stress and performance analysis.

Functional testing is used to demonstrate that the device functions are operational. The goal is to exercise each aspect of the specified behavior over some subset of its input. Functional testing examines some aspect of a behavior with little regard for its internal logical structure. It helps to identify incorrect or missing functionality, interface errors, performance errors, and initialization and termination errors.

At the module level, functional testing is appropriate for testing boundary conditions and low-level functions. At the integration and system level, the types of functions tested are normally those involving some combination of lower-level functions.

To improve failure detection, functional testing must be combined with other strategies.

Structural testing develops test data based on the source code. It includes data flow anomaly detection, data flow coverage assessment, and various levels of code coverage. Logical paths through the software are tested by providing test cases that exercise specific sets of conditions. Structural testing helps to guarantee that all independent paths within a module have been exercised, that all logical decisions are exercised on their true and false sides, and that all loops execute at their boundaries and within their operational bounds.

At the system level, full structural testing may be difficult owing to the size of the system being tested. At the module level, all of the structural techniques are applicable. At the integration level, the focus of the structural techniques is on interface analysis, which may involve module interfaces as well as interfaces with other system components.

Structural testing and analysis techniques can't detect missing functions. They must be used in combination with other strategies for adequate failure detection.

The main difference between functional and structural testing is that the former uses the specification as the master data, whereas the latter is based on the source code. In functional testing, simulations are run on the input part of the test to obtain the actual results, and failures are diagnosed at the output by comparing the specification with the actual result. Structural testing is the same except that failures are diagnosed at the output by comparing the expected and actual results. The coverage values (percentages) are checked using a code coverage tool. For both types of testing, failures are isolated by searching for the cause in the source code or by reading the specification and debugging the code.

Error-oriented testing develops test data by focusing on the presence or absence of errors in the coding process. The goal is to verify that specific errors aren't present in the implementation. A lessons-learned approach that looks for errors that have been experienced in the past is one form of error-oriented testing.

Stress analysis involves analyzing the behavior of the system when its resources are saturated in order to assess whether the system will continue to satisfy its specifications. It's a measure of system robustness. Performance analysis, as the name implies, involves measuring how well the product meets its specified performance objectives.

A good verification tool produces coverage results for each individual test case, segmented by a VHDL source file. For example, a coverage number (percentage) is obtained for each VHDL file for every test case that's run. If there are 50 entities in the design, one per unique VHDL text file, there should be more than 50 test cases to make up the entire test suite. A two-dimensional matrix of verification results easily shows which test cases are most effective (see Table 1).

The algorithm for ordering the tests would then be the following:

  1. 1. Examine the matrix, thereby identifying tc2 as the most valuable test case; it completely covers more VHDL segments than any other.

  2. 2. Extract tc2 as the first test to be executed and redraw the matrix without tc2 and also without any of the files completely covered by tc2.

  3. 3. Repeat steps 1 and 2 to identify the next-most-valuable test case (tc7 in the table) and continue the iterations until the point is reached at which no more VHDL segments are completely covered by any of the remaining test cases.

  4. 4. Complete the list by taking each file in turn and choosing the test that gives the best coverage for that file.

In the simple example, the design team would have identified that running tc2, tc7, and tc3, in that order, from the full set of eight possible tests, would maximize the code coverage in the early stages of a regression.

Table 2 Coverage vs. number of tests
Coverage Number of tests
Full test suite (%) Subset of test (%) Full test suite Subset of test
72.0 69.0 32 12
76.0 74.5 47 14
90.0 89.0 53 11

Results fit Pareto theory
With some 5,000 entries in the initial matrix, the implementation had to be automated using a Perl script. The results (see Table 2) were obtained at three checkpoints during the design cycle, and they demonstrate that a high degree of coverage could always be obtained running just a small subset of tests from the test suite.

A side effect of the method is the potential to identify wholly redundant test cases. Two tests having identical characteristics in the matrix must be the same. The TNETE223 test suite was found to contain one such test case, which had been created by copying an existing test case but never modified to verify a different function. The design team was able to remove that test from the regression suite.

Test Approaches
Testing occurs at different levels of subcomponent integration, each with its own specific goals. At each of the levels, one or more different techniques will be applied as necessary to reach the overall testing goals.

Module testing is the lowest level of testing, involving individual modules or design units. The goal of module testing is to ensure that the component being tested conforms to its specifications and is ready to be integrated with other subcomponents of the product.

Integration testing is the systematic combination and execution of product components--for example, combining a state machine controller with the datapath it controls. Multiple levels of integration testing are possible with a combination of components at several different integration levels. The goal is to ensure that the interfaces between the components are correct and the product components work together to execute the functionality correctly.

System testing is the process of testing the integrated system to verify that it meets its specified requirements. Practical priorities must be established to complete this task effectively. One general priority is that system testing must concentrate on ensuring the use and interaction of functions rather than on testing the details of their implementations. Another priority is that testing typical situations is more important than testing special cases, suggesting that test cases can be constructed corresponding to high-probability user scenarios. Concentrating on those scenarios facilitates the early detection of critical problems that would greatly disrupt the process.

System tests should be developed and performed by a group independent of the code developers, and system test plans must be developed and inspected with the same rigor as the other elements of the project. Finally, system tests must be repeatable.

Regression testing can be defined as the process of executing previously defined test cases on a modified code to ensure that changes made to the code haven't adversely affected previously existing functions. The error-prone nature of code modification demands that regression testing be performed. An important regression testing strategy is to place a higher priority on testing older capabilities than on testing the new capabilities provided by the modification. Doing so ensures that the capabilities that end users depend on are still intact. Such verification is especially important when you consider that some studies show that half of all the failures detected by end users after a modification were failures of old capabilities.

A change in approach
Up-front code coverage analysis saves both time and effort. The design engineers from the TNETE223 were sufficiently pleased with the change in approach. The aggressive schedule was, for the most part, achieved, and the engineers have not had any hesitation in making up-front code coverage analysis their standard approach.

As mentioned earlier, the design team has plans to examine further applications for code coverage data. Among the possibilities they're considering are identifying test cases that exercise known critical timing paths, identifying the test cases that will produce the best toggle data for power analysis, and developing a starting set of vectors for reuse in fault-grading a design. The usefulness of code coverage analysis is just beginning to be appreciated.


Stuart Riches is an ASIC design engineer at VLSI Technology, Inc. in Milton Keynes, U.K. He was a design engineer at Texas Instruments, Inc. in Northhampton, U.K. when this article was written. Initially, he worked for four years as a software engineer developing EDA tools at TI in Bedford, U.K. In 1990, he changed jobs and worked on the 'C80 DSP team until moving into mixed-signal ASIC design in 1993, contributing to a number of local-area network devices.

Martin Abrahams is an applications support manager at TransEDA, Ltd. in Eastleigh, Hampshire, U.K. He is responsible for customer support operations worldwide. He has also worked at TransEDA for six years and assisted with the development of both VHDLcover and Coverplus.

To voice an opinion on this or any Integrated System Design article, please email your message to miker@isdmag.com.


integrated system design  July 1998



[ Articles from Integrated System Design Magazine ] [ ICs and uPs ]
[ Custom ICs and Programmable Logic ] [ Vendor Guide ]
[ Design and Development Tools ] [ Home ]



For more information about isdmag.com email webmaster@isdmag.com
For advertising information email amstjohn@mfi.com
Comments on our editorial are welcome.
Copyright © 2000 Integrated System Design

  Free Subscription to EE Times
First Name Last Name
Company Name Title
Email address
  Click here for your Free Subscription to EETimes Europe
 
CAREER CENTER
Looking for a new job?
SEARCH JOBS
SPONSOR

RECENT JOB POSTINGS
CAREER NEWS
SRC Expands R&D Centers
The Semiconductor Research Corp has added a new center to its university R&D efforts.

For more great jobs, career related news, features and services, please visit EETimes' Career Center.


All White Papers »   

 
Education and
Learning


Learn Now:












Home | About | Editorial Calendar | Feedback | Subscriptions | Newsletter | Media Kit | Contact | Reprints|  RSS|   Digital|  Mobile
Network Websites
International
Network Features




All materials on this site Copyright © 2009 TechInsights, a Division of United Business Media LLC All rights reserved.
Privacy Statement | Terms of Service | About