Verification Martial Arts: A Verification Methodology Blog

Archive for the 'Debug' Category

Webinar on Deploying UVM Effectively

Posted by Shankar Hemmady on 22nd October 2012

Over the past two years, several design and verification teams have begun using SystemVerilog testbench with UVM. They are moving to SystemVerilog because coverage, assertions and object-oriented programming concepts like inheritance and polymorphism allow them to reuse code much more efficiently.  This helps them in not only finding the bugs they expect, but also corner-case issues. Building testing frameworks that randomly exercise the stimulus state space of a design-under-test and analyzing completion through coverage metrics seems to be the most effective way to validate a large chip. UVM offers a standard method for abstraction, automation, encapsulation, and coding practice, allowing teams to build effective, reusable testbenches quickly that can be leveraged throughout their organizations.

However, for all of its value, UVM deployment has unique challenges, particularly in the realm of debugging. Some of these challenges are:

  • Phase management: objections and synchronization
  • Thread debugging
  • Tracing issues through automatically generated code, macro expansion, and parameterized classes
  • Default error messages that are verbose but often imprecise
  • Extended classes with methods that have implicit (and maybe unexpected) behavior
  • Object IDs that are distinct from object handles
  • Visualization of dynamic types and ephemeral classes

Debugging even simple issues can be an arduous task without UVM-aware tools. Here is a public webinar that reviews how to utilize VCS and DVE to most effectively deploy, debug and optimize UVM testbenches.

Link at http://www.synopsys.com/tools/verification/functionalverification/pages/Webinars.aspx

Posted in Coverage, Metrics, Debug, UVM | No Comments »

DVE and UVM on wheels

Posted by Yaron Ilani on 22nd May 2012

Sometimes driving to work can be a little bit boring so a few days ago I decided to take advantage of this time slot to introduce myself and tell you a little bit about the behind-the-scenes of my video blog. Hope you’ll like it !

Hey if you’ve missed any of my short DVE videos – here they are:

Posted in Debug, UVM, Verification Planning & Management | No Comments »

Are You Afraid of Breakpoints?

Posted by Yaron Ilani on 17th May 2012

Are you afraid of breakpoints? Don’t worry, many of us have been.  After all, breakpoints are for software folks, not for us chip heads, right??
Well, not really… In many ways, chip verification is pretty much a software project.
Still, most of the people I know fall into one of these two categories – the $display person, or the breakpoints person.

The former doesn’t like breakpoints. He or she would rather fill up their code with $display’s and UVM_INFO’s and recompile their code every time around.
That’s cool.
The latter likes and appreciates breakpoints and uses them whenever possible instead of traditional $display commands.

So if you are the second type – here’s some great news from DVE that will help you be even more efficient.
And $display folks – stay tuned as it may be time for you to finally convert :-)

In this short video I show how to use Object ID’s – a new infrastructure in DVE – to break in a specific class instance !

 

Want more ?

Go here to catch up with our latest DVE and UVM short videos:
http://www.youtube.com/playlist?list=PL06DA5270480FC7E1

Posted in Debug, SystemVerilog, UVM, Uncategorized | No Comments »

Customizing UVM Messages Without Getting a Sunburn

Posted by Brian Hunter on 24th April 2012

The code snippets presented are available below the video.

my_macros.sv:

   `define my_info(MSG, VERBOSITY) \
      begin \
         if(uvm_report_enabled(VERBOSITY,UVM_INFO,get_full_name())) \
            uvm_report_info(get_full_name(), $sformatf MSG, 0, `uvm_file, `uvm_line); \
      end

  `define my_err(MSG)         \
      begin \
         if(uvm_report_enabled(UVM_NONE,UVM_ERROR,get_full_name())) \
            uvm_report_error(get_full_name(), $sformatf MSG, UVM_NONE, `uvm_file, `uvm_line); \
      end

   `define my_warn(MSG)        \
      begin \
         if(uvm_report_enabled(UVM_NONE,UVM_WARNING,get_full_name())) \
            uvm_report_warning(get_full_name(), $sformatf MSG, UVM_NONE, `uvm_file, `uvm_line); \
      end

   `define my_fatal(MSG)       \
      begin \
         if(uvm_report_enabled(UVM_NONE,UVM_FATAL,get_full_name())) \
            uvm_report_fatal(get_full_name(), $sformatf MSG, UVM_NONE, `uvm_file, `uvm_line); \
      end

my_init.sv:

  initial begin
      my_report_server_c report_server = new("my_report_server");

      if($value$plusargs("fname_width=%d", fwidth)) begin
         report_server.file_name_width = fwidth;
      end
      if($value$plusargs("hier_width=%d", hwidth)) begin
         report_server.hier_width = hwidth;
      end

      uvm_pkg::uvm_report_server::set_server(report_server);

      // all "%t" shall print out in ns format with 8 digit field width
      $timeformat(-9,0,"ns",8);
   end

my_report_server.sv:

