Verification Martial Arts: A Verification Methodology Blog

Archive for the 'Phasing' Category

Implicit vs. Explicit Phasing

Posted by JL Gray on 3rd June 2010

JL Gray, Consultant, Verilab, Austin, Texas, and Author of Cool Verification

Last week I discussed the concepts of phases and threads. This week, I’ll continue that theme by focusing on the difference between implicit and explicit phasing.

Quick quiz: If you had to remember just one thing about the benefits of implicit phasing, what would that one thing be?

Posted in Phasing, Tutorial | Comments Off

Phases and Threads

Posted by JL Gray on 27th May 2010

JL Gray, Consultant, Verilab, Austin, Texas, and Author of Cool Verification

Back in the fall, I wrote about the differences between Phases and Threads, and how that relates to implicit and explicit phasing in the VMM.  In this video, I’ve taken a step back to describe phases, threads, and timelines using a real-world analogy based on the seasons of the year.

As you’re watching this video, one thing to keep in mind is that threads are dealt with by vmm_xactor-based objects, and phases are handled by vmm-timeline and vmm_group-based objects.

Posted in Phasing, Tutorial | 1 Comment »

Verification in the trenches: Implementing Complex Synchronization Between Components Using VMM1.2

Posted by Ambar Sarkar on 5th February 2010

ambar Dr. Ambar Sarkar, Chief Verification Technologist, Paradigm Works Inc.

Why is it tricky to get transactors and other verification components to work in sync with each other, especially  if they come from different projects?  It is likely that they worked well within their source projects,  but their phases (build, configure, reset, start, shutdown etc) were implemented quite differently compared to other components. These differences are usually driven by the inherent protocol requirements or team preferences. For example, consider the verification of an SOC with an AXI  host interface and a PCIe Root Complex. You will likely get your host interface transactor out of reset and execute a configuration sequence before you let your PCIe end point transactor send in requests. So you would not want to run the phases of these two transactors in lock step.

While there are countless ways to implement the phases and their sequencing, one can broadly classify a component  as being either explicitly or implicitly driven, depending on how its phases are invoked.

Implicit phasing: In my earlier post, we discussed how one can often easily coordinate the execution of various verification components. Simply put, as long as one is able to distribute the execution of the component between predetermined methods (called phases), the components can execute in lock-step with one another without requiring any additional coding by the verification engineer. This is called implicit phasing. Implicit phasing may suffice in many cases, but the challenge is to agree on the same set of phases and their sequencing. You basically will need a way to define additional  phases and potentially even rearrange their implicit calling sequence.

Explicit phasing: In contrast, explicit phasing requires the environment writer to explicitly call and synchronize the phases of the components. Typically, it takes some work to get such components to play well with one another.  This happens more often for legacy or externally developed components. In such cases, the  developers may not have known about the predetermined phases so they could not have broken down the implementation quite the way the target environment expects. Explicit phasing is often unavoidable in environments with components from multiple sources, since you may need to carefully control and coordinate the phases by hand to accommodate their differing implementation assumptions.

So the challenge we are discussing today is really about making these explicit and implicit phased components get their phases to match and cooperate during their phase transitions.

This is where vmm_timeline helps. Simply put, vmm_timeline object encapsulates your implicitly phased object and allows it to be called as an explicitly phased object.  It lets you define your own phases and the sequence in which you want to execute them. The ability to customize phases is critical, as you may need to define additional phases to fit in with the way the explicitly phased target  environment expects its phases to execute.

Here is an example that shows how an implicitly-phased component(my_implicit_comp) is being executed within an explicitly-phased my_env. Notice how the my_tl(derived from vmm_timeline) is used.

Step a. Create a vmm_timeline object and instantiate the components

// Implicitly phased comp
class my_implicit_comp extends vmm_group;
`vmm_typename(my_implicit_comp)

function new(string name = “”,
vmm_object parent = null);
super.new(“my_implicit_comp”, name, null);
super.set_parent_object(parent);
endfunctionvirtual function void build_ph();
super.build_ph();

endfunction

endclass

// Create a vmm_timeline class to wrap this implicitly phased component

class my_tl extends vmm_timeline;
`vmm_typename(my_tl)
my_implicit_comp comp1;

function new(string name = “”,
vmm_object parent = null);
super.new(“my_tl”, name, parent);
endfunction

virtual function void build_ph();
super.build_ph();

// Create an instance
this.comp1 = my_implicit_comp::create_instance(this, “comp1”);
endfunction

endclass

Step b. Instantiate in top-level vmm_env and call out the implicit methods

// Instantiate the vmm_timeline object in the top environment and call its phases explicitly.class my_env extends vmm_env;
`vmm_typename(my_env)
my_tl tl;

function new();
super.new(“env”);
endfunction

virtual function void build();
super.build();
this.tl = new(“tl”, this);
endfunction

virtual task start();
super.start();
tl.run_phase(“start”);
`vmm_note(log, “Started…”);
endtask

virtual task wait_for_end();
super.wait_for_end();
fork
// run_test phase corresponds best here
tl.run_phase(“run_test”);
begin
`vmm_note(log, “Running…”);
#100;
end
join
endtask

virtual task stop();
super.stop();

// shutdown phase corresponds best here
tl.run_phase(“shutdown”);
`vmm_note(log, “Stopped…”);
endtask

Note that the converse is also true. Explicitly phased components can be incorporated into implicitly driven environments. You need to encapsulate them in a parent class derived from the vmm_subenv class and define how each implicit phase of the parent class can be mapped to the proper explicit phase(s) of the original component. Then you can simply instantiate this parent class in the target environment. For further details, search the string “Mixed Phasing” in the VMM 1.2 User Guide.

In summary, vmm_timeline helps you manage different phasing and sequencing needs of verification components by making it easier for explicitly and implicitly phased components to interact. No wonder that under the hood of VMM1.2, vmm_timeline is used to implement advanced features such as multi-test concatenation.

This article is the 4th in the Verification in the trenches series. Hope you found this article useful. If you would like to hear about any other related topic, please comment or drop me a line at ambar.sarkar@paradigm-works.com. Also, if you are starting out fresh, please check out the free VMM1.2 environment generator.

