Archive for Dave Rich

24 February, 2017

My last blog post was written a few years ago before attending a conference when I was reminiscing about the 10-year history of SystemVerilog. Now I’m writing about going to another conference, DVCon, and being part of a panel reminiscing about the 15-year history of SystemVerilog and envisioning its future. My history with SystemVerilog goes back much further.

Soul of a New MachineMy first job out of college was working with a group of Data General (DG) engineers made public in the book, Soul of a New Machine, by Tracy Kidder in 1981. Part of my job was writing a program that simulated the microcode of the CPUs we designed. Back then, there were no hardware description languages and you had to hard code everything for each CPU. If you were lucky you could reuse some of the code for the user interface between projects. Later, DG came up with a somewhat more general-purpose simulation language. It was general-purpose in the sense that it could be used for a wider range of projects based on the way DG developed hardware. But getting it to work in another company’s environment would have been a challenge.  By the way, Badru Agarwala was the DG simulation developer I worked with who later founded the Verilog simulation companies Frontline and Axiom. He now manages the Calypto division at Mentor Graphics.

Many other processor companies like DEC, IBM and Intel had their own in-house simulation languages or were in the process of developing one because no commercially viable technologies existed. Eventually, Phil Moorby at Gateway Design began developing the Verilog language and simulator. One of the benefits of having an independent language, although not an official standard yet, was you could now share or bring in models from outside your company. This includes being able to hand off a Verilog netlist to another company for manufacturing. Another benefit was that companies could now focus on the design and verification of their products instead of the design and verification of tools that design and verify their products.

I evaluated Verilog in its first year of release back in 1985/1986. DG decided not to adopt Verilog at that point, but I liked it so much I left DG and joined Gateway Design as one of its first application engineers. Dropping another name, Karen Bartleson was one of my first customers as a CAD manager working at UTMC. She recently took the office of President and CEO of the IEEE.

IEEEFast forward to the next decade, when Verilog became standardized as IEEE 1364-1995. But by then it had already lost ground in the verification space. Companies went back to developing their own in-house verification solutions. Sun Microsystems developed Vera and later released it as a commercial product marketed by Systems Science. Arturo Salz was one of its developers and will be on the DVCon panel with me as well. Specman was developed for National Semiconductor and a few other clients and later marketed by Verisity. Once again, we had the problem of competing independent languages and therefore limiting the ability to share or acquire verification models. So, in 1999, a few Gateway alums and others formed a startup which I joined a year later hoping to consolidate design and verification back into one standard language. That language was SUPERLOG and became the starting point for the Accellera SystemVerilog 3.0 standard in 2002, fifteen years ago.

IEEE Std 1800-2012There are many dates you could pick for the start of SystemVerilog. You could claim it couldn’t exist until there was a simulator supporting some of the features in the standard. For me, it started when I first read an early Verilog Language Reference Manual and executed my first initial block 31 years ago. I’ve been using Verilog almost every day since. And now all of Verilog is part of SystemVerilog. I’ve been so much a part of the development of the language from its early beginnings; that’s why some of my colleagues call me “The Walking LRM”. Luckily, I don’t dream about it. I hope I never get called “The Sleeping LRM”.

So, what’s next for SystemVerilog? Are we going to repeat the cycle of fragmentation and re-consolidation? Various extensions have already begun showing up in different implementations. SystemVerilog has become so complex that no one can keep a good portion of it in their head anymore. It is very difficult to remove anything once it is in the LRM. Should we start over? We tried to do that with SUPERLOG, but no one adopted it until it was made fully backward compatible with Verilog.

The Universal Verification Methodology (UVM) was designed to cut down the complexity of learning and using SystemVerilog. There are now a growing number of sub-methodologies for using the UVM because the UVM itself has exploded in complexity  (UVM Framework and Easier UVM to name a couple). I have also taken my own approach when teaching people SystemVerilog by showing a minimal subset (See my SystemVerilog OOP for UVM Verification course).

DVConI do believe in the KISS principle of Engineering and I hope that is what prevails in the next version of SystemVerilog, whether we start over or just make refinements. I hope you will be able to join the discussion with others and me at the DVCon panel next week, or in the forums in the Verification Academy, or on Twitter.