class my_report_server_c extends uvm_report_server;
   `uvm_object_utils(my_report_server_c)

   string filename_cache[string];
   string hier_cache[string];

   int    unsigned file_name_width = 28;
   int    unsigned hier_width = 60;

   uvm_severity_type sev_type;
   string prefix, time_str, code_str, fill_char, file_str, hier_str;
   int    last_slash, flen, hier_len;

   function new(string name="my_report_server");
      super.new();
   endfunction : new

   virtual function string compose_message(uvm_severity severity, string name, string id, string message,
                                           string filename, int line);
      // format filename & line-number
      last_slash = filename.len() - 1;
      if(file_name_width > 0) begin
         if(filename_cache.exists(filename))
            file_str = filename_cache[filename];
         else begin
            while(filename[last_slash] != "/" && last_slash != 0)
               last_slash--;
            file_str = (filename[last_slash] == "/")?
                       filename.substr(last_slash+1, filename.len()-1) :
                       filename;

            flen = file_str.len();
            file_str = (flen > file_name_width)?
                       file_str.substr((flen - file_name_width), flen-1) :
                       {{(file_name_width-flen){" "}}, file_str};
            filename_cache[filename] = file_str;
         end
         $swrite(file_str, "(%s:%6d) ", file_str, line);
      end else
         file_str = "";

      // format hier
      hier_len = id.len();
      if(hier_width > 0) begin
         if(hier_cache.exists(id))
            hier_str = hier_cache[id];
         else begin
            if(hier_len > 13 && id.substr(0,12) == "uvm_test_top.") begin
               id = id.substr(13, hier_len-1);
               hier_len -= 13;
            end
            if(hier_len < hier_width)
               hier_str = {id, {(hier_width - hier_len){" "}}};
            else if(hier_len > hier_width)
               hier_str = id.substr(hier_len - hier_width, hier_len - 1);
            else
               hier_str = id;
            hier_str = {"[", hier_str, "]"};
            hier_cache[id] = hier_str;
         end
      end else
         hier_str = "";

      // format time
      $swrite(time_str, " {%t}", $time);

      // determine fill character
      sev_type = uvm_severity_type'(severity);
      case(sev_type)
         UVM_INFO:    begin code_str = "%I"; fill_char = " "; end
         UVM_ERROR:   begin code_str = "%E"; fill_char = "_"; end
         UVM_WARNING: begin code_str = "%W"; fill_char = "."; end
         UVM_FATAL:   begin code_str = "%F"; fill_char = "*"; end
         default:     begin code_str = "%?"; fill_char = "?"; end
      endcase

      // create line's prefix (everything up to time)
      $swrite(prefix, "%s-%s%s%s", code_str, file_str, hier_str, time_str);
      if(fill_char != " ") begin
         for(int x = 0; x < prefix.len(); x++)
            if(prefix[x] == " ")
               prefix.putc(x, fill_char);
      end

      // append message
      return {prefix, " ", message};
   endfunction : compose_message
endclass : my_report_server_c

Posted in Debug, Messaging, SystemVerilog, UVM, Verification Planning & Management | 1 Comment »

How do I debug issues related to UVM objections?

Posted by Vidyashankar Ramaswamy on 19th January 2012

Recently one of the engineers I work with in the networking industry was describing the challenges in debugging the UVM timeout error message. I was curious and looked into his test bench. After spending an hour or so, I was able to point out the master/slave driver issue where the objection was not dropped and the simulation thread hung waiting for the objections to drop. Then I started thinking, why not use the run time option to track the status of the objection: +UVM_OBJECTION_TRACE? Well, this printed detailed messages about the objections, a lot more than what I was looking for! The problem now was to decipher the overwhelming messages spitted by the objection trace option! In a hierarchical test bench, there could be hundreds of component, and you might be debugging some SoC level test bench which you didn’t write or are familiar with. Here is an excerpt of the message log using the built in objection trace:

….
VM_INFO @ 0: reset [OBJTN_TRC] Object uvm_test_top.env.master_agent.mast_drv dropped 1 objection(s): count=0 total=0
UVM_INFO @ 0: reset [OBJTN_TRC] Object uvm_test_top.env.master_agent.mast_mon raised 1 objection(s): count=1 total=1UVM_INFO @ 0: reset [OBJTN_TRC] Object uvm_test_top.env.master_agent added 1 objection(s) to its total (raised from source object ): count=0 total=2
UVM_INFO @ 0: reset [OBJTN_TRC] Object uvm_test_top.env added 1 objection(s) to its total (raised from source object ): count=0 total=2
….
UVM_INFO @ 0: reset [OBJTN_TRC] Object uvm_test_top.env.master_agent.mast_mon dropped 1 objection(s): count=0 total=0
UVM_INFO @ 0: reset [OBJTN_TRC] Object uvm_test_top.env.slave_agent.drv raised 1 objection(s): count=1 total=1
….

As a verification engineer, you want to begin debugging the component or part of the test bench code which did not lower the objection as soon as possible. You want to minimize looking into the unfamiliar test bench code as much as possible or stepping through the code using a debugger.

The best way is to call the display_objections() just before timeout has been reached. As there is no callback available in the timeout procedure, I thought of writing the following few lines of code which can be forked off in any task based phase. I would recommend doing this in your base test which can be extended to create feature-specific tests. You can save some CPU processing cycles by coding this into a run time option:

top = uvm_root::get();
fork
begin
#(top.phase_timeout -1);
phase.phase_done.display_objections();
end
join_none

Output of the log message using the above code is shown below:

————————————————————————————
The total objection count is 2
————————————————————————————
Source              Total
Count               Count             Object
————————————————————————————
0                          2                   uvm_top
0                          2                       uvm_test_top
0                          2                           env
0                          1                               master_agent
1 1 mast_drv
0                          1                               slave_agent
1 1 slv_drv
———————————————————————————-

From the above table, it is clear that the master and slave driver did not drop the objection. Now you can look into the master and slave driver components, and further debug why these components did not drop their objection. There are many different ways to achieve the same results. I welcome you to share your thoughts and ideas on this.

Posted in Debug, Messaging, UVM | No Comments »

Cool Things You Can Do With DVE – Part 4

Posted by Yaron Ilani on 26th April 2011

Yaron Ilani, Apps. Consultant, Synopsys

If you liked part 2 where I explained how Interactive Rewind could save you precious time during debug, then here’s another one for you. Obviously one of the most powerful methods of debugging interactively is by adding breakpoints at interesting points. You could have a single breakpoint as a starting point and then go on step by step. But in most cases it would be wiser to put multiple breakpoints in your code so that you could have more control over your simulation or even jump from one interesting point to another (remember you can always go backwards in time).

So the process of adding breakpoints and refining them might take some time and ideally you wouldn’t want to repeat that process all over again when you start a new interactive debug session. Wouldn’t it be nice to be able to save your breakpoints so that you or someone else from your team could reuse them in a different simulation? Well, DVE lets you do that! Simply launch the Breakpoints window from the Simulator menu:

In the example above I’ve added 3 breakpoints. In the source code window they are marked in red, but they are also listed in the Breakpoints window where each breakpoint can be enabled or disabled individually. In the bottom left you can see the “Save” button. Clicking on it will save all your breakpoints to a TCL file. You may use this file later on in any other DVE session by clicking on the “Load” button.

Once your test bench code is more or less stable, with this new feature you can actually create a number of useful breakpoints files (a breakpoints library if you will…). Each breakpoints file could be designed to help debugging a different part of your test bench. Or if you’re debugging some unfamiliar verification IP, you can create a breakpoints file and send it to its owner for help.

Happy debugging!

Check out the previous parts of this series to learn more about more cool features available today in DVE.

Posted in Automation, Debug | 4 Comments »

Cool Things You Can Do With DVE – Part 3

Posted by Yaron Ilani on 13th April 2011

Yaron Ilani, Apps. Consultant, Synopsys

If you missed part 1 or part 2 of this series don’t worry, you can go on reading and catch up with the previous parts later on. Today I’m going to show you a small, yet very powerful feature in DVE that you may not be aware of.

Remember the last time you had to count clock cycles in the waveform window? Sometimes this is a quick way to verify that an internal counter behaves correctly or that a signal goes up just at the right clock edge. Remember how frustrating it is when you lose count for some reason and have to start over? Remember how you’re never 100% sure about the result even if you calculated the time difference between the left and right cursors and divided by the clock period? If your answer was yes to any of those questions then you’re going to love the Grid feature. What Grid simply does, as its name suggests, is draw a grid on top of the waveform. Here’s what it looks like:

If you click on the Grid button (in the red circle) the Grid will show up as dotted lines. As you can see, the Grid can count clock cycles for you. You can set it up to count falling edges, rising edges or any edge. You can also set the range either by entering the start time and end time, or simply by placing the cursors at the desired points and clicking on the “Get Time From C1/C2” button in the Grid Properties window:

The Grid Properties window lets you have even more control over the grid. For example – you can set its cycle time to a custom value. This could be very useful if you want to be able to visually inspect drifting clocks or duty-cycle issues, etc.

In short, the Grid is one of those little things that make a big difference when it comes to efficient debugging and you should definitely become familiar with it. If you ever have to count clock cycles again, remember that you no longer have to do this manually. You don’t even have to make any calculations. Simply launch the Grid and voila!

If you’d like to learn more about DVE’s advanced debug features check out part 1 and part 2 of this series.

Posted in Automation, Debug | 3 Comments »

Cool Things You Can Do With DVE – Part 2

Posted by Yaron Ilani on 7th April 2011

Yaron Ilani, Apps. Consultant, Synopsys

In Part 1 of this series we discussed how SystemVerilog macros might add complexity when it comes to debugging your test bench and how DVE can make your life much easier in that area. Today we’re going to show you another cool feature in DVE that if used wisely, could save you a significant amount of time when debugging. Let’s recall for a moment the two main use models of DVE – Post Processing and Interactive. The former is where you’re debugging your simulation results after it has completed. The latter is where you’re running and debugging your simulation simultaneously, trading off performance for enhanced debug capabilities. Today we shall focus on the interactive mode. We’re about to see how the Interactive Rewind feature will help you minimize your debug turnaround time.

So during a typical interactive session you put a breakpoint somewhere in your code and let the simulation run until it reaches your breakpoint. From that point and on you take the controls and advance the simulation step by step which allows you to inspect your signals or variables very closely. You may assign different values to signals along the way to try out potential workarounds or fixes. Now here’s the tricky part: simulation can only advance forward! So if your breakpoint occurs late in the simulation, every time you want to restart your debug trail you’re bound to wait for the simulation to rerun from the beginning. Why would you want to start over? Well, you might want to change a signal value (remember you can force signals interactively in DVE). But more often than not, stepping through your code gets very complicated and you might miss the interesting point where the bug occurs, or you lose track of the debug trail and need to start fresh. In certain cases your breakpoints occur periodically (e.g. every time a packet is transmitted) and you just wish you could go back in time to the previous occurrence to step through the code again.

The good news is that DVE allows you to navigate backwards in simulation!  We call it Interactive Rewind. All you have to do is set up one or more checkpoints along the simulation. Upon each checkpoint a snapshot of the simulation is saved and you may use it later on to literally go back in time. To give you a sense of how easy it is to work with checkpoints, here’s how it looks like – the left button is used to add a new checkpoint. The right button will be used later to rewind to any of the previously added checkpoints.

Selecting a checkpoint to rewind to is easy: simply select one from the drop-down menu:

You can also control your checkpoints via UCLI, where you’ll find many advanced features such as the ability to add periodic checkpoints automatically.

To sum up, interactive debugging with DVE becomes much more efficient with Interactive Rewind. Simply add checkpoints at strategic points along the debug trail. Then use Step/Next to advance simulation time and Rewind to go back. This will keep your debug turnaround time to minimum, thus enabling you to focus on debugging and not waiting.

Posted in Automation, Debug | 10 Comments »

Cool Things You Can Do With DVE – Part 1

Posted by Yaron Ilani on 3rd April 2011

Yaron Ilani, Apps. Consultant, Synopsys

A SystemVerilog test bench could get quite complex. Typical projects today have thousands of lines of code, and the number is constantly on the rise. However, standard base class libraries such as VMM and UVM can help you minimize the amount of code that needs to be rewritten by providing a rich set of macros that substitute long lines of code with a single line. For example, the simple line `vmm_channel(atm_cell) defines a standard VMM channel for an ATM cell with all the necessary fields and methods, all under the hood. All you have to do is instantiate the newly defined channel wherever you need it.A close cousin to the SV macro is the `include directive which basically substitutes an entire file with a single line. This is a neat way to reuse files and enhance code clarity.

But what happens when you need to debug your source code? Indeed, macros and `includes allow for less clutter and enhanced readability, but at the same time hide from you pieces of code you might actually need access to during debug. Fortunately enough, DVE ships with some new cool features that give you quick and easy access to any underlying code and thus taking the pain out of debugging a SystemVerilog test bench. Let’s see some of them:

Macro Tooltips

Hover your mouse over a macro statement and a tooltip window will pop up displaying the underlying code – very useful for short macros. The tooltip’s height can be customized to your liking!

Macro Expand/Collapse

Macros can be expanded interactively so that the underlying source code is presented in the source file you are viewing. Very powerful!

Hyperlinks / Back / Forward

Clicking on a macro/include statement will take you to the original source code or file.

Don’t worry, you can always go back and forth using the browser-like Back/Forward buttons.

To sum up, DVE offers a really comfortable way to debug your SystemVerilog source code – be it plain code, macros or `included files. While keeping you focused on the important part of your code, DVE provides quick and easy access to any underlying code. And thanks to the Back & Forward buttons you can skip back and forth between macros, `included files and your main source file as smoothly as you would in your internet browser. This really takes the pain out of debugging a modern SystemVerilog test bench.

Posted in Debug, SystemVerilog | 3 Comments »

Transaction Debugging with Discovery Visualization Environment (DVE) Part-2

Posted by JL Gray on 8th March 2011

Asif Jafri, Verilab Inc.

In my previous blog post, I introduced how to dump waves and how to use $tblog for dynamic data and message recording. If you need more control over scope sensitive transaction debugging, $msglog task is very useful. This blog has been divided into two sections: in the the first section, I talk about how to use $msglog. In the second section, I will discuss how VMM performs transaction recording by calling $msglog from within the VMM library. The call is protected so as not to confuse other simulators or tools. You can use $msglog in any of your code as well.

•    The advantage of using $msglog is that we have more control over the debug messaging. If a transaction can be divided into start and finish, it is possible to identify cause and effect.
•    Parent and child relationship can be shown
•    Identify execution stream with start and end time.

The following steps need to be followed to invoke $msglog.

Include msglog.svh in testbench code
Add +incdir+${VCS_HOME}/include in the compile line

1) The example below shows how to call the $msglog task in the testbench. The first msglog statement creates a transaction (read) on a stream (stream1) which has an attribute addr. It also sets the header text (RD) and body text (text 1). This statement can be placed in a read task of your transactor.  The second msglog statement once again can be placed in the read task and it shows when the read completes. Streams are global and do not need to be created explicitly. They are created implicitly as they are needed.

$msglog (“stream1”, XACTION, “read”, NORMAL, “RD”, “text 1”, START, addr);

clip_image001[19]

$msglog (“stream1”, XACTION, “read”, NORMAL, “”, FINISH);

The table below shows the various possible parameters for the type, severity and relation field in the $msglog task:

Type

Severity

Relation

FAILURE

FATAL

START

NOTE

ERROR

FINISH

DEBUG

WARNING

PRED

REPORT

NORMAL

SUCC

NOTIFY

TRACE

SUB

TIMING

DEBUG

PARENT

XHANDLING

VERBOSE

CHILD

XACTION

HIDDEN

XTEND

PROTOCOL

IGNORE

USER

COMMAND

CYCLE

As shown above you can also place $msglog tasks in the response task of the responding transactor if the transaction needs to be followed into the response transactor.

$msglog(“stream1″, XACTION, “resp”, NORMAL, “RESP”, START, data);

2) VMM provides build-in transaction recording. To enable it use “+define+VMM_TR_RECORD” when compiling your code. At simulation runtime, recording of transactions is controlled by setting “+vmm_tr_verbosity=debug” in the command line.
The following VMM base classes have build-in recording support:
vmm_channel, vmm_voter, vmm_env, vmm_subenv, vmm_timeline

The figure below shows an example of the recorded transactions as viewed in the waveform viewer:

image


You can also do your own transaction recording by using the following VMM functions:

vmm_tr_record::open_stream
vmm_tr_record::open_sub_stream
vmm_tr_record::close_stream
vmm_tr_record::start_tr
vmm_tr_record::extend_tr
vmm_tr_record::end_tr


e.g.
mystream = vmm_tr_record::open_stream(get_instance(), “MyChannel”);

vmm_tr_record::start_tr(mystream, “Read”, “Text line 1\nText line 2”);

vmm_tr_record::end_tr(mystream);

vmm_tr_record::close_stream(mystream);


As shown in the two part blogs on transaction debugging, $tblog and $msglog can be very useful transaction debugging constructs. You can choose to dump transactions and follow them through the environment, dump channel data, notification ID, phase names etc. To be able to see all this information on the waveform viewer has been a blessing for me.  I hope it is helpful to you.

Posted in Debug, VMM infrastructure | No Comments »

Transaction Debugging with Discovery Visualization Environment (DVE) Part-1

Posted by JL Gray on 25th February 2011

Asif Jafri, Verilab Inc., Austin, TX

The art of verification has evolved dramatically over the last decade. What used to be a very simple verilog testbench which could not possibly cover the vast solution space has evolved into the current monstrosity (Random testbenches) which is a very powerful tool, but the complexity to debug has gone up exponentially.

VMM has introduced various debug constructs to aid in the debug of the design as well as the test environment such as:
•    Messaging: Report regular, debug, or error information.
•    Recording: Transaction and components have built-in recording facilities that enable transaction and environment debugging.

Today I want to spend some time looking at DVE as a powerful debug tool in our tool box.

To start things off lets look at some simple calls used to invoke dumping waves.

1) $vcdpluson() : This call is used to start dumping design signals into a .vpd (VCD plus) format. “vpd” is a proprietary Synopsys format (binary, highly compressed) that is generated by vcs, which solves the issue of generating excessively large .vcd (IEEE standard) format files.