Posted in Communication, Modeling, Phasing, Reuse | Comments Off

Using factories in an implicitly-phased environment

Posted by Kiran Maiya on 25th January 2010

You might have read the neat article posted by Wei-Hua about the class factory in this forum. You may wonder what could be the best way to code this in an implicitly-phased environment. In this article I will be discussing how transactions based on vmm_data can be made factory enabled using VMM-1.2 based factory utility in an implicitly-phased environment. We will see how transaction objects can be replaced using these factory utilities. I’ve deliberately attempted not to introduce too many concepts such as macros to implement default methods. I will post an article on replacing transactors shortly.

As a test bed let us take a simple concept of generating raw pixels using generators. These raw pixels are modeled as vmm_data objects. This pixel object contains RGB color information in the variable clr which is a rand property. A discriminant member called type_e determines the color that this pixel object can take.


/* 1 */ `include “vmm.sv”
/* 2 */ program main ;
/* 3 */
/* 4 */ //// Class: Pixel ////
/* 5 */
/* 6 */ class Pixel extends vmm_data ;
/* 7 */ `vmm_typename(Pixel)
/* 8 */ static vmm_log log = new(“Pixel”, “class”) ;
/* 9 */ typedef enum {Red, Green, Blue, ANY} clr_type_e ;
/* 10 */
/* 11 */ typedef enum {
/* 12 */         R1, R2, R3, R4, R5,
/* 13 */         G1, G2, G3, G4, G5,
/* 14 */         B1, B2, B3, B4, B5
/* 15 */         } clrcode_e ;
/* 16 */ rand clrcode_e       clr ;
/* 17 */ clr_type_e type_e = ANY ;
/* 18 */
/* 19 */ constraint con
/* 20 */ {
/* 21 */ if(type_e == Red)
/* 22 */    clr inside {R1, R2, R3} ;
/* 23 */ if(type_e == Green)
/* 24 */    clr inside {G1, G2, G3} ;
/* 25 */ if(type_e == Blue)
/* 26 */    clr inside {B1, B2, B3} ;
/* 27 */ }

In addition to the constructor, the factory override methods needs to implement two predefined methods of vmm_data class, copy() and allocate(). These methods return the right type of the object that was enabled as factory. This can also be implemented using vmm_data short-hand macros, but for the purpose of clarity the full implementation is shown.

/* 28 */

/* 29 */ /// Function: new()

/* 30 */ function new(string name = “”, vmm_object parent = null) ;

/* 31 */ super.new(log) ;

/* 32 */ endfunction: new

/* 33 */

/* 34 */ /// Function: copy()

/* 35 */ virtual function vmm_data copy(vmm_data to = null) ;

/* 36 */ Pixel me ;

/* 37 */ if(to == null)

/* 38 */ me = new (this.get_object_name(), this.get_parent_object()) ;

/* 39 */ else if(!$cast(me, to))

/* 40 */ `vmm_fatal(log, “Can’t copy to non-Pixel instance”) ;

/* 41 */

/* 42 */ /// Copy members here

/* 43 */ me.clr = this.clr ;

/* 44 */ me.type_e = this.type_e ;

/* 45 */ return me ;

/* 46 */ endfunction: copy

/* 47 */

/* 48 */ /// Function: allocate()

/* 49 */ virtual function vmm_data allocate() ;

/* 50 */ Pixel me = new () ;

/* 51 */ return me ;

/* 52 */ endfunction: allocate

It is a good practice to have the psdisplay() method implemented. This will be handy for debugging the simulation and/or for a better report log.

/* 53 */

/* 54 */ /// psdisplay()

/* 55 */ virtual function string psdisplay(string prefix = “”);

/* 56 */ $sformat(psdisplay, “%s clr = %s, type_e = %s”,

/* 57 */ prefix, clr.name(),type_e.name()) ;

/* 58 */ endfunction: psdisplay

Finally make this Pixel class to be factory enabled by using the factory utility macro as shown below.

/* 59 */

/* 60 */ `vmm_class_factory(Pixel) // Introduce factory API

/* 61 */

/* 62 */ endclass: Pixel

This base pixel class can be customized to different variants by forcing the discriminant type as shown below. Objects of these types can be later used to override the factory. These class extensions should also be enabled as factories using the factory utilities as shown below.

/* 63 */

/* 64 */ //// GreenPixel ////

/* 65 */

/* 66 */ class GreenPixel extends Pixel ;

/* 67 */ /// new()

/* 68 */ function new(string name = “”, vmm_object parent = null) ;

/* 69 */ super.new(name, parent) ;

/* 70 */ type_e = Green ;

/* 71 */ endfunction: new

/* 72 */

/* 73 */ constraint con_GreenPixel

/* 74 */ {

/* 75 */ type_e == Green ;

/* 76 */ }

/* 77 */

/* 78 */ /// copy()

/* 79 */ virtual function vmm_data copy(vmm_data to = null) ;

/* 80 */ GreenPixel me ;

/* 81 */

/* 82 */ if(to == null)

/* 83 */ me = new ;

/* 84 */ else if(!$cast(me, to))

/* 85 */ `vmm_fatal(log, “Can’t copy to non-Green Pixel instance”) ;

/* 86 */

/* 87 */ /// Copy members here

/* 88 */ return super.copy(me) ;

/* 89 */ endfunction: copy

/* 90 */

/* 91 */ /// allocate()

/* 92 */ virtual function vmm_data allocate() ;

/* 93 */ GreenPixel me = new() ;

/* 94 */ return me ;

/* 95 */ endfunction: allocate

/* 96 */

/* 97 */ `vmm_class_factory(GreenPixel)

/* 98 */

/* 99 */ endclass: GreenPixel

