Sign In
Forgot Password?
Sign In | | Create Account

Verification Horizons

Don't Forget the Little Things That Can Make Verification Easier

by Stuart Sutherland, Sutherland HDL, Inc.

The little things engineers can do when coding RTL models can add up to a significant boost in verification productivity. A significant portion of SystemVerilog is synthesizable. Taken individually, these synthesizable RTL modeling constructs might seem insignificant, and, therefore, easy to overlook when developing RTL models. These “little things”, however, are like getting free assertions embedded directly in the RTL code, some of which would be quite complex to write by hand. Using these SystemVerilog constructs in RTL modeling can reduce verification and debug time. This article presents several features that SystemVerilog adds to traditional Verilog RTL modeling that can help catch subtle RTL coding errors, and make verification easier and more efficient.

There is a common misconception that Verilog is a hardware modeling language, and SystemVerilog is a verification language. This is not true! Much of SystemVerilog is synthesizable with today’s ASIC and FPGA synthesis compilers. This article focuses on a few of the SystemVerilog RTL modeling constructs that help make verification easier. Only a brief summary of these constructs is presented, with an emphasis on how these constructs benefit verification productivity. There are a number of resources for more information on these and other synthesizable SystemVerilog constructs, including the DVCon-2014 conference paper, Can My Synthesis Compiler Do That? by Sutherland and Mills

Enforced Single-Driver Funtionality

Traditional Verilog has two primary types of data, nets and variables. The types used almost exclusively for RTL modeling are the wire net type and reg variable type. Traditional Verilog has strict rules on where the wire type (or another net type), must be used, and where it may be used. This mandatory usage of a net type places a burden on verification. Net types permit multiple-driver functionality, even where multiple drivers are not intended. The verification process must detect unintentional multiple drivers.

SystemVerilog significantly reduces this risk with two additional types: logic and uwire. The full meaning of these types is beyond the scope of this paper. Their effect on verification is what is important. In most contexts, the logic type makes it a syntax error to have multiple drivers. The uwire type also enforces single drivers. No special verification is needed to ensure single-driver functionality — these data types automatically prevent potential multi-driver functional errors.

Self-Verifying RTL-Specific Procedural Blocks

In traditional Verilog, procedural always blocks are used to model combinational, latch, and sequential logic. Synthesis and simulations tools have no way to know what type of logic an engineer intended to represent with the always keyword. Instead, these tools can only interpret the code within the procedural block, and then “infer” — which is just a nice way to say “guess” — the engineer’s intention. This guessing by synthesis compilers places a burden on verification engineers to develop testbenches, stimulus, and response scoreboarding to verify that RTL and postsynthesis gate functionality correctly represent intended design functionality. This is a significant verification effort! Should RTL and/or gate-level verification fail to detect and isolate incorrect combinational or sequential behavior, faulty functionality could potentially find its way into an end product.

SystemVerilog adds three RTL-specific procedural always blocks: always_comb, always_latch, and always_ff. These RTL-specific procedural blocks document design intent for the procedure. Software tools can now automatically verify that this intent is being met. Functional bugs in the traditional Verilog model become compilation errors or warnings that pinpoint the location of bugs. These built-in assertion-like checks free the verification engineer from having to write code to verify correct combinatorial, latched, or sequential behavior.

Self-Checking Enumerate Data Types

Traditional Verilog nets and variables are loosely typed. There is little or no checking of the value being assigned to the net or variable. The DVCon-2014 conference paper Can My Synthesis Compiler Do That? by Sutherland and Mills shows an example of a finite state machine RTL model that is syntactically correct, but has six functional bugs. Verification engineers are burdened with the task of designing stimulus that will bring out the functional problems, and scoreboard checking that will detect the problems. Time must be spent debugging the cause of the problems, modifying the RTL models, and then reverifying the design to ensure all functional bugs have been corrected.

SystemVerilog adds enumerated type nets and variables that are more strongly typed. Enumerated types allow nets and variables to be defined with a specific set of legal values. Each legal value is referenced using a label. The stronger built-in checking of enumerated types provides a significant advantage over traditional Verilog. With enumerated types, all six bugs in the model described in the preceding paragraph become syntax errors. Simulators will not compile the faulty code, and synthesis compilers will not allow the faulty code to be implemented in gates, until the bugs are fixed.

Correct By Construction Array Copying and Array Assignments

Traditional Verilog supports one-dimensional and multidimensional arrays, which, in RTL models, can be used to represent look-up tables and register files. However,traditional Verilog only permits access to a single element of an array at a time. To copy data from one array to another array requires writing loops that index through each element of each array. Manipulating the data in an array can also require the use of loops. Passing an array to a function, or through module ports to another module, also requires working with one element at a time, typically using loops in generate blocks or procedural code. The extra coding required in traditional Verilog to work with arrays is both tedious and prone to subtle coding errors. Verification engineers must verify that the RTL code has implemented array handling correctly.

SystemVerilog allows entire arrays to be copied as a single assignment statement, and assigning to entire arrays with a single statement. Complete arrays can be passed to functions and through module ports. Array copying, assignments and passing have syntactic and semantic rules that help ensure array handling is correct by construction. By eliminating the complexity of array copying and assignments, SystemVerilog reduces the risks of coding errors and simplifies the task of verifying that arrays are being referenced correctly in RTL code.

Correct By Construction Copying and Assignments to Groups of Signals

Traditional Verilog represents functionality at the discrete signal level. While this accurately models how signals are represented in the silicon, it can require many lines of code, in order to work with each individual signal. In a module with dozens or hundreds of separate signals, coding mistakes can easily occur, such as a missing assignment to any one of the many signals.