Eg:
initial
    begin
        $vcdpluson();
    end

When compiling, specify -debug_pp (for post process debug), -debug (for interactive debug), -debug_all (for interactive debug with line stepping and breakpoints) to enable VCS Dumping.

The code snippets shown above will generate waves of all design signals for viewing in the DVE waveform viewer. You can also use the UCLI (unified command line interface) command ‘dump’ for dumping design signals interactively or in scripts.

Won’t it be great if we can also view dynamic variables as waveforms?

2) $tblog() system task is used for recording dynamic (or static) data and simple messages.  No additional environment setup is required. $tblog() has to be called in the testbench where you want to record a message or a variable. The next example shows how to record a message in the send_packet task of a transactor.

// Foo transactor
task send_packet();
    int id; // local variable
    …
    $tblog(-1, “Sending packet”); // record all local and class variables
    …
    cnt = cnt + 1; // cnt is a class variable
    if (cnt < 50)
       $tblog(0, “Count is less than 50”, cnt, id); // record variable cnt and id

endtask: send_packet

Along with the message and variable values, $tblog automatically records the time and the call stack. To view these messages and variables in the waveform viewer select a recording from transaction browser and add it as a waveform.
The figure below shows how a message is displayed in a DVE waveform window.

image

Another useful tool for transaction debugging is using the $msglog task which will be discussed in the next article “Hyperlink….”.

Posted in Debug, VMM infrastructure | No Comments »

Cool Things You Can Do With DVE – The Videos

Posted by Yaron Ilani on 19th January 2011

DVE is now on YouTube !! Here’s a collection of short videos demonstrating some the coolest features in DVE that you need to know about. If you wish to learn more, check out the the recent blog articles. Enjoy!

Debugging UVM Sequences

Searching & Cool GUI tips

Interactive Rewind

Debugging SystemVerilog Macros

Debugging FSMs & The Grid

Debugging Your Source Code

Debugging SystemVerilog Assertions (SVA)

Tracing Drivers and Active Driver

More videos coming up soon…

Posted in Debug | 1 Comment »

VMM Smart Log in DVT

Posted by Cristian Amitroaie on 1st April 2010

In this blog, I’d like to cover two cool features that are coming up with the DVT Integrated Development Environment (IDE). The 1st one is the possibility to color VMM log occurrences, the 2nd one a possibility to hyperlink these occurrences to the VMM source code.

Here is a snapshot showing VMM logs being colored and hyperlinked to source code:

vlogdt-vmm-smart-log

Not only providing hyperlinks from VMM log to source code, DVT also provides hyperlinks to VCS compilation/simulation errors and warnings. To enable these features, all you have to do is to define the right parameters in DVT Run Configuration window. For instance, you can specify the compilation/simulation commands and turn VMM log filtering from the corresponding tab.

APB_Run_Configuration

This is just one among many other VMM features that are available in DVT.

For more details see www.dvteclipse.com.

Posted in Debug, Tools & 3rd Party interfaces, VMM | No Comments »

Role of methodology in Assertion Based Verification (ABV)

Posted by Srinivasan Venkataramanan on 25th March 2010

Srinivasan Venkataramanan, CVC Pvt. Ltd.

Abhishek Muchandikar, CAE, Verification Group, Synopsys

Raja Mahadevan, Sr. CAE, Verification Group, Synopsys

It is well understood and accepted fact that Assertions play a critical role in detecting a class of design errors (or bugs) in functional verification. Just like any other verification component in a robust, reusable environment, assertions need to be both controllable and observable from various levels including tests, regressions, command line etc. However an ad-hoc throw of assertions across the design and verification code doesn’t always consider this requirement upfront.

Recently standardized SystemVerilog 2009 construct checker..endchecker is definitely a good step towards creating a good encapsulation for these widely spread out assertions. In our recent book on SystemVerilog Assertions (2nd edition of SVA handbook, www.systemverilog.us/sva_info.html ) we cover this construct in depth. We also presented a case study of a Cache controller verification using these new constructs at DVCon 2010 (paper & code available from www.cvcblr.com on request).

The role of a methodology goes far beyond the constructs, it does utilize them but provides more controllability and observability for the end user trying to make sense out of all these various features to achieve his/her final goal of getting verification done.

In this series of blog entries we try and cover some of the key aspects of such methodology role in adopting ABV (Assertion Based Verification). We welcome reader comments to add more innovative thoughts and ideas to this puzzle. Our goal of this blog series is not to cover all possible aspects of ABV methodology as that would include a wide range of topics, many of them already well covered in VMM book (www.vmm-sv.org); rather in this blog series we look at application aspects of ABV methodology.

To start with, let’s partition the role of methodology into two major buckets: observability & controllability.

Under observability we will explore the following:

· Make assertions observable in native form within the methodology framework

· Tie the assertion results to the verification plan via VMM Planner hooks

Under controllability we will explore the following:

· Control the severity & verbosity of assertions from external world – command line, testcases etc.

· Control assertion execution during reset, exceptions, low power etc.

Making assertions natively observable in VMM

In simulation based verification, observability is primarily enabled by the kind of messages that get emitted during the run. Messaging service plays an important part in a verification environment indicating the progress of the simulation or providing additional information to debug a design malfunction.  To ensure a consistent look and better organization of messages issued by various verification layers be it the transactor, scoreboards, or assertions, use of a standard messaging service is required. VMM provides a time-proven utility vmm_log to enable this key requirement. While the use of vmm_log in a typical VMM environment is well understood and widely deployed, the integration of the same to assertions is not that widely spoken about in the literature.

Assertion reporting as such always tends to be a loner in terms of the verification environment messaging family. This is due to the fact that assertion reporting has been handled in ad-hoc manner – many a times unattended (i.e. no action blocks at all), this can lead to simulator specific reports for assertion firings (pass/fail) where as the rest of testbench environment uses a consistent vmm_log style.

The drawback of such a use model is twofold:

· Absence of a single tightly integrated messaging service across the verification board

Assertion failures do not interact with the test bench environment and hence there is absolutely no way to effectively and correctly qualify the simulation. The limitation of such a behavior (in a regression setup), would never qualify the test as a “failures” unless some other post processing is duly placed

· Assertion results bear zero control over the verification simulation cycles

Quite often it is observed that the tests tend to run the entire simulation cycles even in the presence of assertions failures which maybe uncalled for and may warrant an immediate termination of the simulation.

Efficient incorporation of assertions in a verification environment calls for synchronization between assertion results and the verification environment. A common messaging service would be the key to such synchronization. The VMM messaging service “vmm_log” is a fine example of a standard messaging class which is seamlessly integrated into assertion checkers/properties which ensures consistency across the complete verification environment.

The user could force the simulation to quit via a `vmm_fatal macro or proceed with the simulation for a particular checker instance failure. The use of vmm_log for assertion error messaging gets recognized by the VMM environment leading to an effective simulation result. Integration of VMM messaging service provides extended flexibility to the user to control the simulation based on the severity of the checker instance.

Steps to integrate vmm_log with assertion reporting

· Declaration of a new package with a static VMM log object

package vmm_sva;

`include “vmm.sv”

vmm_log sva_vmm_log = new(“SVA_CHECKER”,$psprintf(“%m”));

endpackage : vmm_sva

· Inclusion of the package in the assertion file

module sva_file(….)

import vmm_sva ::*;

// AHB master property check

property HburstSingleHtransNseq;

@ (posedge HCLK)disable iff (!HRESETn) (

((SINGLE && HGRANT)

)

|-> ((NSEQ || IDLE)));

endproperty

HburstSingleHtransNseq_check  : assert property (HburstSingleHtransNseq)