In real environment, pixels streams are generated using a custom pixel generators based of vmm_xactors or use one of the pre-defined generators. I will not discuss the generators in this article for the sake of simplicity. However a simplistic approach is taken here to show the generation in an implicit environment by utilizing the run_ph() of a timeline class. The driver logic is mimicked in the run_ph() method of PixelTimeline which is an extension of vmm_timeline. This method it is implicitly triggered during the run phase of the timeline. Transaction object tr which is a Pixel object, is instanced at run-time using the create_instance() method rather than the traditional constructor new(). Although the object instantiation via the factory can also be carried out in the constructor of the transactor or the build phase of the generator (timeline here), this has a disadvantage. With the create_instance() called inside pre-run phase of the generator, it allows only one opportunity for effectively replacing the factory instance before it is created. By calling the create_instance() factory method repeatedly at run-time, it allows the factory to override dynamically as required by testcases.

/* 100 */

/* 101 */ //// PixelTimeline ////

/* 102 */

/* 103 */ class PixelTimeline extends vmm_timeline ;

/* 104 */ `vmm_typename(PixelTimeline)

/* 105 */ Pixel tr ;

/* 106 */ bit done = 0 ;

/* 107 */

/* 108 */ /// Function: new()

/* 109 */

/* 110 */ function new(string name = “”, string inst = “”, vmm_object parent = null) ;

/* 111 */ super.new(get_typename(), name) ;

/* 112 */ //tr = Pixel::create_instance(this, “Fact”) ; // Not advisable

/* 113 */ endfunction : new

/* 114 */

/* 115 */ virtual function void build_ph() ;

/* 116 */ // Not recommended to call create_instace

/* 117 */ endfunction: build_ph

/* 118 */

/* 119 */ /// Task: myrun

/* 120 */

/* 121 */ task run_ph() ;

/* 122 */ tr = Pixel::create_instance(this, “Fact”) ; // This is recommended

/* 123 */ repeat(5)

/* 124 */ begin

/* 125 */ tr.randomize() ;

/* 126 */ tr.display(“::”) ;

/* 127 */ end

/* 128 */ $display(“”);

/* 129 */ endtask: run_ph

/* 130 */

/* 131 */ endclass: PixelTimeline

Having the environment ready, let us see how the objects can be replaced using the factory utility. A typical environment will be created by extending vmm_group. Environment creation is out of scope of this topic and will not be discussed here; instead a simple program block is shown creating the relevant blocks.

/* 132 */

/* 133 */ //// Program

/* 134 */ initial

/* 135 */ begin

/* 136 */ PixelTimeline tl ;

/* 137 */ Pixel tr = new ;

/* 138 */ GreenPixel gpxl ;

/* 139 */ vmm_log log = new(“A”, “B”) ;

/* 140 */

/* 141 */ tl = new (“tl”, “Main”, null) ;

Following code shows a free running generator with no customization on the pixels.

/* 142 */

/* 143 */ /// Free running simulation, any color

/* 144 */ tl.run_phase() ;

The above code will generate pixels of all colors and the output will be as follows

:: clr = R3 :: type_e = ANY

:: clr = G3 :: type_e = ANY

:: clr = B3 :: type_e = ANY

:: clr = G3 :: type_e = ANY

:: clr = B5 :: type_e = ANY

Factory replacement can be done in two ways,

  1. override by transaction copy using a reference object or
  2. override by transaction type

While overriding by transaction copy the factory method override_with_copy() should be used. This will call the copy() method to return the right type to be overridden. Here one needs to have a reference copy that will be passed as an argument while replacing factory. In the following code snippet it is shown that a local transaction copy is pixilated to Red using the type discriminant. This copy is used to override the transaction object as shown below.

/* 145 */

/* 146 */ /// Override with a transaction object copy of type Red

/* 147 */ tr.type_e = Pixel::Red ;

/* 148 */ Pixel::override_with_copy(“@%*”, tr, tr.log, `__FILE__, `__LINE__) ;

/* 149 */ tl.reset_to_phase(“start_of_sim”) ;

/* 150 */ tl.run_phase() ;

/* 151 */

This part of the code will generate the red pixels and the output will be as follows

:: clr = R1 :: type_e = Red

:: clr = R3 :: type_e = Red

:: clr = R2 :: type_e = Red

:: clr = R3 :: type_e = Red

:: clr = R1 :: type_e = Red

While overriding by transaction type the factory method override_with_new() should be used. This will call the allocate() method to return the right type. To specify the type of object to be manufactured one can use the predefined method this_type() which returns the type of the specified object. Here in the following example GreenPixel type is used to override the factory.

/* 152 */

/* 153 */ /// Override with new type-Green

/* 154 */ Pixel::override_with_new(“@%*”, GreenPixel::this_type,

/* 155 */ log, `__FILE__, `__LINE__) ; // Strongly typed

/* 156 */ tl.reset_to_phase(“configure”) ;

/* 157 */ tl.run_phase() ;

/* 158 */

/* 159 */ #100 $finish ;

/* 160 */ end

/* 161 */ endprogram: main

/* 162 */

The above code will generate the green pixels and the output will be as follows

:: clr = G2 :: type_e = Green

:: clr = G2 :: type_e = Green

:: clr = G1 :: type_e = Green

:: clr = G3 :: type_e = Green

:: clr = G3 :: type_e = Green

It is worthwhile to notice that the factory override methods are strongly typed. There isn’t any room for accidental type mismatch. Tool will automatically error out during compilation. For example, the following code is illegal and the tool throws a compilation error.

Data::override_with_new(“@%*”, GreenPixel::this_type,

log, `__FILE__, `__LINE__) ; // Strongly typed

Where Data is not an extension of type Pixel.

Hope you all will have a colorful experience with VMM-1.2 factory utility (no pun intended).

Posted in Phasing, Reuse, VMM infrastructure | Comments Off

VMM 1.2 – The Movie

Posted by John Aynsley on 14th January 2010

JohnAynsley

John Aynsley, CTO, Doulos

To celebrate the release of VMM 1.2 on VMM Central, I thought I would do something a little different and share with you a video giving a brief overview of the new features, including the implicit phasing and TLM-2 communication. So grab some popcorn, sit back, and enjoy…

Posted in Phasing, Structural Components, Transaction Level Modeling (TLM), VMM | Comments Off

Verification in the trenches: Creating your verification components using VMM1.2

Posted by Ambar Sarkar on 25th December 2009

ambar Dr. Ambar Sarkar, Chief Verification Technologist, Paradigm Works Inc.

Ever wonder why it is hard to mix and match verification components from different sources and have them play nicely with the one you created? You want all of these components to execute in sync with each other through the phases of their construction, configuration, shutdown, etc. For example, if the AXI slave transactor is executing its reset phase while the PCIe stimulus generator is sending in DMA read requests to the AXI interface, you have a problem. Often, you end up adding dedicated code or using explicit synchronization objects such as events to get the right coordination. Wouldn’t it be nice if this synchronization came automatically?

This is where the vmm_unit base class introduced in VMM1.2 comes in. The basic idea is to derive your verification component from this predefined class and you are guaranteed that the verification environment will automatically synchronize its execution with the others. While there is much offered by the vmm_unit class, the following statement summarizes its real benefit:

vmm_unit class comes with a rich set of built in synchronization points.

These synchronization points are represented as predefined tasks or functions called phases. The verification engineer provides the actual implementation of these phases. The environment makes sure that all the objects derived from the vmm_unit class get their phases called in a well defined order, so that once an object moves into a phase, it is guaranteed that all its siblings have completed the previous phase. For example, once a component enters reset, you know every other associated component is either being reset or about to enter the reset state.

Couple of things to note, however. First, you do not have to provide implementation for each and every phase. If you do not define them, the default action is that this object will wait for the others to finish this phase before moving to the next one. Second, you can override, replace, or even add your own phases to introduce a finer or different synchronization scheme altogether.

So how does the implementation end up looking like? Here is a snippet from something that I coded recently for a reusable module-level verification environment. Note that I only defined a few of the phases of my own and used the default implementation for the others.

Predefined phase Sample Code Snippet
build_ph()
// Create various functional components of this environment
pwr_hi = new(“subenv”, “PWR_HI”, this);
pwr_pi = new(“subenv”,”_PWR_PI”, this);
// Instantiate a consensus manager
cm = new(this, {this.get_object_name(), “_CM”}, pwr_port);
….
configure_ph() // If someone built me as a sub-environmnet, take appropriate action
if (is_subenv) begin
// Disable the host interface driver
connect_ph() // Connect the components as needed
pwr_hi.chk.ana_port.tlm_bind(sb.pwr_hi_sb_chk_ap);
pwr_pi.has_generator) pwr_pi.gen.ana_port.tlm_bind(sb.pwr_pi_sb_post_ap);
start_of_sim_ph() // Put a diagnostic message, otherwise leave empty
`vmm_verbose(log, “Starting simulation”);
reset_ph() // Power_cycle
pwr_port.dck.reset <= 0;
@(pwr_port.dck);
pwr_port.dck.reset <= 1;
repeat (10) @(pwr_port.dck);
pwr_port.dck.reset <= 0;
repeat (2) @(pwr_port.dck);
training_ph() // Leave as default
config_dut_ph() // Sw initialization sequence
// …
start_ph() // Leave as default
start_of_test_ph() // Leave as default
run() // All you need is to wait for the consensus manager to agree to shut down
cm.wait_for_end_t();
shutdown_ph() // Leave as default
cleanup() // Leave as default
report() // Dump the final scoreboard status
sb.report();
destruct() // Leave as default