SystemVerilog adds a structure construct that provides a more abstract and powerful way of working with large numbers of signals. Structures are used to bundle related signals together under a common name, and are analogous to records in VHDL.

The following example shows how the 54 signals (including the Payload array) that make up a UNI ATM cell can be bundled together as a SystemVerilog structure:

typedef struct {
logic [ 3:0] GFC; // Generic Flow Control
logic [ 7:0] VPI; // Virtual Path ID
logic [15:0] VCI; // Virtual Channel ID
logic [ 2:0] PTI; // Payload Type Indication
logic CLP; // Cell Loss Priority
logic [ 7:0] HEC; // Header Error Control
logic [ 7:0] Payload [48]; // Payload
} uni_t;

This structure definition uses the typedef keyword, another important SystemVerilog extension to traditional Verilog. By defining the UNI structure as a user-defined type, it can be used for multiple declarations in the same module, and used in multiple modules.

A powerful aspect of structures is that they can be read or written as a whole. An entire structure can be copied to another structure, and all members of a structure can be assigned values in a single statement. Entire structures can be passed through module ports or to functions. Where traditional Verilog works with separate signals, leaving the door open for a plethora of potential coding mistakes, copying, assigning, and passing structures have syntax and semantic rules that help ensure that these operations are complete and correct by construction. These rules simplify verification, and reduce the time and effort required to verify operations on large numbers of separate signals.

Elimination of Redundant Declarations

The original Verilog language does not have a shared declaration space. Each module must contain all declarations used within that module. There is a risk of differences in the declarations in different modules, which can result in subtle functional bugs. The burden is on the verification team to generate stimulus that will detect any functional bugs that result from those declaration differences.

SystemVerilog addresses this Verilog shortcoming with the addition of declaration packages. Packages provide a declaration space that can be referenced from any design module, as well as from verification code. Packages can eliminate duplicate code, the risk of mismatches in different blocks of a design, and the difficulties of having to verify declaration mismatches.

Accurate and Self-Checking Decision Statements

One of the ugliest gotchas of traditional Verilog is the subtle and undesired behavior of the wildcard casex/casez statements. Many conference papers have focused on the problems caused by these Verilog constructs. Verification engineers must be diligent in verifying that the gotchas of casex/casez statements have been avoided in the RTL models. SystemVerilog adds a case...inside decision statement that does not have the problems of casex/casez statements. The effort and time needed to verify casex/ casez statements is eliminated.

From the earliest days of RTL synthesis, synthesis compilers have used full_case and parallel_case directives (also called “pragmas”) to guide the gate-level optimization of Verilog case statements. These directives cause synthesis to perform specific optimizations in the gate-level implementation of the case decisions. A major flaw with the full_case and parallel_case synthesis directives is that the commands are hidden in comments. Simulation is not affected by the directives, and therefore RTL simulation does not verify that the optimization effects of these directives are appropriate in the design.

SystemVerilog solves this problem by bringing the functionality of full_case and parallel_case into the RTL modeling world, using the keywords unique, unique0, and priority as decision modifiers. In simulation, these decision modifiers add built-in verification checking to help detect when the full_case or parallel_case optimizations would not be desirable. For synthesis, these modifiers enable the appropriate full_case and/or parallel_case synthesis optimizations.

Correct by Construction Bus Protocols with Self-Checking

Communication between design blocks often involves a set of signals and handshaking protocols. With traditional Verilog, these signal declarations must be duplicated in each design block, and at the higher level of hierarchy that connects the blocks together. The verification of the handshaking protocols is done at the testbench level, and cannot be done until late in the design cycle, after each block has been modeled.

SystemVerilog provides interface ports as a more abstract way for communication between design blocks. An interface definition encapsulates the several bus signals under single name. Modules use a single interface port with the encapsulated set of signals, instead of needing several separate ports for the bus signals. In addition to encapsulating the signals of a bus protocol, interfaces can encapsulate built-in verification code, such as assertions, so that all communications over the bus are automatically verified. Interfaces simplify RTL modeling, and significantly reduce the time and effort of verifying communication between design blocks.

Embedded Self-Checking for Unexpected or Undesired Values or Conditions

Traditional Verilog RTL models are typically written with an assumption that the data on which the models operate is valid. State decoding assumes the state variable has legal values. Decision statements assume that the expression being tested does not X, Z or other unanticipated values. Verification engineers are expected to verify that these assumptions in the RTL models are correct. Writing the tests that detect invalid values within design blocks is nontrivial and time consuming. It can require using hierarchical paths in the verification code to examine signals internal to modules deep within the design hierarchy.

SystemVerilog adds assertions to the original Verilog language. Assertions can — and should — be written by design engineers anytime the RTL code makes an assumption regarding a logic condition or value. The following example illustrates how simple it is to add assertions in RTL code as the code is being written. This simple one line of code will trap any problems with the sel input to the module at the time and place the problem occurs, rather than hoping that verification will detect a functional problem downstream in both logic and time.

always_comb begin
assert (!$isunknown(sel)) else $error
(“%m : case sel = X”);

case (sel)
2’b00 : out = a;
2’b01 : out = b;
2’b10 : out = c;
2’b11 : out = d;
endcase end


SystemVerilog adds many RTL modeling constructs to traditional Verilog that can make verification easier and more accurate! Major simulators and most ASIC and FPGA synthesis compilers support these constructs. The “little things” design engineers do in RTL models can have a significant impact on verification productivity. The SystemVerilog RTL modeling constructs were added to traditional Verilog for good reasons — be sure to take advantage of them in your design and verification projects!

Online Chat