0% found this document useful (0 votes)
73 views

Using Strong Types in Systemverilog Design and Verification Environments

jiji

Uploaded by

selvi0412
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
73 views

Using Strong Types in Systemverilog Design and Verification Environments

jiji

Uploaded by

selvi0412
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 10

USING STRONG TYPES IN SYSTEMVERILOG

DESIGN AND VERIFICATION ENVIRONMENTS

DAVE RICH, MENTOR GRAPHICS

W H I T E P A P E R

F U N C T I O N A L V E R I F I C A T I O N

w w w . m e n t o r . c o m
Using Strong Types in SystemVerilog Design and Verification Environments

INTRODUCTION
One of the classic debates in computer science is whether a language should have a strongly-or weakly-typed data
system. A strongly-typed language does not allow operations on data that are of incompatible types. Having
strong types, as in VHDL, helps define intent and avoid errors, but is much more verbose. A weakly-typed language,
such as Verilog, is more compact, but more difficult to debug without additional linting tools. These differences are
some of the factors that HDL users often cite as reasons to prefer one language over the other.

SystemVerilog introduces strong types on top of the existing weaker Verilog data type system that can provide an
environment similar to VHDL. SystemVerilog also introduces many new types used by the software developer that
are useful for verification. This paper introduces methodologies for taking advantage of SystemVerilog’s type
system for both the designer and verification engineer.

One of the fundamental differences between the Verilog and VHDL languages is their data type system. In Verilog,
data types are all pre-defined (built-in), and implicit type conversion rules are defined for almost all types. Verilog is
classified as a weakly-typed language. VHDL data types, on the other hand, are either predefined or user-defined, and
require explicit type conversions between most un-equivalent types. VHDL is a strongly-typed language.1 This extra
level of type definitions also gives VHDL the ability to express much higher level data types than Verilog.

As with most Hardware Description Languages, Verilog and VHDL have data types that have the ability to represent
the binary structures that make up a digital design. These data types are the bit- and vector-level logical types and
have served the design community for many years.

Both HDLs were created at a time when very few hardware engineers had a software background, although VHDL
did address the need to design at higher levels of abstraction. However, the task of verification has become more of a
software-oriented problem and neither language anticipated the additional that would place on them.2

BASIC TYPES OF PROGRAMMING


SystemVerilog adds user-defined types, object-oriented types, dynamic types, and other features from the software
development world.3 This provides the foundation for building a unified hardware design and verification language.

The table below defines the basic categories of data types used in SystemVerilog and compares some of the
terminology used in Verilog and in VHDL.

Verilog Example VHDL Example SystemVerilog


Category
Types Types Example Types
Packed array,
Discrete: integer,
Integral integer, reg packed structure,
enumeration
int, byte, enum
real, integer, reg, Scalar and access, Reals, integral,
Singular
event file handles
Unpacked array,
Multi-dimensional Composite: record,
Aggregate unpacked struct,
array array
class
Base and extended
Classes None Not Applicable
classes

SystemVerilog has a few levels of data type compatibility rules that determine where intermixing of objects of
different data types is allowed.

w w w. m e nto r. co m
2
Using Strong Types in SystemVerilog Design and Verification Environments

Operations requiring matching data types are strongly-typed. Two objects have matching data types when they
are declared with identical pre-defined types or use an alias for the same built-in type. This behavior is similar to
VHDL’s treatment of all data types. In the following example, objects A and B have matching data types:

typedef int unsigned


uint;
uint A;
int unsigned B;

At the other end of the spectrum are the equivalent and assignment compatible data types from legacy Verilog.
All integral data types are assignment compatible with each other and operands will be automatically padded or
truncated to fit as needed, much to the dismay of the VHDL user.

SystemVerilog also provides cast compatible data types that are also part of the strongly-typed system. This allows
explicit conversions between non-matching types.

PACKED AND UNPACKED DATA TYPES


Most people with a software programming background are familiar with the concept of an array. An array is a list
of values, or elements, where each element is of the same type. The individual elements are referenced with one
or more indexes.

The SystemVerilog terminology of packed and unpacked arrays is new to most design and verification engineers.
In the software world, an array provides an abstraction for iterating through or indexing into a group of similar
objects. A structure provides a way of grouping dissimilar objects. An array or structure can be initialized as a
whole, but most operations are performed on individual members. These traditional software data types are
called unpacked arrays or structures in SystemVerilog. For example:

// two unpacked arrays and structs


int A1[7:0], A2[7:0];
struct {int i; real r) S1, S2;
// individual element references
A1[0] = A1[0]+ A2[1];
S1.i = S2.i * S1.r
A1 = A2; if (S1==S2) … // aggregate
references
A1 = A1+1; S1++; // illegal operations