The key is to make sure that your code is partitioned into the appropriate phases, as shown above. Also note that a bunch of the phases were left alone to their default implementation.

Okay, one minor detail. You do not directly derive from the vmm_unit base class. Instead, two classes, vmm_xactor and vmm_group have been provided. Both are derived from vmm_unit, so you have all the support for synchronization. vmm_xactor should be used as the base class for defining your individual transactors, whereas vmm_group should be used as the base class for components that put together several others into a single entity such as the top-level environment or a top-level interface vip.

Of course, the correctness of your synchronization  will still depend on what you end up implementing in the body of the pre-defined phases. The names of the predefined phases give a hint. So you are still subject to what the other components implemented in their corresponding phases. Do follow the spirit of what each phase is supposed to do. Do not connect your components in build_ph()  phase even if the test passes. Do so in connect_ph(). A small price to pay for most cases, IMHO.

Do note that there often are scenarios where some components need to be synchronized separately from others. For example, in a PCIe based SOC, what if you need the OCP interface to be up and running before you bring your PCIe interface out of reset? In this case, you definitely do not want the OCP and the PCIe VIPs to run their configure and reset phases in lock-step with each other. This is where advanced synchronization features such as vmm_timelines come to play, but that’s a topic for the next post. Stay tuned.

This article is the 3rd in the Verification in the trenches series. Hope you found this article useful. If you would like to hear about any other related topic, please comment or drop me a line at ambar.sarkar@paradigm-works.com. Also, if you are starting out fresh, please check out the free VMM1.2 environment generator.

Posted in Phasing, Structural Components | Comments Off

Just in time for the holidays: VMM 1.2!

Posted by Janick Bergeron on 15th December 2009

Janick Bergeron
Synopsys Fellow

I am pleased to see that the OpenSource version of VMM 1.2 is finally released. It is the culmination of six months of hard work by the entire VMM teams and the hundreds of customers who have provided inputs on its requirements and the dozens of teams who have contributed their feedback during the beta period.

What is new in VMM 1.2 is a “secret de Polichinelle“. Ever since the start of the beta period, several VMM users and Synopsys engineers have published tutorials, seminar presentations and blog articles on many of its powerful aspects. Nonetheless, I would like to take this opportunity to give you the highlights and pointers to where you can find more information.

A new User’s Guide

One of the most important aspect of this release—and one that has not been mentioned so far—is the completely revamped and expanded User’s Guide. We have integrated the content of the VMM for SystemVerilog book, the book’s errata, and the previous User’s Guide into a single User Guide that completely documents all of the features of the class library. Furthermore, the body of this new User’s Guide has been expanded to present the methodology in a style that will be easier to learn, with many examples. Speaking of examples, this latest distribution contains a lot more examples (in $VMM_HOME/sv/examples), illustrating the many applications domains of the VMM and all of its new features.

Implicit Hierarchical Phasing