, , , , , , , , , , , ,

19 September, 2013

It’s hard for me to believe that SystemVerilog 3.1 was released just over 10 years ago. The 3.1 version added Object-Oriented Programming features for testbench development to a language predominately used for RTL design synthesis. Making debug easier was one of the driving forces in unifying testbench and design features into a single language. The semantics for evaluating expressions and executing statements would be the same in the testbench and design. Setting breakpoints and stepping through the code would be seamless. That should have made it easier for either a verification or a design engineer to understand a complete verification environment. Or maybe it would enable either one to at least understand enough of the environment to isolate a particular problem.

Ten years later, I have yet to see that promise fulfilled. Most design engineers still debug their simulations the same way they debug in the lab: they look at waveforms. During simulation, they rarely look at the design source code, and certainly never look at the testbench code (unless it’s just basic pin wiggling like a waveform). Verification engineers are not much different. They rely on waveform debugging because that is what they were brought up on, and many do not even realize source-level debugging is available to them. However the test/testbench is more like a piece of software than a hardware description, and there are many things about a modern testbench that is difficult to display in a waveform (e.g. call stacks, local variables, and random constraints). And methodologies like the UVM add many layers of source-level complexity that most users do not have the time to wade through.

Next week I will be presenting as part of an Industry Special Session during the Forum on specification & Design Languages (FDL September 24-26,2013) that will discuss these issues and try to get more involvement from the academic and user communities to help resolve them. Was combining constructs from many languages into one a success? Can tools provide representations of source-level constructs in an easier graphical form? We hopefully will not need another decade.

, , , ,

16 July, 2013

It is often said that the English language is one of the most difficult languages to learn: inconsistent spelling rules; the same words are used with different meanings in different contexts. “Why does a farmer produce produce?

Working on the SystemVerilog IEEE 1800 standard, I understand that even more clearly now. The word class is used many times in different contexts to mean slightly different things that the reader is expected to understand. With brevity, but little more attention to clarity, I will explain some of these different contexts.

Class Types

When you declare a class, you are declaring set of members and a set of methods that operate on those members.

class MyClass; bit [7:0] member1; 
 bit member2;
 function void method; 
   $display("members are %h %b", member1, member2); 

Consider this a user defined type, like a typedef. We are declaring the form and behavior of a type, but nothing is allocated to store the values of this type.

Class Objects

A class object is a particular instance of a class type. Each instance is an allocation of the members defined by the class type. The only way to create an object is to call the class constructor using the built-in new() method of a class. We classify class objects as dynamic objects because executing a procedural statement is the only way to create them.

Class Handles

Each time you call the new() method, it constructs a new class object and the method returns a class handle to the class object. A handle is an indirect reference to a class object, like a pointer to an address in memory. Unlike pointers in other languages such as C/C++, you are very limited in what you can do with a handle in SystemVerilog.

Class Variables

A class variable is where you store the class handle that references a particular class object of a particular class type. Declaring a class variable does not create a class object, only the space to hold the class handles. This contrasts with other data types where the declaration of a variable creates an object of that type and gives you a symbolic name to reference those objects. For example:

typesef struct {bit [7:0] member1; bit member2;} MyStruct; 
MyStruct StructVar1, StrucVar2

This creates and allocates the space for two MyStruct type objects and you can use StructVar1.member1 to access one of its members. On the other hand:

MyClass ClassVar1, ClassVar2;

This creates and allocates the space for two MyClass variables, but only allocates the space to hold handles to MyClass objects, not the objects themselves. If you tried to access ClassVar1.member1 now, you would get a null handle reference error because the initial value of a class variable is the special value null. One of the nice things about handles instead of pointers is that they remove the possibility of corrupt object references that access uninitialized or de-allocated memory.

Class Types, Objects, Handles, and Variables

Once you have a class variable, you can call the new() method to construct a class object

ClassVar1 = new();

This calls the constructor of the MyClass type that returns a handle to a MyClass object and then stores that handle in the MyClass variable, ClassVar1. You can now access ClassVar1.member1 because ClassVar1 references an actual object. If you then do:
ClassVar2 = ClassVar1;
Both class variables reference now the same class object – but there is still only one object of MyClass. ClassVar1.member1 and ClassVar2.member1 refer to the same class member.