In the digital hardware world, everything is constructed from binary bits. All HDLs have bit-level data types that
represent those binary bits along with a multi-value system (i.e. 0, 1, X, Z). Often, those bits are grouped together
in an array to represent a larger entity, also called a bus or vector. SystemVerilog calls these vectors packed arrays or
packed structures. The key difference between packed and unpacked data types is that a packed data type allows
operations on an object as a whole as if it were a single integral value, whereas one typically needs to select a
single element from an unpacked data type before any operation other than a copy or compare. For example:

w w w. m e nto r. co m
3
Using Strong Types in SystemVerilog Design and Verification Environments

// two packed arrays and structs


int [7:0] A1, A2;
struct packed {int i; real r) S1, S2;
// individual element references
A1[0] = A1[0]+ A2[1];
S1.i = S2.i * S1.r
A1 = A2; if (S1==S2) … // aggregate
references
A1 = A1+1; S1++; // legal operations

DYNAMIC DATA TYPES


A key requirement for any software programming language is the ability to create data structures dynamically. This
could be as simple as constructing a string for a message or as complex as building a hierarchical tree structure.

The most fundamental dynamically-sized type in SystemVerilog is a queue. A queue is an unpacked array that can
be used to create variable sized payloads, FIFOs, and many other kinds of lists. The power of the queue is that the size
of the array can grow and shrink as elements are added to or removed from the array. Queues are declared as
unpacked arrays, using the ‘$’ character in lieu of array indices.

int q [$]; // default size is


unbounded
q[0] = 1; // insert first element
q = {q, 3}; // add element
$display(q[$]); // display last element
q = q[1:$]; // delete first element
q = q[0:$-1]; // delete last element

Other fundamental dynamically-sized types provided are the string type, the associative array, and the class object,
which we discuss in the next section. A common characteristic of all the dynamic types is that SystemVerilog
automatically manages the allocation and de-allocation of memory for all objects. This provides a level of
programmer safety similar to that of other high reliability languages like Java that limit the number of programmer-
induced errors.

WORKING WITH DIFFERENT DATA TYPES


SystemVerilog has a cast operator that provides a number of mechanisms for converting data types. In its simplest
usage, the cast provides an explicit hint to the compiler that changes the implicit type conversion rules. For
example, normally the result of (2 * 3.5) is a real value (7.0) because if one operand is real the result is real. However,
using an explicit cast, the result of (2 * int’(3.5)) is an integer value (6). A user defined type, such as an unpacked
struct, has strongly-typed matching rules. For example, the following two types do not match, even though they
have the same layout.

typedef struct { bit[15:0] value;} addr_t;


typedef struct { bit[15:0] value;} data_t;
addr_t A;
data_t D;

w w w. m e nto r. co m
4
Using Strong Types in SystemVerilog Design and Verification Environments

Consequently, the assignment A = D; is not legal. The assignment A.value = D.value; is legal because the
member data types do match.

A bit-stream cast is another mechanism for type conversion. This kind of cast converts types without a loss of information
by stripping all of the bits in an object of one data type into a one-dimensional array of bits and then putting them back
in order to a destination object of another data type. So now the following assignment can be made:

A = addr_t’(D);
D = data_t’(A);

OBJECT-ORIENTED TYPE SYSTEM


Much has been written about the utility and benefit of object-oriented programming (OOP) languages, like C++
and Java. For hardware verification, OOP has also been proven useful in various proprietary languages. Building on
this knowledge, SystemVerilog includes object- oriented programming features, the most fundamental of which is
the class object. In its simplest form, a class is like a structure, an encapsulation of data.

typedef struct {
// members
bit [7:0] address;
bit [31:0] data;
} Packet_s;

Packet_s P; //an instance of Packet_s

In SystemVerilog, classes are dynamically created, whereas structures are created when they are declared.

class Packet_c;
// properties
bit [7:0] address
bit [31:0] data;
endclass : Packet_c

Packet_c P; //a handle to Packet_c


P = new(); // Construct an object
// P now has a reference to an object
P.data = 1234;

From C++ terminology, a data variable that is part of a class definition is called a property. By embedding task and
function definitions called methods, a class combines data and functionality into a single object. This allows details
of the class implementation to be abstracted away from the class user. In this example, the writer of the task does not
know whether they are accessing a data member or a function.

w w w. m e nto r. co m
5
Using Strong Types in SystemVerilog Design and Verification Environments

class Packet_c;
bit [7:0] address;
bit [31:0] data;
function bit parity;
return ^data; endfunction
endclass : Packet_c

task command( input Packet_c P);