The original VMM used explicit phasing exclusively. With 1.2, VMM now supports implicit hierarchical phasing. With implicit phasing, transactors and environments need not be responsible for the phasing of the components they instantiate: that is taken care of automatically by the new vmm_timeline object. The implicit phasing is also hierarchical, meaning that an environment may contain more than one vmm_timeline instances. Sub-timelines limit the scope and interaction of user-defined phases when block-level environments are reused in a system context. Sub-timelines may also be rolled back if their portion of verification environment needs to be stalled or restarted, for example because its corresponding functionality in the DUT has been powered down. Furthermore, VMM allows implicit and explicit phasing to be arbitrarily mixed: instead of insisting that it be in control of every aspect of a verification environment, it can import portions of an environment described using an alternative phasing methodology and have it be explicitly phased using a different mechanism by encapsulating in a vmm_subenv instance. Similarly, any VMM environment can be subjugated to another phasing methodology by allowing vmm_timeline instances to be explicitly phased.

TLM 2.0

In addition to the vmm_channel, VMM 1.2 now offers an alternative transaction-level interface mechanism inspired by OSCI’s Transaction-Level Modeling standard version 2.0. I say “inspired” because it is not a direct translation of the SystemC TLM standard, as the SystemVerilog language does not support multi-inheritance used in the SystemC implementation. The TLM2 standard is radically different from TLM1 because the latter did not live up to its promises of model interoperability and simulation performance. In addition to specifying an interface and transport mechanism, TLM2 specifies clear transaction progress and completion models through phases and the Base Protocol. VMM has always provided similarly well-defined transport mechanism (vmm_channel) and completion models (see pp176-195 of the original VMM book). With the addition of TLM2 sockets, VMM can also be used to implement high-performance virtual prototyping models in SystemVerilog. Of course, we’ve made sure that you can attach a vmm_channel to an initiator or target blocking or nonblocking socket interface for maximum flexibility.

Object Hierarchy

Whereas modules form a strict hierarchy in SystemVerilog, class instances (also known as objects) do not – at least from a language standpoint. However, it is a common mental model even though it is not enforced by the language. VMM 1.2 has the ability to define parent-child relationships between any instances of the vmm_object class. And because that class is the base class for all other VMM classes, any instance of a VMM class or user-defined extensions thereof can have a parent and any number of children. This creates a user-defined hierarchy of objects. And because each object has a name, it implicitly creates a hierarchical naming structure. Furthermore, because this hierarchical and the name of its component is entirely user-defined, VMM 1.2 provides the concept of namespaces to create alternative object hierarchies and names, making it easy to create hierarchical registries or to map an object hierarchy to another one. Objects can easily be found by name or by traversing the hierarchy from parent to child or vice-versa.

Factory API

VMM always had the concept of class factories (see p217 in the original VMM book). It used the factory pattern in all of its pre-defined generators and recommended that it be used whenever transaction objects were created or randomized (see Rules 4-115 and 5-6 in the original VMM book). It simply did not provide any pre-defined utility to ease the implementation or overriding of class factory instances. VMM 1.2 remedies this situation by introducing a class factory API that makes it easier to replace class factory instances, as well as to build class factories. Furthermore, it provides two factory override mechanism: a fast one that creates class instances with default values, and a slower one that creates exact copies. And, being strongly typed, the new factory API will detect at compile time if you are attempting to replace a factory instance with an incompatible type.

And many more!

VMM 1.2 provides many more additional features, like hierarchical options, RTL configuration support, and test concatenation.

Learning more

You can download the OpenSource distribution here. You will also find VMM 1.2 in your VCS 2009.12-1 distribution (use the +define+VMM_12 compile-time command-line option to enable it!).

Visit this blog often, as many industry leaders and Synopsys engineers will continue to provide insights on the new features included in VMM 1.2

Also, stay tuned for a series of one-day VMM 1.2 seminars and workshops that will be touring the major semiconductor centers around the globe.

Posted in Announcements, Debug, Phasing, Structural Components, Transaction Level Modeling (TLM), VMM infrastructure | 2 Comments »

Using Explicitly-Phased Components in an Implicitly-Phased Testbench

Posted by JL Gray on 11th December 2009

In my last post, I described the new VMM 1.2 implicit phasing capabilities.  I also recommended developing any new code based off of implicit phasing.  Obviously, though, companies that have been using the VMM for quite some time will have developed all of their existing testbench components using explicit phasing.  It is relatively straightforward (and in some sense almost trivial) to use an explicitly phased component in an implicitly phased testbench.

Remember that the whole point of explicit phasing is that users cycle components through the desired phases by manually calling functions and tasks within the component itself. vmm_env contains the following methods:

  • gen_cfg
  • build
  • reset
  • config_dut
  • start
  • wait_for_end
  • stop
  • cleanup
  • report

vmm_subenv contains the following relevant methods:

  • new
  • configure
  • start
  • stop
  • cleanup
  • report

In an explicitly-phased environment, subenv methods are called manually by integrators, usually from the equivalent method in vmm_env. There are two approaches for instantiating a vmm_subenv-based component in an implicitly-phased testbench. The default approach is to simply allow the implicit phasing mechanism to call these explicit phases for you. Explicitly phased components are identified by the implicit phasing mechanism, and methods are called using a standard (and not entirely unexpected) mapping:

Implicit Phase Explicit Phase Called
build_ph vmm_subenv::new[1]
configure_ph vmm_subenv::configure
start_ph vmm_subenv::start
stop_ph vmm_subenv::stop
cleanup_ph vmm_subenv::cleanup
report_ph vmm_subenv::report

[1] Users must call vmm_subenv::new manually.

Now, you might want to phase your vmm_subenv in a non-standard way. If that’s the case, the first thing you’ll need to do is disable the automatic phasing. Here’s how. First, instantiate a null phase:

vmm_null_phase_def null_ph = new();

Next, override the phases you don’t want to start automatically. For example:

my_group.override_phase(“start”, null_ph);
my_group.override_phase(“stop”, null_ph);

Finally, call the explicit phases from the parent object’s implicit phases.  A complete example is shown below.

class testbench_top extends vmm_group;
bus_master_subenv bus_master;
vmm_null_phase_def null_ph = new();