else `vmm_fatal (sva_vmm_log, “AMBA Compliance Protocol Rules : ERRMSINGLE: Master has issued a SEQ/BUSY type SINGLE transfer”));

endmodule

Simulation Result:

Bases on the severity of the assertion, you could terminate the simulation and also the testbench environment recognizers this failure and qualifies the simulation as a failure as depicted below

*FATAL*[FAILURE] on SVA_CHECKER(vmm_sva) at                  195:

[AMBA Compliance Protocol Rules : ERRMSINGLE]   Master has issued a SEQ/BUSY type SINGLE transfer

Simulation *FAILED* on /./ (/./) at                  195: 1 errors, 0 warnings

$finish called from file “/tools/eda/snps/vcs-mx/etc/rvm/vmm.sv”, line 36499.

$finish at simulation time                  195

V C S   S i m u l a t i o n   R e p o r t

Users can choose from the variety of vmm_log macros such as `vmm_error, `vmm_warning etc. to suit the relevant message being flagged by that assertion. With this subtle change/enhancement to the SVA action block one can leverage on VMM’s simulation controllability features such as error counting, simulation handling of errors (stop, debug, continue etc.). One can also promote/demote errors to warnings for instance.

A final note on the logger instance being shown in this example: while the above shown code works, typical usage would classify the messages originating from different portions of design/verification into individual logger instances.

In our next entry in this series, we will address the second aspect of observability – i.e. tie the results to Verification plan, so stay tuned!

Posted in Assertion Based Verification, Debug, Messaging | 5 Comments »

Great article on managing complex constraints

Posted by Janick Bergeron on 12th March 2010

A two-part articles by Cisco and Synopsys engineers in IC Design and Verification Journal explains how complex constraints can be better managed to simplify the solving process, yet obtain high-quality results. Part1 deals with solutions spaces and constraint partitions. Part2 introduces the concept of soft constraint in e and default constraints in OpenVera.

You can read part1 and part2 here.

Posted in Debug, Modeling Transactions, Optimization/Performance, Stimulus Generation | 2 Comments »

Watch out for “totally vacuous” assertion attempts in your verification

Posted by Srinivasan Venkataramanan on 10th March 2010

Srinivasan Venkataramanan, CVC Pvt. Ltd.

Abhishek Muchandikar, Sr RnD Engineer, Verification Group, Synopsys

Sadanand Gulwadi, Sr. Staff CAE, Verification Group, Synopsys Inc., Mt. View, CA, USA

Assertions for protocol checking has been popular for quite some time now. With several off-the-shelf assertion/monitor IPs available from EDA vendors and providers such as CVC (www.cvcblr.com), end users need not have to spend too much time thinking about what assertions to add in their designs, how to code them etc. All that users would need to do is to create suitable bind files and off they go!

While using assertions sounds simple and straightforward, there are scenarios for which users need to watch out. The methodology of using assertions and leveraging on assertion indications from simulations is vital for ROI of Assertion Based Verification. There are several assertion coding guidelines available with VMM book – infact a whole chapter is dedicated to writing effective assertions (Chapter-3, see: http://www.springer.com/engineering/circuits+%26+systems/book/978-0-387-25538-5).

VMM also provides guidelines on how to integrate assertions errors via standard messaging route such as `vmm_error. An additional methodology note that we developed while working with a large DSP customer is to identify quickly “totally vacuous” assertions in a simulation run.

For example, if assertions did fire, then you have likely found a bug. However if assertions remained silent throughout a simulation, then you cannot afford to be too happy, for the assertions may have been “totally vacuous”. This is a term that my ex-colleague and I coined during our work at a large DSP customer here. They were adding assertions and looking for improved productivity early on rather than having to go through detailed assertion coverage metrics, various dump files, and so forth at a later stage While standard garden variety vacuity is quite well understood and explained in our regular SVA trainings (SVA Trainings), the concept of “totally vacuous” is a step beyond that. Totally vacuous assertions are those that were *never* successful during the entire simulation run. This can be due to a few reasons:

1. The assertions were never attempted at all (perhaps the CLOCK was undriven, or was part of a gated clock of a low power domain etc.)

2. The antecedent of a property was never satisfied etc.

Further, observation of the assertion behaviour stated above might indicate the following potential issues in your design or verification plan:

1. Incorrect clock network connections, clock enables, and so forth.

2. Test-case is weak and does not address a key portion of your design (a coverage hole).

For instance, consider the following assertion (taken from our SVA handbook, www.systemverilog.us/sva_info.html)

/* Behavior: if the transfer type is BUSY then on the corresponding

data transfer , the slave must provide a zero wait state OKAY response

(default clock) */

property pResponseToBusyMustBeZeroWaitOKAY (hResp,hReady,hTrans);

@(posedge hclk) (((hTrans == BUSY) && (hReady == 1)) |->

##1 ((hResp == OKAY) && (hReady == 1)) );

endproperty: pResponseToBusyMustBeZeroWaitOKAY

Consider the case when the stimulus didn’t drive the hTrans to be BUSY throughout the simulation. This is strange and means that the stimulus is weak. However when (and how) does a user find this out? With the usual wisdom of “No news is GOOD news”, it is very easy to ignore this important coverage hole and move on with other work. However, the customer desired such strange assertion behaviour to be flagged as early as possible – at the end of every simulation run.

VCS does have the ability to catch such “totally vacuous” assertions and accordingly reports the following at the end of a simulation run:

**** Following assertions did not fire at all during simulation. *****

“/proj/cvc_mips/ahb_mip/master.sva “, 48:

a_pResponseToBusyMustBeZeroWaitOKAY: Antecedent was never satisfied

“/proj/cvc_mips/ahb_mip/slave.sva “, 32:

a_pLowPowerGclk: No attempt started

The above output is default in VCS without the need for any additional user-driven options and frees the user from the additional steps of enabling assertion coverage, debug, etc. Assertion coverage and debug are indeed powerful features for analyzing problems, but should be turned on only after ensuring the assertions are not “totally vacuous” – a glaring weakness that requires being flagged early on by default. It is all about productivity at the end of the day – if a tool can help improve productivity it is always welcome :-)

So the next time VCS prints such a message, you had better watch out before calling it a day!

Posted in Assertion Based Verification, Debug, Messaging | 1 Comment »

Managing VMM Log verbosity in a smart way

Posted by Srinivasan Venkataramanan on 1st March 2010

Srinivasan Venkataramanan, CVC Pvt. Ltd.

Vishal Namshiker, Brocade Communications

Any complex system requires debugging at some point or the other. To ease the debug process, a good, proven coding practice is to add enough messages for the end user to aid in debug. However as systems become mature the messages tend to become too many and quickly users feel a need for controlling the messages. VMM provides a comprehensive log scheme that provides enough flexibility to let users control what-how-and-when to see certain messages (See: http://www.vmmcentral.org/vmartialarts/?p=259).

As we know the usage of `vmm_verbose/`vmm_debug macros requires the +vmm_log_default=VERBOSE run time argument. However when using this, there are tons of messages coming from VMM base classes too – as they are under the VERBOSE/DEBUG severity. Users at Brocade did not prefer to have these messages when debugging problems in user code. Parsing through these messages and staying focussed on debugging the problem at hand was tedious if post-processing of the log file was not implemented. Sure the messages from VMM base classes are useful to one set of/class of problems, but if the current problem is with user code, user would like to be able to exclude them easily. An interesting problem of contradictory requirements perhaps? Not really, VMM base class is well architected to handle this situation.

In VMM, there are two dimensions to control which messages user would like to see. The verbosity level specifies the minimum severity to display and you’ll see every message with a severity greater to equal to it. The other dimension/classification is based on TYPE. There are several values for the TYPE such as NOTE_TYP, DEBUG_TYP etc. Most relevant here is the INTERNAL_TYP – a special type intended to be used exclusively by VMM base class code. All debug related VMM library messages are classified under INTERNAL_TYP. You can use vmm_log::disable_types() method.

A quick example to do this inside the user_env is below:

virtual function void my_env::build();
super.build();

this.log.disable_types(.typs(vmm_log::INTERNAL_TYP),
.name(“/./”),.inst( “/./”) );
endfunction : build

This is a typical usage if everyone in the team agrees to such a change. However if a localized change is needed for few runs alone, one can combine the power of VCS’s Aspect Oriented Extensions (AOE) made to SystemVerilog. In this case, user supply a separate file as shown below:

///////////  disable_vmm_msg.sv
extends disable_log(vmm_log);
after function new(string name = “/./”,
string instance = “/./”,
vmm_log under = null);
this.disable_types(.typs(vmm_log::INTERNAL_TYP));
endfunction:new

endextends

Add this file to the compile list and voila! BTW, during recent SystemVerilog extensions discussion at DVCon 2010, AOP extensions are being requested by more users to be added to the LRM standard. With its due process, a version of AOP is likely to be added to the LRM in the future (let’s hope in the “near future” :) ).

