There are few engineering tasks as daunting as the design and verification of a large, complex semiconductor device. A single designer may be responsible for millions of gates, with a combination of reuse, adaptation, and logic coded from scratch. Most large devices are SoC designs, with deeply embedded interactions between hardware and software. Verification engineers need to understand the design, the embedded code, the testbench, the low-level production software, and perhaps even some end applications.
Behind this complexity there is a rich array of languages to capture and verify the SoC. The most commonly used are SystemVerilog for the hardware and testbench plus C/C++ for the embedded software and high-level models. There are many libraries and other building blocks to help create the design and verification environment, most notably the Universal Verification Methodology (UVM) standard. However, these libraries are themselves quite complex, with many options and variations, so it can be hard to keep all this is mind when coding and debugging.
With all this language and library complexity, SoC teams may wish for some sort of assistance when writing code. Regular text spelling and grammar checkers have become proficient at not just spotting errors, but also suggesting possible fixes. Given that natural languages are much less rigorously defined than computer programs, it seems entirely reasonable to expect similar or better automation for SystemVerilog and the other design and verification languages.
The value of an IDE
Software programmers are familiar with the concept of an integrated development environment (IDE) within which they can write and debug their code. In recent years, it has become possible to acquire an IDE that supports the full range of hardware and software creation, verification, and debug for even the largest and most complex SoC projects. The IDE can analyze the design and verification code in context, with knowledge of both the languages and libraries being used.
The IDE must support the full range of software programming languages, modeling languages, hardware description languages such as Verilog and VHDL, dedicated verification languages such as e, and both the design and verification features of SystemVerilog. The IDE can:
- Perform many types of checks on the code;
- Highlight and format the code according to user preferences;
- Compile or interpret the code to present the complete structure;
- Connect to a simulator for debugging failing verification test cases; and
- Provide an intuitive graphical user interface (GUI).
This set of features can have a large impact on engineering efficiency, reducing common tasks from minutes or hours down to seconds. Using the IDE can shave weeks or months off a chip schedule, especially since verification and debug consume the most resources on most development projects. The IDE’s value is even greater when it not only detects errors in code and provides an auto-complete feature as the engineers type, but also offers proposals for the resolution of coding errors and inconsistencies within the code structure.
The IDE as an auto-corrector
It should not be too surprising that the IDE can suggest fixes and provide auto-correct-as-you-type capability. In addition to its compiler, the IDE has powerful analysis engines constantly running behind the scenes. It re-reads the source code whenever engineers make changes and updates its internal database of the complete design and verification environment. This database must support input in SystemVerilog, Verilog, VHDL, e, and C/C++, connecting all design and verification elements into a single structure and enabling an analysis that spans all these languages.
Drawing on this database and its knowledge of libraries and building blocks, the IDE has considerable insight into the intents of the designers and of the verification team. Much as a a grammar checker uses its knowledge of natural language conventions to suggest changes, the IDE leverages its internal knowledge to propose changes that resolve issues it detects. Of course, no tool can know exactly what the engineers intend, so proposals must be accepted before any changes are made to the code.
As shown in Figure 1, the IDE’s proposals start with a familiar spelling check, including an option to accept or ignore any proposed fix. If accepted, the change is made automatically to the code. Proposed changes to spelling are offered only for comments and text strings because different syntactical rules apply to the rest of the code. This first screenshot and the others that follow show examples from the Design and Verification Tools (DVT) Eclipse IDE from AMIQ EDA.
The scope of detected issues and proposed solutions goes far beyond the simple spell checks provided by a word processing tool. Because the IDE compiles the complete design and verification environment, it has the full scope of the code and can identify a wide range of inconsistencies. For example, the IDE can detect typographical errors in identifiers. In Figure 2, the user has entered an incorrect reference to a UVM component, and the IDE is proposing some actual names that might match the user’s intention. The first entry in the proposal list has been accepted, and the reference has then been automatically updated in the code.
If the user types in a reference to a variable that has not been declared, the IDE not only detects this but proposes a fix. As shown in Figure 3, if the proposal is accepted then the declaration is automatically inserted at the appropriate place in the code.
In another auto-correct-as-you-type example, Figure 4 shows a class definition in which the user has called a method that has not yet been declared. The IDE proposes to add an implementation, but as it has no way of knowing what the function is supposed to do, it inserts only a stub into the code. The stub includes a special ‘TODO’ pragma to remind the engineers to complete the implementation, and adds this completion as an entry in a project task list.
Although not shown in Figure 4, in a similar way the IDE can also detect a missing external task or function implementation and insert a stub outside the class scope.
Sometimes a module being referenced exists, but a specific port does not. Figure 5 shows an example of instantiating a module that is defined, although one of the ports in the instance is not in the definition. The IDE offers the options of waiving the error, automatically updating the instance to drop the offending port and match the definition, or auto-updating the definition to add the missing port. The ‘add’ option is the one shown being chosen in the screenshot.
The IDE can also detect missing module parameters and add them to the definition. These types of omission happen frequently during the early phases of coding, as modules and classes are being defined and used, perhaps by different engineers. The IDE’s checks and proposals are even more valuable later in the project. When a definition or instantiation is updated unilaterally, compilation errors will occur. The engineers are saved the trouble of sorting this out; the IDE detects an inconsistency as soon as it is typed and proposes possible resolutions.
There is a particularly insidious form of omission common when coding SystemVerilog (or Verilog): Missing an item in a sensitivity list. The code inside such a list is only evaluated if at least one of the items in the list changes its value. This is risky as omitting a signal may lead to latch insertion during synthesis, which is usually undesirable. Figure 6 shows an example in which only one variable (‘x’) is listed, although the variable ‘y’ is also used in the code covered by the sensitivity list.
In this case, if the value of ‘y’ were to change while ‘x’ did not, the two updates would be missed, and ‘x’ and ‘z’ would retain their old values. This sort of coding error can be hard to trigger and debug in simulation, requiring much back-tracing to find the source of the incorrect data. The IDE provides a far more efficient solution by finding and reporting the missing variable, with a proposal to add it to the sensitivity list. In Figure 6, the proposal has been accepted and ‘y’ has been automatically added to the list.
Much like module definitions and instantiations, sensitivity lists and the code within them can become inconsistent when unilateral changes are made. Sometimes the engineers might delete a variable but forget to remove it from the list. This does not cause any functional errors, but the code looks confusing and simulation may be less efficient because of unnecessary evaluations. As shown in Figure 7, the IDE also detects spurious variables in sensitivity lists and proposes that they are automatically removed.
In a related vein, the IDE can detect and report signals that are declared but never actually used in the code. Figure 8 shows one such signal; the IDE offers the choice to waive the warning, remove the signal, or rename the signal. Here, the ‘remove’ option was chosen, so the signal declaration was automatically deleted. The figure also shows another useful check by the IDE: Detecting when a signal has been assigned a value, but that value is never used. This could be an error, or simply the result of coding still in progress.
Chip design and verification is a large task. It is complicated by huge amounts of code with many similar identifiers. Typographical errors, missing declarations, and inconsistent references cause verification failures and may lead to hours of tedious debug. The auto-correct-as-you-type capability of an IDE makes this task much easier by not only finding problems, but by also proposing solutions and automatic updates. The resulting efficiency and reduction in project time make the use of a sophisticated IDE a clear requirement.