function void build_ph();
bus_master = bus_master_subenv::create_instance(this, “bus_master”);
bus_master.override_phase(“start”, null_ph);
bus_master.override_phase(“stop”, null_ph);
endfunction: build_ph

task reset_ph();
bus_master.start();
// wait 1000 clocks…
bus_master.stop();
endtask: reset_ph

endclass: testbench_top

Posted in Communication, Modeling, Phasing, Reuse, VMM | Comments Off

Verification in the trenches: Traversing object hierarchies using VMM1.2

Posted by Shankar Hemmady on 25th November 2009

AmbarSarkar Dr. Ambar Sarkar, Chief Verification Technologist, Paradigm Works Inc.

Ever get stuck trying to configure an object deep inside a verification environment? More likely than not, someone else created the environment, changed it drastically over time, and did not leave a description of the object hierarchy. It is quite time-consuming to unravel the whole hierarchical path from the root to that object. The phrase “needle in a haystack” comes to mind.

I will share some tips on how the vmm_object class, recently added to VMM1.2, can help.

As you are most likely aware, a typical verification environment today contains hundreds of classes defined by the user. Many of these are related to each other in parent/child relationships, creating several hierarchies.

As you are most likely aware, a typical verification environment today contains hundreds of classes defined by the user. Many of these are related to each other in parent/child relationships, creating several hierarchies.

Ambar_Sarkar_blog2_fig1

So how does the vmm_object class help in traversing these hierarchies? In a nutshell, it is the base class for all classes defined in the VMM library. This means that for every object derived from a class in the VMM library, you can use the same API for:

  • Finding its type
  • Finding its ancestors and children
  • Avoiding name clashes ( a new feature called namespace and we will save this topic for another post)
  • Displaying the hierarchy
  • Iterate over the objects
  • Find object by a regular expression search

The last two bullets above are what I feel help me most, because:
a. I do not have to write separate code for traversing the hierarchy of different types of objects.
b. I can locate an object easily without having to remember or figure out the exact path to it.

Here is an example. I wanted to access all the atomic generators in my environment and they were all named with the suffix GEN.

There are at least two ways to accomplish this:

1. Use the `foreach_vmm_object macro:

// Configuration phasefor test

virtual function void configure_ph();

string pattern = “@%*GEN”; // regular expression used to search for generator name

// Just iterate over all `VMM_ATOMIC_GEN objects that end with “GEN”
`foreach_vmm_object(`VMM_ATOMIC_GEN, pattern, env)
begin
// Do something with this generator
`vmm_note(log, $psprintf(“Found %s\n”, obj.get_object_name()));
end

When applicable, this approach seems like a quite concise way to get things done. Do note that the implementation of `foreach_vmm_object macro requires it to be the first statement following the declarations in a method or following a begin keyword due to the way it is implemented.

Of course, you can avoid the macro if you are so inclined as shown below. Sometimes I do this to get better visibility while debugging.

2. Use iteration class vmm_object_iter provided with this release:


vmm_object_iter iter; // iterator object
vmm_object obj;
`VMM_ATOMIC_GEN at_gen;
string pattern = “@%*GEN”; // regular expression used to search for generator name

// Just iterate over all `VMM_ATOMIC_GEN objects that end with “GEN”
iter = new(env, pattern); // Get a pointer to the iterator

obj = iter.first(); // Get the first in the list
while (obj != null) begin
// Always check type!
if (!$cast(at_gen, obj))
`vmm_error(log, $psprintf(“Unexpected type for %s. \n”, obj.get_object_name()));

// Do something with this generator
`vmm_note(log, $psprintf(“Found %s\n”, obj.get_object_name()));

obj = iter.next(); // Get the next one

end

Pretty much similar to what I expected as a use model for an iterator class.

Of course, your mileage/opinion may differ from mine. Please share how you plan on using the common vmm_object base class in your daily verification tasks.

This article is the 2nd in the Verification in the trenches series. Hope you found this article useful. If you would like to hear about any other related topic, please comment or drop me a line at ambar.sarkar@paradigm-works.com. Also, if you are starting out fresh, please check out the free VMM1.2 environment generator.

Posted in Debug, Phasing, Reuse, VMM infrastructure | Comments Off

Implicit and Explicit Phasing

Posted by JL Gray on 20th November 2009

JLGray JL Gray, Verilab, Inc.

In my last post I discussed the difference between phases and threads in the VMM. Phases and threads are conventions used to simplify testbench development. The classic VMM approach has been to use the vmm_env and vmm_subenv classes to manage phases of testbench components, leaving vmm_xactor to deal with thread management. Phases were managed “explicitly”, that is to say, users had complete control over when to step the environment and its subcomponents through individual phases via function and task calls.

The VMM 1.2 introduces the concept of “implicit” phasing. Both implicit and explicit phasing can be used to accomplish many of the same goals, albeit in different ways. In an implicitly-phased testbench, functions and tasks representing phases are called automatically at the appropriate times. A global controller (vmm_simulation) works in conjunction with specially configured schedulers (vmm_timeline) to walk all testbench components through relevant phases. vmm_simulation acts like a conductor, keeping all of the various testbench components in sync during pre-test, test, and post-test portions of a typical simulation.

A natural question to ask is, “Are there any benefits to implicit phasing over and above the explicit phasing techniques I’m using today?” When testbench components are walked through phases automatically, there are a few interesting possibilities that arise. For starters, it becomes possible to add and remove phases. Let’s imagine a simulation that has the following phases1:

  • reset_ph
  • training_ph
  • config_dut_ph
  • start_ph
  • shutdown_ph

What happens if I need to use a piece of verification IP that has implemented a training phase that is not applicable in my test environment? In an explicitly phased environment, I’d need to have control of the code that called the sub-component’s training phase in order to ensure the task in question was not called. In an implicitly-phased environment, I can simply delete the phase from being executed on that component:

my_enet_component.override_phase(“training”, vmm_null_phase_def);