Class Dismissed

Just remember to add a few extra words when mentioning classes and it will make things much clearer to the reader.

There are whole other classes of class thingy’s I could have explored, but I hope this class on classes will motivate you to learn more of the subtle meanings behind the words.

, ,

3 May, 2013

A unique concept most beginners have trouble grasping about the Verilog, and now the SystemVerilog, Hardware Description Language (HDL) is the difference between wire’s (networks) and reg‘s (variables). This concept is something that every experienced RTL designer should be familiar with, but there are now many verification engineers with no prior Verilog experience trying to pick up SystemVerilog for their testbench. Verification methodology courses tend to concentrate on the Object-Oriented programming aspects of testbench design, but do not cover this topic thinking that it is for designers only. Not true. If you have to communicate with a DUT then you need to understand the difference between wire’s and reg’s (nets and variables).

Anyone tasked with having to design or verify a piece of hardware should have some basic programming skills and understand the concept of a variable. If not, you had better stop right here and brush up on some programming basics. The key concept that you need to take away from programming is that you write a value into a variable and that value is saved until the next assignment to that variable. This concept is referred to as a procedural assignment which is part of executing an ordered set of statements. An HDL may add some notion of time in between assignments and other statements. The last assignment determines the current value of the variable.

Combinatorial Logic Sequential Logic
reg a,b,c; 
always @(b or c) 
 a = b | c; 
reg a,b,c; 
always @(posedge c) 
 a = a + b; 

Initially, Verilog used the keyword reg to declare variables representing sequential hardware registers. Eventually, synthesis tools began to use reg to represent both sequential and combinational hardware as shown above and the Verilog documentation was changed to say that reg is just what is used to declare a variable. SystemVerilog renamed reg to logic to avoid confusion with a register – it is just a data type (specifically reg is a 1-bit, 4-state data type). However people get confused because of all the old material that refers to reg. Just forget about it and use logic from now on.

Another distinctive characteristic of an HDL is that it models massive amounts of parallel processes. At the lowest level of digital design, every primitive gate (AND, OR, DFF) is an independent concurrent process. Modules are containers representing processes modeled at different levels of abstraction. Groups of primitives and modules pass values to each other via networks of signals. In Verilog, a wire declaration represents a network (net) of connections with each connection either driving a value or responding to the resolved value being driven on the net. The output of each of these concurrent processes drives a net in what is called a continuous assignment because the process continually updates the value it wants to drive on the net. There are various ways to declare a continuous assignment, all of which represent permanent behaviors:

wire A, B, C; 
assign A = B| C; // continuous assignment construct. 
or(A,B,C); // gate-level instance terminal connection 
mymodule m1(A,B,C); // module instance port connection 

Although these are all different forms of continuous assignment constructs, none of them directly assign a value to the net like a procedural assignment would. All of the values being concurrently driven onto the net are passed into a built-in resolution function. The result of that resolution function is based on the strengths of each driver representing the hardware technology in use. For example, an interrupt request signal might use the wired-or (wor) kind of net to indicate that at least one device is driving a ‘1’, otherwise it will resolve to a ‘0’. Some signals will have weaker pull-up/down resistors that will be overridden by the values of a stronger driver. Most technologies do not allow driving different values on the same net and the net will resolve to an unknown ‘x’ when that happens. In this case only one driver is actively assigning a ‘0’ or ‘1’ and the other drivers are effectively turned off by driving a high-impedance or ‘z’ state. The consequence of this is that a bi-directional port must be modeled using a net in order to have multiple drivers on either side of the port.

See my recent DVCon paper for an example of modeling bidirectional signals along with other tips for connecting the Testbench to your DUT.

It turns out that the vast majority of nets in a design will only have a single driver, so no strength information or resolution function is needed. SystemVerilog added a feature that allows a single continuous assignment to drive a variable. The expression driving the continuous assignment is assigned to the variable every time the expression changes its value. As soon as you have more than one driver or need strength information, you must go back to using a net. You cannot mix procedural and continuous assignments to the same variable. The reason for that restriction is that there is no way to resolve the “last write wins” semantics of a procedural assignment with a driver that wants to continually assign the variable (i.e. when is the last write finished and the continuous assignment supposed to take over?).