Posted in Debug, Messaging, SystemVerilog, VMM | No Comments »

Drivers on a Tristate bus….

Posted by Srivatsa Vasudevan on 18th February 2010

Tri-state busses are typically present in a verification environment when we have multiple drivers driving a bus. One of the drivers drives the bus and the rest of the drivers on the bus present high impedance to the bus. By far and large, it is preferred to have a single interface from the testbench side to deal with the tristate bus. This typically helps avoid bus contention.

In some circumstances, this may not be easily possible.

Why don’t you just imagine having to elaborate a design, run to a certain point and run a drivers() command? I’m not sure any of us is looking forward to that are we? Especially if we have to do it again and again.

dummy_signal

If you’re going to do have a tristate bus, one tip would be to add a simple internal signal to the driver that is asserted whenever you’re going to drive a tristate bus. In a dump, that will show up.

The only other alternative would be to run a trace drivers command with a debug switch (-debug_all) to find the contention.

The simple internal signal will save you a lot of debug time and will get thrown out by synthesis if you mark it with the appropriate pragma’s and do it right….

More later… Stay tuned…

Posted in Debug | 1 Comment »

You get real hierarchy with VMM1.2

Posted by Wei-Hua Han on 9th February 2010

If you look at VMM1.2 classes, you may find that almost all new() functions have an argument, vmm_object parent. The purpose of this argument is to build a parent-child hierarchy within a VMM1.2 based environment, so that VMM1.2 can provide an infrastructure where users can access the components inside the environment through hierarchical path and name. And this parent-child hierarchy also contributes to the implicit phasing implementation.