In addition to adding and removing phases, you can also alias one phase to another so that the two phases overlap. For example, let’s say I need the reset phase of one portion of my design to overlap with the training phase of another. I could reconfigure the phasing of the components so they occurred in parallel instead of serially. Here are the steps:

  • Disable the reset phase for the group 1

    group1.override_phase(“reset”, vmm_null_phase_def);

  • Create a new user-defined phase for group 1 called “reset_during_training”

    class reset_during_training_phase_def extends
    vmm_fork_task_phase_def #(group1);
    `vmm_typename(reset_during_training_phase_def)

    virtual task do_task_phase(group1 obj);
    if(obj.is_unit_enabled())
    obj.reset_ph();
    endtask:do_task_phase

    endclass:reset_during_training_phase_def

  • Alias the new user-defined phase to the “training” phase

    vmm_timeline tl = vmm_simulation::get_top_timeline();
    tl.add_phase(“training”, reset_during_training_phase_def);

Another benefit of implicit phasing is that vmm_xactor, which normally manages threads, is also phased. Because of this, your transactors are now aware of the stage of the simulation we are in at any given moment. They can then change their behavior based on this knowledge. Because of this, VIP developer could configure a transactor to automatically start during the reset phase, stop during training, and continue during the start phase. Users could easily reconfigure the transactor to start and stop at other times as needed.

One thing to note is that implicitly phased components can be phased explicitly if desired by the user. This means that implicit phasing provides a superset of the explicit functionality provided by vmm_env and vmm_subenv.

The addition of implicit phasing means developers now have a choice to make when building a verification environment. Should you build it based on implicitly or explicitly-phased components? Luckily, it is possible to use implicitly-phased components in an explicitly-phased environment, and vice versa. My recommendation is for users to create all new testbench code using implicit phasing. If you are used to explicit phasing, the new development style can seem perplexing. However, as I mentioned, implicit phasing is effectively a superset of explicit phasing in its capabilities. Adopting the new methodology across your entire team will ensure the additional capabilities discussed above are available in your testbench in the future without users having to make changes down the road.

1 The listed phases are a subset of the actual pre-defined implicit phases available

Posted in Modeling, Phasing | Comments Off

Verification in the trenches: an end user’s viewpoint on VMM1.2

Posted by Shankar Hemmady on 11th November 2009

AmbarSarkar Dr. Ambar Sarkar, Chief Verification Technologist, Paradigm Works Inc.

As a soup-to-nuts functional verification consultant, I always find myself as an integral member of my client’s verification team, be it during the project planning stage or during the mad rush end of the tape-out. The roles include everything; being an individual test writer, a verification architect, or even as the verification lead for a globally dispersed large verification team. And yes, the schedules are invariably aggressive, and the budgets tight.

So how does having a sound verification methodology such as VMM help? Broadly speaking, it offers a framework within which the verification engineer can get the job done efficiently. Instead of spending time on environment and methodology issues such as wondering about how to configure all the verification components to the same setting, he or she can focus more on identifying the application specific scenarios and easily configuring the environment to generate those. The challenge, of course, is being able to understand exactly how the methodology helps within the context of a given project.

Given this challenge, I often find myself explaining to teams, in terms of their existing verification environments, how a methodology or a feature can help and the corresponding trade-offs involved. Of course, not every feature is applicable to the needs of a given team, so I pay extra attention in explaining how a feature helps, its pros-and-cons, and how to best integrate it with the current verification environment.

In this series of blog posts, I will share my opinions on how the features newly introduced with the VMM1.2 release can help or could have helped the projects I have been directly involved with so far. Of course, I will not share the gory details, but I hope to share enough so that anyone looking at these new features can evaluate them from an end-user’s perspective.

So what’s new with VMM1.2? And how does it help? Check out the table below where it identifies some of the key features, and a “one-line” description for each. This table reflects how I see these features potentially benefit the projects I have worked with; your mileage may vary.

Feature

Description

vmm_object

A base class for all object types, making it easy to traverse hierarchies and locate objects by name

vmm_unit

A base class for all structural elements such as generators, transactors etc, making it easier to synchronize their actions when executing the phases of a test

vmm_timeline

Allows users to coordinate and even define custom phases

vmm_test

Adds support for multi-test management

`vmm_unit_config_xxx

Macros to configure and build verification environment structure in a top-down manner

vmm_opts

Flexible options handling, command-line or otherwise

vmm_rtl_config

Facilitates covering cases where a number of structural configurations for the RTL exist

vmm_tlm

Making sure your components can really connect to each other and foreign objects in a “plug and play” manner

regular expressions

A very convenient way to access objects by name and set specific properties to them