In summary, you should now be using logic for 4-state variables (or bit for 2-state variables) to represent all of your single drive signals. Any signal with more or the potential for more than one driver should be declared as a wire.

, , ,

25 February, 2013

Today at this week’s DVCon 2013 conference, the IEEE Standards Association (IEEE-SA) and Accellera Systems Initiative (Accellera) have jointly announced the public availability of the IEEE 1800 SystemVerilog Language Reference Manual at no charge through the IEEE Get Program.

As I posted a few weeks ago, the 1800-2012 is not a major revision of the standard, but does contain a few enhancements that will be of interest to design and verification engineers alike. However, providing the standard as freely available download is major news.

Even though the relative cost of the LRM was minor compared to the cost of most projects utilizing the standard, there seemed to be a barrier in most engineer’s minds in justifying the expense. So most just continued to use the last freely available SystemVerilog 3.1a LRM, which was 9 years old and very obsolete for such a rapidly changing technology.

Thanks Accellera!

, , , ,

7 February, 2013

The latest revision of the IEEE 1800-2012 SystemVerilog Language Reference Manual (LRM) is about to hit the press; though I doubt people will be printing the 1300+ pages on their own from the soon to be readily available online version. Here’s a little background into what’s in all those pages.

The first SystemVerilog LRM came from Accellera in 2002 as a set of extensions to the IEEE 1364-2001 LRM. This first LRM was called version 3.0 because it was considered the third generation of Verilog. Accellera released a few more versions and turned version 3.1a over to the IEEE in 2004. The IEEE released the 1800-2005 SystemVerilog LRM as a set of extensions to the 1364-2005 Verilog LRM, which became the last revision of the 1364 LRM. Four years later, the IEEE combined the SystemVerilog extensions with the Verilog LRM producing a single 1800-2009 SystemVerilog LRM.

Now, a short three years later, the SystemVerilog IEEE 1800-2012 LRM is ready having addressed 225 issues. The majority of these issues are clarifications and corrections to the existing LRM. However, a few enhancements ranging from the simple removal of the restriction on non-blocking assignments to class members to the major addition of multiple class interface inheritance made their way into the new LRM. A number of those enhancements will undoubtedly be presented at the upcoming Design & Verification Conference.

I’d like to demonstrate two enhancements that should be of value to most verification engineers. They address two of the more commonly asked SystemVerilog questions I receive: How do I generate an array of unique values? and How to I create covergroup bins to get toggle or one-hot functional coverage?

Generating unique array of random values

Many verification scenarios require creating sets of random instructions or addresses with no repeating values, usually represented as elements in a dynamic array. Earlier versions of SystemVerilog required you to use either nested foreach loops to constrain all combinations of array elements so that they would not be equal to each other. Or else repeatedly randomize one element at a time, and then constraining the next element to not be in the list of already generated values.

The new unique constraint lets you use one statement to constrain a set of variables or array elements to have unique values. When randomized, this class generates a set of ten unique values from 0 to 15.

You can also add other non-random variables to the set of unique values which has the effect of excluding the values of those variables from the set of unique values. When randomized, this class generates a set of ten unique values excluding the values 0, 7 and 15.

Complex coverpoint bin expressions

The previous SystemVerilog syntax for specifying functional coverage bins was very limiting. Unless you could explicitly state the individual bin values or range of bin values in your coverpoint definition, or could figure out a way to instantiate multiple copies of your covergroup passing in a different bin value as an argument, you were out of luck. This also made defining coverage crosses extremely difficult.

The new SystemVerilog bin syntax lets you specify a bin expression that is evaluated over the range of possible values of the coverpoint expression. The bin expression acts like a constraint, and the set of coverpoint values where the bin expression is true become the set of bins. The coverpoint below generates as set of bin values between 0 and 127 that are divisible by 3. The range is 0 to 127 because sbyte is a 7 bit variable.

Probably the most powerful feature is the coverpoint bin set that simply allows you to define an array of values that you want as bins. This is useful for specifying one-hot encodings, toggle coverage of a register, or any complex algorithm that can generate the set of bin values you want. The code below builds a list of onehot values in the encodings array, and then constructs the protocol_cg covergroup using the array as a set of bin values.