if (P.parity)

endtask

The real power of object oriented programming is achieved through the use of inheritance. A new class may be
defined as a derivative of a previously-defined base class, from which it inherits everything defined in the base
class. The derived class definition may then add to or take search order precedence over the data properties or
methods of the base class. The following example extends the original Packet_c class by adding a new field id, and
overrides the parity method.

class Bad_Packet_c extends Packet_c;


int id;
function bit parity;
return ~^data;
endfunction
endclass : Bad_Packet_c

Extending classes creates a hierarchy of class types with a single base class at the root and subclasses extending down
the hierarchy. By default, when creating a subclass object, all of the higher-level classes, or super classes, in the path to
the root base class are constructed at the same time.

In the diagram above, when constructing Really_Bad_Packet_c, the properties in Bad_Packet_c and Packet_c are
also constructed, but hidden from direct access in the extended class. This characteristic will become important as
we begin discussing random variables and constraints, because the constraint solver solves for all the properties in
the super classes.

w w w. m e nto r. co m
6
Using Strong Types in SystemVerilog Design and Verification Environments

class Really_Bad_Packet_c extends Bad_Packet_c;


bit [33:0] data;
function bit parity;
return ~^super.data;
endfunction
endclass : Bad_Packet_c

The reference to super.data refers to the property data in Packet_c. The super prefix starts the search for an object
one level higher in a class hierarchy.

From the user perspective, it is important to realize that details of the class implementation are hidden from the
caller. If a method (i.e. function) of a class is called, the code looks exactly like a “regular” hierarchical function call.
The fact that it’s really an object method doesn’t affect the way it is used. Thus, even in an object-oriented
environment, the code looks relatively straightforward.

DATA TYPES AND THEIR USE IN TESTBENCH DEVELOPMENT


The cardinal rule when developing verification testbenches is to remember that writing software. Even though the
testbench connects to a hardware model, it should be thought of as a software model of the environment in
which the hardware will operate, regardless of the language used to write the code. As such, the general view of a
testbench is similar to a software program, in which code is executed sequentially. Other than the lowest level that
connects to the hardware, testbenches should be modelled at the transaction level as much as possible, without
worrying about clocks and other messy hardware-specific features.

There are several ways to think of transaction-level code, depending on user background, language of choice, and
other factors. Whether relying on object-oriented programming techniques, or even just basic procedural code, a
transaction is most easily thought of as simply a function call. Both SystemVerilog and VHDL provide this
functionality; it is simply up to the testbench writer to organize the code according to their transaction-level view.

A properly-architected transaction level testbench promotes the two key concepts of modularity and reusability. As
software engineers have known for years, a large monolithic block of code is difficult to maintain, and nearly
impossible to reuse. The same holds true when developing verification testbenches, which as mentioned above,
are really software programs.

If the testbench is written in terms of function calls, then it becomes easier to modify or extend the functionality
simply by modifying the behavior of the function, without having to change the underlying infrastructure code
that calls the function. It turns out that object-oriented programming makes such modifications much easier, but
the theory holds even for non-OOP languages, as long as the user organizes the code in this way.

A good way of organizing the code to achieve this modularity is by partitioning the testbench into verification
components, each of which is responsible for a relatively small and self-contained portion of the testbench
behavior. SystemVerilog provides additional features to support many types of verification components.

TRANSACTION LEVEL MODELING (TLM)


A transaction is an agreement of how to move information from one place to another. The first part of that
agreement is what that information is and how it is represented. The information could be an entire frame of video
or a single event. Most software and hardware engineers understand this part as some data type or collection of
data types, but some people incorrectly think that is all there is to a transaction. The hardest concept for most

w w w. m e nto r. co m
7
Using Strong Types in SystemVerilog Design and Verification Environments

people to understand is that the other part of the agreement is the mechanism that moves the information from
one place to another; this also where the hardware and software worlds diverge.

In a hardware world, the agreement involves some sort of synchronous or asynchronous handshaking protocol, or
time division multiplexing to start and stop a transaction. In the software world, the agreement is an API of function
calls, and more specifically in TLM, put or get function calls. In fact, the agreement in the TLM standard is that a put
or get function is essentially the only mechanism to move information from one place to another. The only way to
introduce timing is by choosing blocking or non-blocking function calls and by using drivers that interface to the
hardware or pin-level timing.

A properly designed TLM interface can also provide isolation between verification components by using what is
known as an adaptor pattern.5 An adaptor allows two classes that would normally be type incompatible to work
together. The following shows how two verification components isolate themselves from each other by using a TLM
interface class.

The initiator is a component that contains handles to a put and get base class interface that are implemented in the
target. For example, considering just the code for put interface:

class initiator; tlm_put_if put_port;



put_port.put(my_transaction);
endclass

The target implements the put by extending the put interface and constructs it so its handle can be exported to
the initiator.

class target;
tlm_put_imp extends tlm_put_if;
task put(…);
//Target’s put implementation
endtask
endclass
tlm_put_imp put_export = new(this);
...
endclass

w w w. m e nto r. co m
8
Using Strong Types in SystemVerilog Design and Verification Environments

The initiator and target are connected together in an enclosing class or module.

class my_env;
initiator i = new();
target1 t = new();
function void connect;
i.put_port = t.put_export;
endfunction
endclass

STIMULUS GENERATION
Verilog and VHDL have always had the ability to generate random values, and to make random decisions based on
those values. However, constrained random verification requires the ability to solve for many random variables with
many inter-related constraints simultaneously. This requires a more declarative approach to specifying constraints
and SystemVerilog does this as part of the declaration of classes.

SystemVerilog uses the rand modifier to distinguish the random variables from the non-random variables in a class. A
constraint can be added as a named list of expressions, declared using the constraint keyword.

class Packet_c;
rand bit [7:0] address;
rand bit [31:0] data;
constraint addr_range {
address < 132;
}
endclass : Packet_c

The constraint solver is invoked by using a built-in method of the class, randomize(), which is called after the class has
been constructed. In this example, calling P.randomize will randomize address using the constraint addr_range, and
it will randomize data with no constraints.

Packet_c P; Constraints may be added or overridden when


extending a class, just like properties and methods.
initial begin
All of the existing constraints remain in effect in the
P = new(); base class unless they are overridden. For example,
if (!P.randomize) $stop; assume the Packet _ c class in the previous example
$display(P.address); is extended:
end

class Word_Packet_c extends Packet_c;


constraint word_align { When randomizing an instance of the
address[1:0] == ‘0; Word _ Packet _ c class, both the
} addr _ range and word _ align
constraints apply.
endclass : Word_Packet_c

w w w. m e nto r. co m
9
Using Strong Types in SystemVerilog Design and Verification Environments

SUMMARY
When it comes to writing verification code, user-defined and other higher-level data types are a necessity. VHDL
users have been able to use the strongly-typed aspects of the language to create and use such data types
effectively, allowing them to write much more complex verification code than traditional Verilog users. With an
emphasis on verification, SystemVerilog provides the ability to use these higher-level data types, as well as take
advantage of object-oriented programming and other software techniques that are more advanced than what is
available in VHDL or Verilog.

Properly architecting a testbench in terms of transaction-level function calls improves the modularity and
reusability of the code, regardless of the language. VHDL users should find SystemVerilog to be a straightforward
language for writing verification code not all that different from the kind of code they are writing today. Since
SystemVerilog can easily connect to VHDL hardware models, there really is nothing to keep VHDL designers from
using SystemVerilog as their verification language.

When considering the built-in constraint, randomization and functional coverage features that SystemVerilog also
provides, VHDL users may find themselves pleasantly surprised at their ability to write even better verification code,
without having to compromise any of the strongly-typed aspects of the VHDL language. Also, since the verification
code is essentially software, the hardware-specific differences between VHDL and Verilog tend not to impact the
testbench at all, making it even easier for VHDL users to adopt SystemVerilog.

REFERENCES
[1] DeGroat, J.E., “Transparent logic modeling in VHDL,” Design & Test of Computers, IEEE, vol. 7, no. 3, pp. 42-48,
Jun 1990
[2] Rich, D.I., “The evolution of SystemVerilog,” Design & Test of Computers, IEEE, vol. 20, no. 4, pp. 82-84,
Jul-Aug 2003
[3] “IEEE Standard for SystemVerilog”, IEEE Std 1800-2005, Clause 1.2, Nov 2005
[4] O’Connell, M. “Java: The inside story.” http://www.sun.com:80/sunworldonline/swol-07-1995/swol-07-java.html,
Jul 1995
[5] Gamma, E., et. al “Design Patterns: Elements of Reusable Object-Oriented Software”, Addison-Wesley, 1994

For the latest product information, call us or visit: w w w . m e n t o r . c o m


©2018 Mentor Graphics Corporation, all rights reserved. This document contains information that is proprietary to Mentor Graphics Corporation and may
be duplicated in whole or in part by the original recipient for internal business purposes only, provided that this entire notice appears in all copies.
In accepting this document, the recipient agrees to make every reasonable effort to prevent unauthorized use of this information. All trademarks
mentioned in this document are the trademarks of their respective owners.

MGC 12-18 TECH7520-w

You might also like