`vmm_class_factory

Macros to replace and extend object functionality anywhere in the code hierarchy conveniently, and support top-down build process


Table 1. VMM 1.2 Features

While the “one-liner”s above help get an overall idea about the feature, the Verification in the trenches series of blog posts will describe each in further detail starting with their motivation, pros and cons, and how to incorporate them quickly. The hope is that you will be able to judge for yourself how some of the features described can help your current and future project needs.

Feel free to comment/share your opinions and experiences. I will be very interested in hearing from folks in the trenches. How are these features working out for you? Are you getting the benefits as you had hoped? Which one of these features you can use today? Drop me a line! Share!

Posted in Phasing, Structural Components, Transaction Level Modeling (TLM), VMM infrastructure | Comments Off

Phases vs. Threads

Posted by JL Gray on 4th November 2009

JLGray JL Gray, Consultant, Verilab, Austin, Texas, and Author of Cool Verification

Building a testbench for personal use is easy. Building a testbench that can be used by others is much more difficult. To make it easier for verification IP written by different people to interoperate, modern verification methodologies support the concept of standardized “phases” during a simulation run. Phases are a way to help verification engineers communicate in a standard language about what is meant to be taking place at any given time during a simulation.  For example, an explicitly phased VMM testbench built using vmm_env contains the following phases of execution:

· gen_cfg

· build

· reset

· config_dut

· start

· wait_for_end

· stop

· cleanup

· report

Ideally, each of these phases serves a clear purpose. If I want to reset the DUT, a good way to do it is to instrument the reset phase with the appropriate reset logic.  Similarly, the bulk of the simulation activity will likely occur during the wait_for_end phase.  The VMM now has support for implicit phasing. In an implicitly-phased system, components in the verification environment are stepped through each phase automatically by a global controller called vmm_simulation (and its associated “timelines”).  I will discuss timelines in a separate post.  In both the explicit and implicitly phased cases, the phases serve as guides through the simulation. However, most of the real work of the testbench will be accomplished by threads spawned off from these phases.

It is easy to spawn threads using a simple fork/join, but the VMM provides tools to make managing threads easier. In the VMM, the vmm_xactor base class provides support for managing threads and is at the same time phase-aware.  How does it do this?  For starters, vmm_xactor is now implicitly phased by the top level vmm_simulation controller.  However, users maintain full control over the ability to start and stop the transactor, just as they did in earlier versions of the VMM.  That means that a user could start a transactor during any VMM phase, and stop the transactor during the same or a later phase. The transactor could then query the current phase and change its behavior depending on the state of the simulation. Users can also modify their behavior via the use of callbacks.

Here is a diagram demonstrating the interaction between threads and an example subset of the new VMM implicit phases.

clip_image002

The diagram demonstrates activities that take place during specific phases of the testbench. It also shows that threads may start in one phase (such as the host generator starting in the reset phase) and stop in another (in this case, the shutdown phase).  The astute reader will note that I didn’t really need standardized phases at all to handle this. I could have done all of the activities described above in the “run” phase. In fact, that’s what many people do, even today where other phases are available.  The issue, as I stated at the beginning of the article, is that by standardizing when we do specific types of activities, our verification IP will be easier to reuse in other compatible environments.

Posted in Communication, Modeling, Phasing | 1 Comment »

Protocol Layering Using Transactors

Posted by Janick Bergeron on 9th June 2009

jb_blog Janick Bergeron
Synopsys Fellow

Bus protocols, such as AHB, are ubiquitous and often used in examples because they are simple to use: some control algorithm decides which address to read or write and what value to expect or to write. Pretty simple.

But data protocols can be made a lot more complex because they can often be layered arbitrarily. For example, an ethernet frame may contain an IP segment of an IP frame that contains a TCP packet which carries an FTP frame. Some ethernet frames in that same stream may contain HDLC-encapsulated ATM cells carrying encrypted PPP packets.

How would one generate stimulus for these protocol layers?

One way would be to generate a hierarchy of protocol descriptors representing the layering of the protocol. For example, for an ethernet frame carrying an IP frame, you could do:

class eth_frame extends vmm_data;
rand bit [47:0] da;
rand bit [47:0] sa;
rand bit [15:0] len_typ;
rand ip_frame payload;
rand bit [31:0] fcs;

endclass

class ip_frame extends vmm_data;
eth_frame transport;
rand bit [3:0] version;
rand bit [3:0] IHL;

rand bit [7:0] data;
endclass

That works if you have exactly one IP frame per ethernet frame. But what if your IP frame does not fit into the ethernet frame and it needs to be segmented? This approach works when you have a one-to-one layering granularity, but not when you have to deal with one-to-many (i.e. segmentation), many-to-one (i.e. reassembly, concatenation) or plesio-synchronous (e.g. justification) payloads.

This approach also limits the reusability of the protocol transactions: the ethernet frame above can only carry an IP frame. How could it carry other protocols? or random bytes? How could the IP frame above be transported by another protocol?

And let’s not even start to think about error injection…

One solution is to use transactors to perform the encapsulation. The encapsulator would have an input channel for the higher layer protocol and an output channel for the lower layer protocol.

class ip_on_ethernet extends vmm_xactor;
ip_frame_channel in_chan;
eth_frame_channel out_chan;

endclass

The protocol transactions are generic and may contain generic references to their payload or transport layers.

class eth_frame extends vmm_data;
vmm_data transport[$];
vmm_data payload[$];

rand bit [47:0] da;
rand bit [47:0] sa;
rand bit [15:0] len_typ;
rand bit [  7:0] data[];
rand bit [31:0] fcs;

endclass

class ip_frame extends vmm_data;

vmm_data transport[$];
vmm_data payload[$];

rand bit [3:0] version;
rand bit [3:0] IHL;

rand bit [7:0] data;
endclass

The transactor main() task, simply waits for higher-layer protocol transactions, packs them into a byte stream, then lays the byte stream into the payload portion of new instances of the lower-layer protocol.

virtual task main();
super.main();

forever begin
bit [7:0] bytes[];
ip_frame ip;
eth_frame eth;

this.wait_if_stopped_or_empty(this.in_chan);
this.in_chan.activate(ip);

// Pre-encapsulation callbacks (for delay & error injection)…

this.in_chan.start();
ip.byte_pack(bytes, 0);
if (bytes.size() > 1500) begin

`vmm_error(log, “IP packet is too large for Ethernet frame”);
continue;
end

eth = new(); // Should really use a factory here

eth.da = …;
eth.sa = …;
eth.len_typ = ‘h0800;  // Indicate IP payload

eth.data = bytes;
eth.fcs = 32’h0000_0000;

ip.transport.push_back(eth);
eth.payload.push_back(ip);

// Pre-tx callbacks (for delay and ethernet-level error injection)…

this.out_chan.put(eth);
eth.notify.wait_for(vmm_data::ENDED);

this.in_chan.complete();

// Post-encapsulation callbacks (for functional coverage)…

this.in_chan.remove();
end
endtask

When setting the header fields in the lower-layer protocol, you can use values from the higher-layer protocols (like setting the len_typ field to 0×0800 above, indicating an IP payload), you can use values configured in the encapsulator (e.g. a routing table) or they can be randomly generated with appropriate constraints:

if (!route.exists(ip.da)) begin
bit [47:0] da = {$urandom, $urandom};  // $urandom is only 32-bit

da[41:40] = 2’b00; // Unicast, global address
route[ip.da] = da;
end
eth.da = route[ip.da];

The protocol layers observed by your DUT are then defined by the combination and order of these encapsulation transactor.

vmm_scheducler instances may also be used at various points in the layering to combine multiple streams (maybe carrying different protocol stacks and layers) into a single stream.

Posted in Modeling, Modeling Transactions, Phasing, Structural Components, SystemVerilog, Tutorial | 3 Comments »

f14a9c9eb40a827fbe090f5e377eb902wwwwwwwwwwwwwwwwwwwwwwwwwww