Available in the latest version of Questa

By the way, every feature discussed in this post is available in the latest version of Questa, 10.2.

, , ,

24 February, 2012

Advanced verification techniques including functional coverage and constrained random stimulus generation have proven themselves invaluable in the design of the smallest FPGAs to the largest SoCs today. Still many design and verification teams that need to and are willing to embrace these technologies have yet to do so. Verification environments written with basic hardware description languages like Verilog and VHDL, as well as home grown environments patched together with C, Tcl, or PERL scripts are entrenched and difficult to move away from. Adopting these new techniques requires training on several fronts. You need to learn the SystemVerilog language along with Object-Oriented programming skills. And to make your verification environments reusable and interchangeable with Verification IP (VIP) that you may want to get from outside sources, you need to learn the Universal Verification Methodology (UVM).

Or do you?

Maybe you can get started by using the minimal amount of things to get started. But how can you know what you need to know when there is so much to learn? That’s where the UVM Express comes in.

The UVM Express is a carefully planned path with a few key steps along the way to get you up and running. You learn just the things you need to be more productive at each step and advance at your own pace. There’s no need to digest everything at once to get up and running. The UVM Express path has four key steps:

Step #1 Organize your Testbench into a BFM

  • Use a SystemVerilog Interface to group your Signals
  • Write your test in terms of transactions
  • Call tasks to execute transactions

Step #2 Add Functional Coverage

  • Use Metrics to check Verification quality- How good are your tests?
  • Add coverage agents
  • Leverage pre-built VIP in passive mode

Step #3 Add Constrained Random Stimulus

  • Improve your test quality by generating stimulus efficiently
  • Leverage pre-built VIP in active mode

Step #4 Use the full power of the UVM

  • Modify your environment to improve reusability and configurability
  • Leverage all your code from the previous steps

The UVM Express adds to the many guides and examples in the UVM/OVM Online Methodology Cookbook on the Verification Academy. There is also a new UVM Express module that provides a multi-media walk through each of the steps. You can discuss this with me at next week’s DVCon 2012.

, , ,

11 November, 2011

Adopting SystemVerilog can be challenging to some, and learning the UVM at the same time might seem overwhelming. There is no getting over the fact that if you are going to develop any reasonably sized testbench in SystemVerilog, you need to learn how to declare and construct a class. You also need to learn a few Object-Oriented programming principles so you can extend a UVM class into something for your particular needs.

Once you lean those principals, adopting the UVM can significantly reduce the amount of time it takes to build your testbench because it provides the infrastructure to handle many of the common tasks used in functional verification today. Just a few examples of some of the features included in the UVM are:

By using a common set of industry standard verification methodology and practices, engineers are given the ability to develop modular, reusable verification IP developed by project teams internal or external to their company. Another benefit of the UVM is that it is extensively documented as well as having a considerable amount of tutorial and example material readily available. Mentor Graphics provides the Verification Academy Cookbook and the Cookbook Recipe of the Month Seminar Series to get you started.

One of the significant features of the UVM that differentiates it from what was lacking in the OVM is its Register Layer (it was so lacking that Mentor back-ported the UVM Register Layer to the OVM for those users not yet able to migrate to the UVM). The compelling use model for the UVM Register Layer is that it abstracts away much of the UVM that one needs to learn as a test writer. You write much of your test as you would in software:, read_data, .parent(this));

spi_rm.ctrl.write(status, write_data, .parent(this)); 

Here we are issuing read and write commands to the control register of an SPI register model. All of the underlying translations to a specific DUT interface with its specific protocol are handled by Register Layer with configuration information set up by the testbench architect.

Our October Recipe of the Month gives a brief introduction to the UVM Register Layer. Our November Recipe will provide more details on implementing them in your environment.

Dave Rich

, ,

8 March, 2011

by Rich Edelman and Dave Rich


The UVM is a derivative of OVM 2.1.1. It has similar use model, and is run in generally the same way.

One significant change is that the UVM requires a DPI compiled library in order to enable regular expression matching, backdoor access and other functionality.