Here is a small example to illustrate how a hierarchy can be built with VMM1.2:

  1. class mike_c extends vmm_object;
  2. function new(vmm_object parent=null, string name=”");
  3. super.new(parent,name);
  4. endfunction
  5. endclass
  6. class ben_c extends vmm_object;
  7. function new(vmm_object parent=null, string name=”");
  8. super.new(parent,name);
  9. endfunction
  10. endclass
  11. class jason_c extends vmm_object;
  12. mike_c Mike;
  13. ben_c Ben;
  14. int weight;
  15. function new(vmm_object parent=null, string name=”");
  16. bit is_set;
  17. super.new(parent,name);
  18. weight=vmm_opts::get_object_int(is_set,this, “weight”,0, “set weight”);
  19. endfunction
  20. function void build();
  21. Mike = new(this,”Mike”);
  22. Ben = new(this,”Ben”);
  23. endfunction
  24. endclass
  25. program p1;
  26. jason_c Jason;
  27. initial begin
  28. vmm_opts::set_int(“Jason:weight”,10);
  29. Jason=new(null,”Jason”);
  30. Jason.build();
  31. vmm_object::print_hierarchy(Jason);
  32. $display(“Jason has %0d children”,Jason.get_num_children());
  33. $display(Jason.Mike.get_object_name());
  34. $display(Jason.Ben.get_object_hiername());
  35. $display(Jason.weight);
  36. end
  37. endprogram

In this small example, line 30 creates an object (Jason) for jason_c and its parent is “null”, so Jason is a root component in the hierarchy. When Jason.build() is called in line 31, object Mike and Ben are created and their parent is set to Jason. So in this small system we build the following hierarchy:

[Jason]

|–[Mike]

|–[Ben]

Jason has 2 children

Mike

Jason:Ben

This hierarchy can be printed by vmm_object method print_hierarchy().

Please note that unlike Verilog modules and instances where the hierarchy is defined as per the Verilog LRM, the VMM1.2 parent-child hierarchy is really user defined. It depends on how “parent” argument is specified when the object is created, and not on where the object variable is declared or created.

As for the component name, although you may choose to specify a different name as the variable name, it is a good practice to keep it consistent, which makes the code more readable and avoids confusion.

From the above example, you can find that the hierarchical name for object Jason.Ben is “Jason:Ben”. VMM1.2 uses “:” as the hierarchical separator instead of “.”. The reason is that this hierarchical name is actually a made-up name, and we want to differentiate it from the semantic hierarchical reference name specified in Verilog/SystemVerilog which uses “.” as the separator.

There are many methods provided in VMM1.2 which help users to work with the parent-child hierarchy. Some of these methods are:

  • find_child_by_name(): finds the named object relative to this object
  • get_num_children(): gets the total number of children for this object
  • get_nth_child(): returns the nth child of this object
  • get_object_hiername(): gets the complete hierarchical name of this object
  • get_parent_object():returns the parent of this object
  • get_root_object(): gets the root parent of this object
  • get_typename(): returns the name of the actual type of this object
  • is_parent_of(): returns true, if the specified object is a parent of this object
  • print_hierarchy(): prints the object hierarchy
  • Set_parent_object(): sets or replaces the parent of this object

Dr. Ambar Sarkar has explained how users can traverse the hierarchy in his blog post.

This parent-child hierarchical infrastructure is one of the most important mechanisms in VMM1.2. Many other VMM1.2 features rely on this infrastructure:

1.   Implicit phasing

Implicit phasing is new in VMM1.2. In implicit phasing, structural components (transactors) are aligned with each other automatically. The phase specific methods are called automatically throughout the whole hierarchy in a top-down (for functions) or forked (for tasks) mode. Thus implicit phasing makes integration of Verification IPs into the simulation environment or other structural components a lot easier. Other VMM1.2 users also benefit from implicit phasing when building complicated verification environments.

2.   Factory replacement

Factory is an important feature that enables flexibility and reuse inside a verification environment. Because of the parent-child hierarchy, users can replace components, generated transactions or scenarios with their extension type or other objects by specifying hierarchy path and names. Support for regular expression for specifying hierarchies and names make this utility very powerful.

For example, in the following code segment, we override the type mike_c for Mike with mike_ext :

mike_c::override_with_new(“@%Jason:Mike”,mike_ext::this_type,log);

3.   Hierarchical configuration

In addition to supporting runtime configuration through command-line options or files, using the parent-child hierarchy VMM1.2 also supports configuration of components by specifying their hierarchical path and name. All these configuration utilities are provided through vmm_opts.

For example, in the following code segment, we set the property weight of object Jason to 10 using hierarchical configuration:

vmm_opts::set_int(“Jason:weight”,10);

Like factory, users can also use regular expression with hierarchical configuration.

If you have watched “Growing Pains”, you know that I am not quite accurate when I say

Jason has 2 children

He indeed has three…

Have fun with VMM1.2. J

Posted in Debug, Reuse, Tutorial, VMM infrastructure | 1 Comment »

Leverage on the built-in callback inside vmm_atomic_gen and be productive with DVE features for VMM debug

Posted by Srinivasan Venkataramanan on 7th February 2010

Srinivasan Venkataramanan, CVC Pvt. Ltd.

Rashmi Talanki, Sasken

John Paul Hirudayasamy, Synopsys

During a recent Verification environment creation for a customer we had to tap an additional copy/reference of the generated transaction to another component in the environment without affecting the flow. So one producer gets more than one consumer (here 2 consumers). As a first time VMM coder the customer tried using “vmm_channel::peek” on the channel that was connecting GEN to BFM. Initially it seemed to work, but with some more complex code being added across the 2 consumers for the channel, things started getting funny – one of the consumers received the transactions more than once for instance.

The log file looked like:

@ (N-1) ns the transaction was peeked by Master_BFM  0.0.0

@ (N-1) ns the transaction was peeked by Slave_BFM 0.0.0

.

.(perform the task)

.

@N ns the Master_BFM  get the transaction 0.0.0

@N ns the transaction was peeked by Slave_BFM 0.0.0

@N ns the transaction was peeked by Master_BFM 0.0.1

@N ns the transaction was peeked by Slave_BFM 0.0.1

With little reasoning from CVC team, the customer understood the issue quickly to be classical race condition of 2 consumers waiting for same transaction. What are the options, well several indeed:

1. Use vmm_channel::tee() (See our VMM Adoption book http://systemverilog.us/vmm_info.html for an example)

2. Use callbacks – a flexible, robust means to provide extensions for any such future requirements

3. Use vmm_broadcaster

4. Use the new VMM 1.2 Analysis Ports (See a good thread on this: http://www.vmmcentral.org/vmartialarts/?p=860 )

The customer liked the callbacks route but was hesitant to move towards the lengthy route of callbacks – for few reasons (valid for first timers).

1. Coding callbacks takes more time than simple chan.peek(), especially the facade class & inserting at the right place

2. She was using the built-in `vmm_atomic_gen macro to create the generator and didn’t know exactly how to add the callbacks there as it is pre-coded!

Up for review, we discussed the pros and cons of the approaches and when I mentioned about the built-in post_inst_gen callback inside the vmm_atomic_gen she got a pleasant surprise – that takes care of 2 of the 4 steps in the typical callbacks addition step as being recommended by CVC’s popular DR-VMM course (http://www.cvcblr.com/trng_profiles/CVC_DR_VMM_profile.pdf).

Step-1: Declaring a facade class with needed tasks/methods

Step-2: Inserting the callback at “strategic” location inside the component (in this case generator)

This leaves only the Steps 3 & 4 for the end user – not bad for a robust solution (especially given that the Step-4 is more of formality of registration). Now that the customer is convinced, it is time to move to coding desk to get it working. She opened up vmm.sv and got trapped in the multitude of `define vmm_atomic_gen_* macros with all those nice looking “ \ “ at the end – thanks to SV’s style of creating macros with arguments. Though powerful, it is not the easiest one to read and decipher – again for a first time SV/VMM user.

Now comes the rescue in terms of well proven DVE – the VCS’s robust GUI front end. Its macro expansion feature that works as cleanly as it can get is at times hard to locate. But with our toolsmiths ready for assistance at CVC, it took hardly a few clicks to reveal the magic behind the `vmm_atomic_gen(icu_xfer). Here is a first look at the atomic gen code inside DVE.

clip_image002

Once the desired text macro is selected, DVE has a “CSM – Context Sensitive Menu” to expand the macro with arguments. It is “Show à Macro”, as seen below in the screenshot.

clip_image004

With a quick bang go on DVE – the Macros expander popped up revealing the nicely expanded, with all class name argument substituted source code for the actual atomic_generator that gets created by the one liner macro. Along with clearly visible were the facade class name and the actual callback task with clear argument list (something that’s not obvious by looking at standard vmm.sv).

clip_image006

Now, what’s more – in DVE, you can bind such “nice feature” to a convenient hot-key if you like (say if you intend to use this feature often). Here is the trick:

Add the following to your $HOME/.synopsys_dve_usersetup.tcl

gui_set_hotkey -menu “Scope->Show->Macro” -hot_key “F6″

Now when you select a macro and type “F6” – the macro expands, no rocket science, but a cool convenient feature indeed!

Voila – learnt 2 things today – the built-in callback inside the vmm_atomic_gen can save more than 50% of coding and can match up to the effort (or the lack of) of using simple chan.peek(). The second one being DVE’s macro expansion feature that makes debugging a real fun!

Kudos to VMM and the ever improving DVE!

Posted in Callbacks, Debug, Reuse, Stimulus Generation, VMM, VMM infrastructure | No Comments »

Viewing VMM log details in waveforms

Posted by Avinash Agrawal on 17th December 2009


Avinash Agrawal, Corporate Applications, Synopsys

Often engineers need a combination of logfile outputs and waveforms, to look at their simulations. And they wonder if it is possible to look at waveforms and get information on the number of simulation errors that might have occurred in a simulation upto any particular point of simulation time.

The good news is that the VMM log service helps a user track the source of different messages to different verification components.

When VMM macros such as `vmm_error, `vmm_note etc are used at different places in the verification environment, the user is able to view the corresponding information in the simulation output. This information includes the time at which the message was logged, the verification component and the specified instance of which the message was issued from. However, it can be very useful if the timing of the errors or warnings in the simulation output can be correlated with waveforms in simulation. For example, if there is a protocol violation message issued from one of the testbench monitors, the user can map the time when the message was issued to the actual signals in the waveform. That way user can quickly uncover the relevant problem in the DUT.

The VMM message service vmm_log consists of the vmm_log_format object to control the format of the messages. The vmm_log_format object also gets the information of the type/severity of the messsages. The vmm_log class for each component uses the default implementation of all these methods. The user can easily extend the vmm_log_format class and add in his modifications. Modifications can be either to trigger an assertion or incrememt a variable which can be dumped into the waveform window. This way, the  engineer can correlate the errors with the change in the variable or an assertion in the waveform window.

The following code shows how this can be done:

module top();
  int error_count;

initial begin
 $vcdpluson();
end

endmodule

program P;

class env_format extends vmm_log_format;  //extending vmm_log_format
                                          // for adding in user modifications
      virtual function string format_msg(string name,
                                         string inst,
                                         string msg_typ,
                                         string severity,
                                         ref string lines[$]);
         if (msg_typ == "FAILURE" && severity == "!ERROR!") begin
            top.error_count++;  //incrementing error count for warnings and errors
         end
//or trigger an assertion which can also be seen in the waveform
        assert (~(msg_typ == "FAILURE" && severity == "!ERROR!"));
          format_msg = super.format_msg(name, inst, msg_typ, severity, lines);
      endfunction
endclass

class xactor extends vmm_xactor;

  int id;

  function new(int id, string instance);
    super.new("xactor", instance);
    this.id = id;
  endfunction

  virtual task main();
    super.main();
    `vmm_note(log, "This is a note message");
    #5;
    `vmm_error(log, "This is an error message");
    if (id == 0)
      #10 `vmm_error(log, "This is an error message");
    else
      #30 `vmm_error(log, "This is an error message");
  endtask
endclass

class env extends vmm_env;
  xactor x1;
  xactor x2;
  vmm_log log;

  function new();
    env_format fmt;
    log = new("env", "class");
    fmt = new();
    log.set_format(fmt);
  endfunction

  virtual function void build();
    super.build();
    x1 = new(0, "x1");
    x2 = new(1, "x2");
  endfunction

  virtual task start();
    super.start();
    x1.start_xactor();
    x2.start_xactor();
  endtask

  virtual task wait_for_end();
    super.wait_for_end();
    #1000;
  endtask

  virtual task stop();
    super.stop();
    x1.stop_xactor();
    x2.stop_xactor();
  endtask

endclass

initial begin
  env e = new;
  e.run();
end

endprogram

Posted in Debug, Messaging | No Comments »

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 »

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 at http://resourceworks.paradigm-works.com/svftg/vmm .

Posted in Debug, Phasing, Reuse, VMM infrastructure | No Comments »

Finding out which vmm callbacks are registered with a particular vmm_xactor instance

Posted by Avinash Agrawal on 13th November 2009

Avinash Agrawal Avinash Agrawal, Corporate Applications, Synopsys

Is it possible to find out which VMM callbacks are registered with a particular vmm_xactor instance?

The answer is yes. Here’s how:

The vmm_xactor base class in VMM instantiates a queue of vmm_xactor_callbacks, callbacks[$]. So, it is possible to use the queue methods to find out details on the callbacks associated with an instance of the vmm_xactor class. To find out the number of callbacks associated with a vmm_xactor instance, we can use the size() function on the callbacks queue. And to list the names of the callbacks associated with the vmm_xactor instance, we can add a new string member (that would carry the name associated with the callback) to the classes derived from vmm_xactor_callbacks, and display this string variable as needed.

Here is an example. Assume that we have extended the vmm_xactor_callbacks class as follows. We also add a string name, that would carry the name associated
with the callback.

class atm_driver_callbacks extends vmm_xactor_callbacks ;
string name;
// Called before a transaction is executed
virtual task pre_trans_t(atm_driver master, atm_cell tr, ref bit drop); endtask
// Called after a transaction has been executed
virtual task post_trans_t(atm_driver master, atm_cell tr);endtask
endclass

The vmm_xactor instance can have a task as follows that displays the callbacks associated with that vmm_xactor instance, as the following example code shows:

task atm_driver::displaycallbacks;
begin
atm_driver_callbacks mycb = new();
$display(“2LOG : number of callbacks is %d\n”, callbacks.size());
$cast(mycb,callbacks[0]);
$display(“2LOG : callback[0] is %s\n”, mycb.name);
$cast(mycb,callbacks[1]);
$display(“2LOG : callback[1] %s\n”, mycb.name);
end
endtask

And, in the build() method of the environment, we have the following code:

//Instantiate the callback objects
atm_sb_callbacks atm_sb_cb = new();
atm_cov_callbacks atm_cov_cb = new();
atm_driver_callbacks mycb = new();
atm_cov_cb.name = “CBNAME1″;
atm_sb_cb.name =”CBNAME2″;

//Register the callbacks to the driver instance drv
this.drv.append_callback(atm_cov_cb);
this.drv.append_callback(atm_sb_cb);
//Call the xactor instance class method that displays the callbacks as follows:
this.drv.displaycallbacks;

This will produce the following output:
LOG : number of callbacks is 2
LOG : callback[0] is CBNAME1
LOG : callback[1] CBNAME2

As seen in the output pasted above, the names and the number of VMM callbacks are registered with the particular vmm_xactor instance, are displayed.

Posted in Callbacks, Debug, Structural Components | No Comments »

SV-AOE: your friendly debug-companion!

Posted by Shankar Hemmady on 9th November 2009

CVC_Ajeetha_KumariCVC_srinivasan_VenkataramanCisco_Ramanathan_S Ajeetha Kumari & Srinivasan Venkataramanan, Contemporary Verification Consultants (CVC),

Ramanathan Sambamurthy, Cisco Systems

As verification specialists, like some of our readers, we thrive on solving challenging problems. Specifically Debug is an area that fascinates us a lot. Here is one of them, using VCS’s Aspect Oriented Extensions (AOE) to SystemVerilog to debug a Memory blow-up in SV-TB code. The problem statement was elaborated in our previous entry: http://www.vmmcentral.org/vmartialarts/?p=385

We brainstormed on potential improvements in order to shorten debug cycles in the future. One option we explored was the use of SIZED mailboxes, when applicable:

function new();

// parameter MBOX_SIZE = 100;

this.out_mbx = new(MBOX_SIZE);

endfunction : new

A better, scalable option is to use a wrapper class around plain SV Mailboxes. That would then allow AOE to aid in debug around the “put”. For instance, consider a simple class-wrapper around a SV Mailbox:

class mbox_c;

mailbox mbox;

function new(string name);

this.name = name;

this mbox = new();

endfunction : new

virtual task put (my_xactn x0);

this.mobx.put(x0);

endtask : put

// Similarly get(), new() etc.

endclass : mbox_c

Now, instead of a plain mailbox, we have a wrapper around it called mbox_c. Assuming that this wrapper was used all across the environment instead of the mailboxes, one can leverage the VCS’s Aspect Oriented Extensions to SystemVerilog to the rescue. In a separate file one can write:

extends chan_dbg(mbox_c);

before task put(my_xactn x0);

$display (“%m AOE: Mailbox %s size is %0d”, this. name,

this.num());

endtask : put

endextends

In contrast to standard OOP, AOE allows “in-place extensions” and hence adds to existing class code without creating hierarchy new class type. This means no factory is needed to swap the base class with a derived class and other associated extra code. Instead, just an additional file with few lines and you are set to go! While some of us may debate whether this is a good coding style for developing reusable environments, for throw away code like debug this is very handy as it requires no intervention to existing code. For instance, with the above code, a typical VCS run (with the dbg.sv code included in command line) produces the following output:

mbox_c::put_before AOE: Channel S2P_BFM_IN_CHANNEL level is 0

mbox_c::put_before AOE: Channel S2P_SER_MON_OUT_CHANNEL level is 0

mbox_c::put_before AOE: Channel S2P_PAR_MON_OUT_CHANNEL level is 1

mbox_c::put_before AOE: Channel S2P_BFM_IN_CHANNEL level is 0

mbox_c::put_before AOE: Channel S2P_SER_MON_OUT_CHANNEL level is 0

mbox_c::put_before AOE: Channel S2P_PAR_MON_OUT_CHANNEL level is 2

mbox_c::put_before AOE: Channel S2P_BFM_IN_CHANNEL level is 0

mbox_c::put_before AOE: Channel S2P_SER_MON_OUT_CHANNEL level is 0

mbox_c::put_before AOE: Channel S2P_PAR_MON_OUT_CHANNEL level is 3

mbox_c::put_before AOE: Channel S2P_BFM_IN_CHANNEL level is 0

mbox_c::put_before AOE: Channel S2P_SER_MON_OUT_CHANNEL level is 0

mbox_c::put_before AOE: Channel S2P_PAR_MON_OUT_CHANNEL level is 4

mbox_c::put_before AOE: Channel S2P_BFM_IN_CHANNEL level is 0

mbox_c::put_before AOE: Channel S2P_SER_MON_OUT_CHANNEL level is 0

mbox_c::put_before AOE: Channel S2P_PAR_MON_OUT_CHANNEL level is 5

mbox_c::put_before AOE: Channel S2P_SER_MON_OUT_CHANNEL level is 0

mbox_c::put_before AOE: Channel S2P_PAR_MON_OUT_CHANNEL level is 6

Of course, there are few safe-guards for such common pit-falls. We address this topic in our VMM adoption book (http://www.systemverilog.us/vmm_adoption) in Chapter-8, Advanced Topics (Section 8.3).

· A vmm_channel (equivalent of a Mailbox in SV) is blocking and has a default size of 1 (can be increased, reconfigured at run time as well)

· It includes built-in debug messages that can be turned on via command line

· It provides a vmm_channel::sink() routine – can be useful if the consumer is not available for integration

· It allows similar AOE debug extension, a code snippet is shown below:

extends chan_dbg(vmm_channel);

before task put(vmm_data obj, int offset = -1,

`VMM_SCENARIO grabber = null);

$display (“%m AOE: Channel %s level is %0d”,

this.log.get_name(),

this.size());

endtask : put

endextends

Posted in Debug | No Comments »