Dave RichDave Rich is Verification Technologist at Mentor Graphics and is one of the authors of Mentor’s Advanced Verification Methodology cookbook. He began his career as a design and verification engineer in 1981 at Data General. In 1987, he joined Gateway Design Automation as one of the first application engineers to support Verilog-XL. At Gateway, he helped design many of the early features of the Verilog Hardware Description Language (HDL), and after Cadence acquired Gateway, helped prepare the Language Reference Manual (LRM) that would eventually be donated to the newly formed Open Verilog International. In 1995, he joined another Verilog simulation company, Frontline Design Automation as an AE manager and later as a Product Manager after it was acquired by Avant!. In 1998, he joined Ambit Design and worked as a consulting engineer for both synthesis and simulation products after it was acquired by Cadence. In 2000, he joined Co-Design Automation as Director of Application Engineering where the Superlog HDL was being developed that eventually became the basis of the Accellera SystemVerilog 3.0 standard. Co-Design Automation was acquired by Synopsys in 2002. Dave began work on numerous technical committees within Accellera and later the IEEE P1800 working group, where he continues today. « Less
Dave RichDave Rich is Verification Technologist at Mentor Graphics and is one of the authors of Mentor’s Advanced Verification Methodology cookbook. He began his career as a design and verification engineer in 1981 at Data General. In 1987, he joined Gateway Design Automation as one of the first … More »
November 15th, 2011 by Dave Rich
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:
…
spi_rm.ctrl.read(status, 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
http://go.mentor.com/getting-started-with-UVM-registers
Posted in Uncategorized | No Comments »
February 14th, 2011 by Dave Rich
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”;
endclass |
class B #(int w=1);
static string name = “packet”;
endclass |
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 = $psprintf(“packet%0d”,w);
endclass |
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;
`ovm_object_utils(packetA)
…
endclass |
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();
endfunction
…
endclass |
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
packetA::type_id::set_inst_override(extended_packetA::get_type(),”env.my_agent.*”);
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();
endfunction
…
endclass |
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.
packetB#(2)::type_id::set_inst_override(
extended_packetB#(2)::get_type(),”env.my_agent.*”);
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.
http://go.mentor.com/mcem
Tags: OVM, SystemVerilog, UVM Posted in Uncategorized | No Comments »
March 23rd, 2010 by Dave Rich
At a recent SystemVerilog requirements gathering meeting,I was quite amused to see “deprecating features” come out as one of the top 10 user requested priorities for the next revision of the IEEE 1800 standard. Even more amazing was that this request came out without listing which features were to be considered for deprecation.
 P1800 Requirements gathering meeting 2/27/2010
I’m sure most people don’t understand the meaning of the word deprecate. I thought I understood until I looked it up in a dictionary. According to Merriam-Webster:
Deprecate:
1 a archaic : to pray against (as an evil) b : to seek to avert <deprecate the wrath…of the Roman people — Tobias Smollett>
2 : to express disapproval of
3 a : play down : make little of <speaks five languages…but deprecatesthis facility — Time> b : belittle, disparage<the most reluctantly admired and least easily deprecated of…novelists — New Yorker>
In computer science standards and documentation, deprecation has come to mean to supersede or discourage use of a feature. It does not mean a feature has to be removed to be compliant with the standard. You can’t remove a feature from an existing standard; you can only remove a feature from being documented in a future standard. No vendor is going to immediately remove a feature from a tool that it has already implemented and in widespread use without ample warning and without providing a practical alternative to the user. Typically, a deprecated feature is never removed from support in a tool unless in the rare case it’s needed to allow for a future enhancement.
The current standard lists in Annex C.4 the defparam and the procedural continuous assignment statements as candidates for deprecation. Listing candidates for deprecation seems to be almost the same as actually deprecating them without removing the LRM. No tool will remove support for these statements regardless of whether they are candidates or actually removed from the LRM.
Q: So why go though the trouble of deprecating a feature in a standard?
A: Well, to discourage use of that feature.
Q: And why is that a good thing to do?
A: It makes learning the language and maintaining existing code much easier.
Take an example from the current Verilog and SystemVerilog LRMs. The logic data type was added to supersede the reg data types; they both have the same semantics. Anyone with a history of Verilog will understand the change in keywords, but someone new to SystemVerilog will be left wondering why there are two keywords for the same thing. And then there is the issue of trying to maintain the LRM so that all references to reg also include logic and the other way around. If someone misses that in one place, people will begin to think the two keywords have different behaviors.
It seems it’s always easier to add new features than to remove them. There are many places to create lists of your favorite enhancements. At the same time, people complain about the size of the Language Reference Manual – it’s over 1200 pages. Doug Smith of Doulos writes “Will this language ever stop exploding?”
So here is my list for deprecation, as well as a place for other to add their list by commenting here.
- Program blocks
- Reg data type – see above
- Wildcard associative array index types
- Un-typed mailboxes
- Dynamic array copy A = new[]B redundant with A = B
- always @(*) – superseded by always_comb
From http://go.mentor.com/the-art-of-deprecation
Tags: SystemVerilog Posted in Uncategorized | No Comments »
September 25th, 2009 by Dave Rich
Another installment of “Longwinded Answers to Frequent SystemVerilog Questions: $unit versus $root”
Believe me – I tried to make this shorter. It’s difficult for me to explain things without a historical perspective.
Verilog was invented to be an interpreted language. Verilog-XL was (and still is) an interpretive engine with single compilation unit use model. In an interpreted engine, all of the source code is parsed and loaded into memory. This means you have to specify all the source files of a design, including the source files of any required libraries, within a single command line before simulating.
VCS (Verilog Compiled Simulator) continued this single compilation use model even though it compiled the code into a machine object saved on disk. Later, it introduced an incremental compile feature that only compiled certain files that needed it, but you still had to specify all the source files on the command line. This is not the same as separate compilation available in most software programming languages where source code can be converted into machine code independently.
Tools such as NCsim and Modelsim introduced the concept of separate compilation, loosely based on the work library concept from VHDL. This is relatively easy to do in Verilog because module definitions are self contained. However, parameter overrides and hierarchical references limit the amount of machine code you can generate. The elaboration step does a lot of this work. It turns out that module instantiation syntax is easy to recognize, so the compiler does not need to see the definition of module that is being instantiating beforehand.
Superlog, the predecessor to SystemVerilog, was also invented as an interpreted language. It introduced the concept of $root as a global scope that allowed any kind of declaration (data types classes, variables) along with module definitions nested in that global scope. Any uninstantiated module becomes implicitly instantiated in $root. That’s fine for a single compilation unit, but you can no longer separately compile modules because they now may have dependencies on declarations outside their scope. For example
class C;
endclass
module top;
C c_h;
endmodule
There’s no problem if this is compiled as a single file, but if module top were to be compiled separately from the class C definition, it wouldn’t know what the identifier C was supposed to represent, and wouldn’t be able to parse the file.
So the IEEE committee borrowed the concept of packages from VHDL and standardized the concept of a compilation unit. A package allows you to compile definitions in a separate step and import those definitions into another compilation step. Packages create separate namespaces for those definitions as wall as imposing compilation order dependencies.
A compilation unit formalizes a scope that represents what is visible in a compilation step – called $unit in SystemVerilog. If you have a design that is compiled as a single compilation unit, there is really no conceptual difference between $unit and $root. However, once you have a design with multiple compilation units, then $unit represents the top level of each compilation unit, and there is nothing in $root except for the implicitly instantiated module instances. The only time you need to use $root or $unit is when a local name in the current scope hides a name in a higher level scope. For example
Compilation unit 1
function void print;
$display("comp1");
endfunction
module mod1;
mod2 m2();
function void print;
$display("mod1");
endfunction
initial $unit::print(); // prints “comp1”
//print() would print “mod1”)
endmodule
Compilation unit 2
function void print;
$display("comp2");
endfunction
module mod2;
mod3 mod1(); // same name as top-level module
function void print;
$display("mod2");
endfunction
initial $root.mod1.print(); // print “mod1”
// mod1.print() would print “mod3”
endmodule
module mod3;
function void print;
$display("mod3");
endfunction
endmodule
This example prints “comp1” and “mod1” in either order. Note that there is no way for compilation unit 1 to directly refer to anything in compilation unit 2, or the other way around.
I hope this clears up some of the confusion between $root and $unit in SystemVerilog.
Dave Rich
http://blogs.mentor.com/nosimulation/blog/2009/09/25/unit-vs-root/
Tags: SystemVerilog Posted in Uncategorized | No Comments »
September 11th, 2009 by Dave Rich
I have lots of blog entries about 95% ready to publish. This entry is from an e-mail I wrote a few months ago when somebody asked about SystemVerilog coding guidelines. I thought it would make a good article. It’s been sitting as a draft because I always have trouble finding the right title or opening words to catch people’s attention. I couldn’t come up with anything better, so here it is: SystemVerilog Coding Guidelines
My official position about this is that you pick a style and stick to it.
Which style you pick is far less important than developing the required culture that will follow it. People can spend hours arguing over the merits of camelCaps versus under_score, but once the decision is made, people on the project need to document it, adhere to it, and police it. Otherwise you’re just wasting everyone’s time.
Why are coding guidelines so important? So someone else can read your code, or maybe you can read your own code six months after you wrote it. Good comments and documentation are an import part, but you still need to be able to read the code.
This concept of reading someone else’s code without understanding the underlying conventions reminds me of the classic short article “Meihem In Ce Klasrum” by Dolton Edwards. The article was written as a satirical response to George Bernhard Shaw’s final wishes to simplify the English language. See how easy the last paragraph is to read once you understand the new writing conventions. Reading your code should be just like that (although not as cryptic).
My advice would be to pick a style from industry and adapt it to fit SystemVerilog. For example, from Google: http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml or from the Free Software Foundation: http://www.gnu.org/prep/standards/
All of these rules for naming conventions, indentation, and file organization still apply to SystemVerilog. Additional rules would be for unsupported constructs, which should be in the release notes for the tool(s) you are using. Finally, there are a few constructs to avoid, like program blocks and wildcard indexes for associative arrays, most of which might be worth hours of debate, each.
Dave Rich
http://blogs.mentor.com/nosimulation/blog/2009/09/11/sv-coding-guidelines/
Tags: SystemVerilog, Verification Posted in Uncategorized | No Comments »
July 7th, 2009 by Dave Rich
I’ve been around simulation and synthesis languages for a while; back when you needed an NDA to see the Verilog LRM, and again with SUPERLOG, the predecessor to SystemVerilog. It’s easy for those like me to get caught up in the features of the language and forget that any programming language is just a tool. With any technology, people pick the tools they think will get the job finished most effectively. Tools evolve to meet the challenges and requirements of their users. Verilog and VHDL have clearly evolved to become the prevailing languages for hardware design.
But before the language wars came the methodology wars. At the time when Verilog and VHDL were being introduced in the late 1980s, most hardware design was by schematic gale-level entry. We would come to our clients with our simulators and synthesis tools and try to change their design methodology by writing RTL. They would bring their best engineers to compete with our tools – and the engineer would always win by producing a design with better area and timing! However, once the productivity of synthesizing large designs with practical quality of results prevailed over the manual effort, the methodology shift was an easier sell.
Fast forward a decade – although designs have increased exponentially as predicted by Moore’s Law, RTL design has not changed in any significant way during that time. Why? Because it takes the same number of lines of RTL code to write an 8-bit adder as it does a 64-bit adder. OK, so that’s an over-simplification, but number of lines of RTL code written by a single design engineer has remained manageable. However, for every registered bit added to the design, the state space doubles, and the transition space for testing all permutations of the state space quadruples. Again that’s a simplification, but the correct order of magnitude.
During that period, a number of technologies have addressed the increasing complexities of verification, such as constrained random generation, coverage driven verification, and object-oriented programming. These technologies require a change in verification methodology from writing a linear set of test patterns.
Success in captivating verification engineers to these new methodologies is taking the same path of those earlier design engineers. A single verification engineer may find a single test to exercise a specific piece of functionally much quicker than it takes a constrained random test to reach that same function. But eventually, a constrained random test will exercise more functionality faster than an engineer can write individual tests. Functional Coverage fits into Constrained Random generation to help measure the quality of your tests by telling you if your constraints are working to exercise the functionality you are required to hit. It takes the randomness out of Constrained Random generation.
Since the verification environment is more software design than hardware, Object-Oriented Programming is a technology that helps you write re-usable code, which in turn keeps your verification code manageable.
SystemVerilog has become the prevailing language that incorporates all these technologies. But does that mean the need for writing directed tests goes away. No. Designers still layout transistors or gates by hand where it’s critical to their project. Verification engineers should use the technology that is best suited to verify their design.
Firmware tests will continue to be written in C/C++ and SystemVerilog’s DPI can help link C based tests to the RTL. SystemC has become the prevailing modeling language for DSP and algorithmic based design. Most simulation tools can seamlessly link those models to RTL to either drive the test or compare results.
So next time you’re thinking about which language to choose to verify your design, step back and think about the methodology first.
Dave Rich
http://blogs.mentor.com/nosimulation/
Tags: SystemVerilog, Verification Posted in Uncategorized | No Comments »
June 4th, 2009 by Dave Rich
That’s a frequent SystemVerilog question I’m asked. Program blocks came directly from donation of the Vera language to SystemVerilog by Synopsys , and try to mimic the scheduling semantics that a PLI application has interacting with a Verilog simulator. So coming from a Vera background, program blocks make perfect sense and do help people transitioning from Vera to SV. But looking at SV from scratch, they are just extra language baggage.
Who would have ever thought we’d be having language wars within the same language!
As far as I can tell, a program block by itself only addresses two race conditions between the testbench and DUT, both of which are covered by using a clocking block by itself.
- Erroneous use of blocking assignments for sequential logic. You have a race within your DUT regardless of the race between your testbench and DUT.
- Erroneous use of non-blocking assignments in combinational gated clock logic. You may have a race within your DUT regardless of the race between your testbench and DUT.
As a user, if you don’t understand why these create races within your DUT, you’re going to have the same races within your testbench, and there’s nothing a program block does that prevent races within your testbench. There lays the false sense of security of having a race-free testbench.
Using a clocking block by itself takes care of the same testbench to DUT races that a program block addresses, plus it takes care of the races caused by non-zero delay skews introduced by gate-level propagation. It does this by the use of the input skews for sampling and output skews for driving.
Now, in addition to the false sense of security, and the redundancy with clocking blocks, here are some additional reasons why I don’t recommend using program blocks
- If you have legacy Verilog testbench code, sometimes you want to share legacy BFM tasks by having your “class” based testbench call those BFM tasks. You’re going to run into nasty timing problems if that task was designed to be scheduled in the active region, and now is scheduled in the re-active. Sampling will be off by a clock cycle. You’ll have even nastier problems if some tasks are called from a program block, and other are still called from a module.
- One person’s Design IP is another person’s Verification IP. At the system level (ESL), there is less of a distinction between models written to represent higher level abstractions of the design, versus part of a testbench. You can’t have differences in scheduling just because one time it’s called from a program, and another time it’s called from a module. Same problem with C code called from a program block or module.
- Unless you’re an experienced Vera user, there is the unexpected surprise that your simulation exits immediately after the thread in your program block ends. Again this is an issue with mixing legacy testbenches, or mixed-language testbenches.
- Most advanced users can barely understand the scheduling semantics of SystemVerilog even without using program blocks. Why introduce unnecessary complexity. Many other enviroments, like SystemC and VHDL have been in production for years without needing the kind of scheduling semantics the program block introduces. Quick quiz: How can you get an assertion pass and fail in the same time slot?
The SystemVerilog language has had many hands involved with its development, including yours and mine. I’m not dismissing anyone efforts, but sometimes you have to take a step back and realize how bloated the language has become. Just because some feature exists in the LRM doesn’t justify that it needs to be used. Let me tell you about virtual interfaces…
Dave Rich
http://blogs.mentor.com/nosimulation/
Tags: SystemVerilog Posted in Uncategorized | 1 Comment »
|
|
|