When running UVM based testbenches, we recommend using the built-in, pre-compiled UVM and DPI compiled libraries. This will remove the need to install any compilers or create a “build” environment.

One other issue to mention if you are converting from OVM to UVM, and if you use stop_request() and/or global_stop_request(), then you will need to use the following plusarg, otherwise your testbench will end prematurely without awaiting your stop_request().


Simulating with UVM Out-Of-The-Box with Questa

The UVM base class libiraries can be used out of the box with Questa 10.0b or higher very easily. There is no need to compile the SystemVerilog UVM package or the C DPI source code yourself. The Questa 10.0b release and every release afterwards contains a pre-compiled DPI library, as well as a pre-compiled UVM library. The only dependency is that your host system requires glibc-2.3.4 or later installed. Questa 10.0c Windows users only, please read this important note about the location of the DPI libraries.

You can easily use these steps:

vlib work
vsim hello …

Notice that we don’t have to specify +incdir+$(UVM_HOME)/src,  $(UVM_HOME)/src/  to vlog, or add a -sv_lib command to the vsim command to load the uvm_dpi shared object.

Controling UVM Versions

Each release of Questa comes with multiple versions of the UVM pre-compiled and ready to load.  By default, a fresh install of Questa will load the latest version of UVM that is available in the release.  If an older version of UVM is needed, this version can be selected in one of two ways.

Modify the modelsim.ini File

Inside the modelsim.ini file, it contains a line which defines a library mapping for Questa.  That line is the mtiUvm line.  It looks something like this:

mtiUvm = $MODEL_TECH/../uvm-1.1b

This example is pointing to the UVM 1.1b release included inside the Questa release.  If we wanted to downgrade to UVM 1.1a, then we would simply modify the line to look like this:

mtiUvm = $MODEL_TECH/../uvm-1.1a

Command Line Switch

The Questa commands can also accept a switch on the command line to tell it which libraries to look for.  This switch overrides what is specified in the modelsim.ini file if there is a conflict.  The switch is ‘-L’.  If this switch is used, then all Questa commands with the exception of vlib will need to use the switch.

vlib work
vlog -L $QUESTA_HOME/uvm-1.1a
vsim hello -L $QUESTA_HOME/uvm-1.1a ...

If you are using some other platform, or you want to compile your own DPI library, please follow the directions below.

If you use an earlier Questa installation, like 6.6d or 10.0, then you must supply the +incdir, and you must compile the UVM.

For example, with 10.0a on linux, you can do

vlib work
vsim -c -sv_lib $UVM_HOME/lib/uvm_dpi …

if you use your own UVM download, or you use Questa 6.6d or 10.0 you need to do the following:

vlib work
vlog +incdir+$UVM_HOME/src $UVM_HOME/src/
mkdir -p $UVM_HOME/lib
g++ -m32 -fPIC -DQUESTA -g -W -shared
-o $UVM_HOME/lib/
vlog +incdir+$UVM_HOME/src
vsim -c -sv_lib $UVM_HOME/lib/uvm_dpi …

Building the UVM DPI Shared Object Yourself

If you don’t use the built-in, pre-compiled UVM, then you must provide the vlog +incdir+ and you must compile the UVM yourself, including the DPI library.

In $UVM_HOME/examples, there is a Makefile.questa which can compile and link your DPI shared object.

For Linux (linux):

cd $UVM_HOME/examples
setenv MTI_HOME /u/release/10.0a/questasim/
make -f Makefile.questa dpi_lib

> mkdir -p ../lib
> g++ -m32 -fPIC -DQUESTA -g -W -shared
>   -I/u/release/10.0a/questasim//include
>   ../src/dpi/ -o ../lib/

For Linux 64 (linux_x86_64)

cd $UVM_HOME/examples
setenv MTI_HOME /u/release/10.0a/questasim/
make LIBNAME=uvm_dpi64 BITS=64 -f Makefile.questa dpi_lib

> mkdir -p ../lib
> g++ -m64 -fPIC -DQUESTA -g -W -shared
>   -I/u/release/10.0a/questasim//include
>   ../src/dpi/ -o ../lib/

For Windows (win32):

cd $UVM_HOME/examples
setenv MTI_HOME /u/release/10.0a/questasim/
make -f Makefile.questa dpi_libWin

> mkdir -p ../lib
> c:/QuestaSim_10.0a/gcc-4.2.1-mingw32vc9/bin/g++.exe
>   -g -DQUESTA -W -shared
>   -Bsymbolic -Ic:/QuestaSim_10.0a/include
>   ../src/dpi/ -o
>   ../lib/uvm_dpi.dll
>   c:/QuestaSim_10.0a/win32/mtipli.dll -lregex

Note: For Windows, you must use the GCC provided on the Questa download page: (

Save to /tmp/
unzip /tmp/
<creates the GCC directories in the MTI_HOME>

Using the UVM DPI Shared Object

You should add the -sv_lib switch to your vsim invocation. You do not need to specify the extension, vsim will look for ‘.so’ on linux and linux_x86_64, and ‘.dll’ on Windows.


vsim -sv_lib $UVM_HOME/lib/uvm_dpi -do “run -all; quit -f”


vsim -sv_lib $UVM_HOME/lib/uvm_dpi64 -do “run -all; quit -f”


cp $UVM_HOME/lib/uvm_dpi.dll .
vsim -sv_lib uvm_dpi -do “run -all; quit -f”

Running the examples from the UVM 1.1 Release

If you want to run the examples from the UVM 1.0 Release you need to get the Open Source kit – it contains the examples.

1. Download the UVM tar.gz and unpack it.

2. set your UVM_HOME to point to the UVM installation.

  • setenv UVM_HOME /tmp/uvm-<version#>

3. Go to the example that you want to run.

  • cd $UVM_HOME/examples/simple/hello_world

4. Invoke make for your platform:

  • For Windows (win32)
cd $UVM_HOME/examples/simple/hello_world
make DPILIB_TARGET=dpi_libWin -f Makefile.questa all
# Note: for windows, you need a "development area", with make, gcc/g++, etc. Using cygwin is the easiest solution
  • For Linux (linux)
cd $UVM_HOME/examples/simple/hello_world
make -f Makefile.questa all
  • For Linux 64 (linux_x86_64)
cd $UVM_HOME/examples/simple/hello_world
make BITS=64 -f Makefile.questa all

Migration from OVM to UVM

An OVM design can be migrated to UVM using a script. Many OVM designs can work without any hand coded changes or other intervention. It is a good idea to first get your design running on the latest version of OVM 2.1.2, before starting the migration process.

These designs can be converted from OVM to UVM using the distributed conversion script:


In certain cases hand coded changes might be required.

Using the ovm2uvm script, you can run a “dry run” try and see what must be changed. There are many options to the script. Before using it, you should study it carefully, and run it in ‘dry-run’ mode until you are comfortable with it. In all cases, make a backup copy of your source code, before you use the script to replace-in-place.

By default it does not change files.

Here is a simple script which copies the ovm code, then applies
the script.

# Copy my ovm-source to a new place.
(cd ovm-source; tar cf – .) | (mkdir -p uvm-source; cd uvm-source; tar xf -)

# Do a dry-run
$UVM_HOME/bin/ -top_dir uvm-source

# Examine the *.patch file

# If satisfied with the analysis, change in place
$UVM_HOME/bin/ -top_dir uvm-source -write

If you are migrating to the UVM from OVM, you are NOT required to use this script, but you must do a conversion by some means.

Once your OVM design is converted to UVM, you are almost ready to run.

The UVM requires that you use some DPI code. Additionally, the UVM defines a different semantic for run(). If you are using an OVM design converted to UVM, and you use stop_request() or global_stop_request(), then you need to add a switch:


In order to NOT use this switch, you need to change your OVM design. You need to NOT use stop_request() or global_stop_request(). You should cause your test and testbench to be controlled by raising objections as the first thing in your run tasks, and then lowering your objections where you previously had your stop requests.

More information about migrating from OVM to UVM can be found in the Verification Academy Cookbook (registration required).

, , , ,

13 February, 2011

Somebody asked me a simple question: Why do need two different macros (`ovm_object_utils and `ovm_object_param_utils) to register classes with the factory, and why can’t it tell me when I’ve used the wrong one? The answer turns out to be quite long, and demonstrates the dangers of using certain macros without first understanding the code behind them. Some I’m posting the response here. Adam Erickson will be presenting a paper Are Macros in OVM & UVM Evil? at the upcoming DVCon11 on Wednesday, March 2nd that goes into more details about the costs and benefits of the OVM macros.

First I need to talk about parameterized classes in SystemVerilog and how they interact with static members of those kinds of classes.

When you declare a parameterized class, it is more like a template, or generic class than a real class type. Only specializations of parameterized classes are real types. Suppose I have the two class definitions in the table below:

Un-parameterized Parameterized
class A;
static string name = “packet”;
class B #(int w=1);
static string name = “packet”;

The class A definition by itself creates the static variable A::name initialized with the string “packet” without any other reference to class A. As soon as you add parameters to a class definition, like the parameter w in class B, the class becomes a generic class and the static variable name does not get created. As soon as there are specializations of the class B, each unique specialization causes the static variables inside the class to be instantiated.  The following statements create two specializations of class B and two instances of the static variable.  B#(2)::name and B#(3)::name are both set to “packet”.

typedef B#(2) B2;
B#(3) B3_1h;
B#(3) B3_2h;

The two class variable declarations (B3_1h and B3_2h) represent only one unique specialization of B because its parameters have the same value in both declarations. The variable B#(1)::name does not exist unless there is some other reference to B or B#(1) somewhere else.

What if you wanted the static string variable name to have a different value for each unique specialization of B? You could write something like

class B #(int w=1);
static string name = $sformatf(“packet%0d”,w);

Now assuming the previous typedef and variable declarations above, B#(2)::name would have the value “packet2” and B#(3)::name would have the value “packet3”. There would be no instance B#(1)::name and the string “packet1” would never have been generated.

Now let us go back to the `ovm_object_utils macro. Suppose we have the following class definition

`include “ovm_macros.svh”
import ovm_pkg::*;
class packetA extends ovm_object;


Looking at just the factory registration statement this macro inserts for us (this little one line macro expands to over 100 lines of code just to support the field automation macros), we see a typedef for a specialization of the parameterized class ovm_object_registry called type_id.

import ovm_pkg::*;
class packetA extends ovm_object;
  typedef ovm_object_registry#(packetA,”packetA”) type_id;
  static function type_id get_type();
return type_id::get();


The specialized class type_id gives us access to all the static declarations inside ovm_object_registry. The code inside that class does something similar to what class A did above, except that it builds a global list of all string names and their associated types that can be used by the factory. The OVM gives you the choice of using the string name “packet” or the static function packetA::get_type() to set overrides, depending on which factory methods you use. The problem using the string names is that there is no type checking until run-time when the override statements are executed. We prefer you use type references to perform overrides


Finally, let us take a look at a parameterized class, but assume we used the same `ovm_object_utils macro.

import ovm_pkg::*;
class packetB #(int w=1) extends ovm_object;
  typedef ovm_object_registry#(packetB#(w),”packetB#(w)”) type_id;
  static function type_id get_type();
return type_id::get();


There are two problems here. The first is that this is now a generic class. The string “packetB#(w)” will not put on the factory registration list unless there is a specialization of the class packetB somewhere. The second is that if there are more than one specializations of packetB, they all will be registered with the same string name, producing an error at run time.

The `ovm_object_param_utils macro simply leaves the second parameter to ovm_object_registry as the null string and forces you to use type references for your overrides. These type references also create the specializations needed to create the static methods inside these classes.


The references to packetB#(2) and extended_packetB#(2) are checked at compile time and cause the static methods within these references to be created.

You can use $psprintf to register a string name as long as the string is unique for each specialization of the class. This can be difficult when the parameters are types.

import ovm_pkg::*;
class packetB #(int w=1) extends ovm_object;
parameter sting name = $psprintf(“packetB%0d”,w);
  typedef ovm_object_registry#(packetB#(w),name) type_id;

OK, I’m done. If you still need more background information. I recommend another DVCon09 paper I wrote with Adam about Using Parameterized and Factories.

, ,

@dennisbrophy tweets

Follow dennisbrophy

@dave_59 tweets

Follow dave_59

@jhupcey tweets

Follow jhupcey