Monday, April 14, 2014

How to organize configuration objects in UVM Testbenches?

Some of the observations about the Complex Verification Environments
   1. Verification Environment will generally have a number of agents (or UVCs).
   2. Testbench will have different modes and configurations at the top level
   3. Agents will have different configurations and randomizations to play with.

Its indeed a laborious task of keeping track of these configurations if not planned and organized properly. There is a need to structure the configurations in an intuitive way so that it not only helps the Verification Team collaborate better but also easy to sustain the Verification Environment.

Following is suggested by UVM user guide:-
1. Each agent should have all the agent level configurations captured in a configuration object (uvm_object)
 2. Environment will have a config object for the environment level or chip level.

                                   Picture Courtesy- Accellera

That sounds pretty straight-forward to understand and implement. However the main aim of the providing configuration objects is to allow the test (or testcase writer) to control/configure the fields in the configuration objects to achieve the test goal or to create various scenarios of interest. This requires some scheme to organize the config objects.

What is the scheme for handling various config objects in the environment?
As we know, Agents' config objects are generally in compliation scope of that particular agent as follows:-


                                                  Fig2. abc_pkg



In order to keep the configuration objects organized in a structured way, and still allow the test writer to intuitively use the config objects, following scheme is devised. The scheme is illustrated using the following piece of code.
      Fig3. Illustration of scheme for handling config objects in UVM testbench

Also, the env_config is instantiated in the test, test writer can access the env_config and agent level configs hierarchically to control the configurations of testbench.

What are the Advantages?
  1.  Easy and intuitive way of accessing configurations information not only for Test writers but also design engineers/managers to review the configurations. Review of configuration capabilities of the testbench is very important because this drives the verification and its goals
  2. Environment config contains only the pointers to the agent level configs and actual config object of a given agent resides within the compilation scope of that agent. Thus, Agent are kept pretty independent and they don't access environment level config object and hence agent can be reused across different environment with almost no change required.
  3. Tests access the agent level config through environment level config object and hence all the configurations done in the testcase are streamlined and this makes the testcases easy to understand.

Thursday, February 28, 2013

Clock Generation with jitter

System Verilog Code:-

//---------------------------------------------------------------------------------------
// Name: jitter_clock_gen
// Author: Bharath Kumar Y
// Description: This module will generate a clock with
//              period                = 16ps
//              Max Skew/half clock   = +/-1ps
//              Max Skew/clock period = +/-2ps
// Copyright (C) Bharath Kumar Y
//----------------------------------------------------------------------------------------

`timescale 1ps/1ps

module jitter_clock_gen;
//Initializations
  bit req0=0;
  bit clk=0;
  integer seed;
  real zero_time=0;
  real one_time=8;


// Just to run the sim for some good amount of time to get
// enough clock edges
initial begin
  # 100 $finish;
end

// Actual clock generation clock
always
  #(8+$dist_uniform(seed,-1,1)) clk = ~clk;

// Checking of clock geneation implemented using
// Immediate assertions
// This block will assert errors when the
// half clock period != 8
always @* 
begin
  if(clk==0) begin
    req0=1;
    zero_time = $realtime;
    $display("zero_time = %t",$realtime);
    assert(!(($realtime<(one_time+8))));
    assert(!(($realtime>(one_time+8))));
  end

  if (req0==1 && clk==1) begin
    req0=0;
    one_time=$realtime;
    $display("time:%t:-req0=%b,req=%b",$realtime,req0,clk);
    assert(!(($realtime<(zero_time+8))));
    assert(!(($realtime>(zero_time+8))));
  end
end

endmodule


Output for the same code using ncsim:-

ncsim> run
zero_time =                   15
ncsim: *E,ASRTST (./fun1.sv,41): (time 15 PS) Assertion jitter_clock_gen.__assert_1 has failed
time:                  22:-req0=0,req=1
ncsim: *E,ASRTST (./fun1.sv,49): (time 22 PS) Assertion jitter_clock_gen.__assert_3 has failed
zero_time =                   29
ncsim: *E,ASRTST (./fun1.sv,41): (time 29 PS) Assertion jitter_clock_gen.__assert_1 has failed
time:                  37:-req0=0,req=1
zero_time =                   46
ncsim: *E,ASRTST (./fun1.sv,42): (time 46 PS) Assertion jitter_clock_gen.__assert_2 has failed
time:                  53:-req0=0,req=1
ncsim: *E,ASRTST (./fun1.sv,49): (time 53 PS) Assertion jitter_clock_gen.__assert_3 has failed
zero_time =                   60
ncsim: *E,ASRTST (./fun1.sv,41): (time 60 PS) Assertion jitter_clock_gen.__assert_1 has failed
time:                  68:-req0=0,req=1
zero_time =                   76
time:                  85:-req0=0,req=1
ncsim: *E,ASRTST (./fun1.sv,50): (time 85 PS) Assertion jitter_clock_gen.__assert_4 has failed
zero_time =                   93
Simulation complete via $finish(1) at time 100 PS + 0
./fun1.sv:26   # 100 $finish;

Wednesday, February 27, 2013

UVM Ports - Illustrated

There is always this question as to when to use uvm_analysis_port, uvm_analysis_export and uvm_analysis_import

The below diagram illustrates the correct use of all types of ports mentioned above through the 'Stacked UVCs' example.  This diagram illustrates the connection of BOTTOM UVC's monitors with the monitors of TOP UVCs. 

The requirement here is that any of the BOTTOM UVCs can be connected to any of the TOP UVCs. This means that we need to have a router component with uvm_analysis_exports since only exports can forward the data coming from the source 'port's of BOTTOM UVC's monitors. BOTTOM UVC's Monitor is the originator of the transacation and hence its required to have the uvm_analysis_port.

Monitors of the TOP UVCs are supposed to have the uvm_analysis_imports as they are the ultimate consumers of the transactions

Monday, February 11, 2013

UVM Questions - 6

                                               Courtesy - Paradigm Works Inc

 Q:  Why there should be a seperate sequencer and driver in an UVM agent?
                                              OR
 Q:  Why UVM doesn't have single component which combines Driver and Sequencer?


Firstly,
     Typically if you are dealing with a packet/frame with layered architecture where lower layer level data encapsulate the higher layer level data. In this case its better to architect the UVC in a layered way.  This renders the testbench modular and facilitates the easy reusability and parallel development of Testbench.
    Once we do the layered architecture of UVCs, only Bottom UVCs need to have Driver since its attached to the DUT interface, higher leayer UVCs don't need to have driver since they don't attach to any DUT interface instead they attach to the bottom UVCs. Higher layer sequences in the sequencer interact with to the lower level UVCs through sequence item as shown in the above diagram.

Secondly,
     At the SoC level verification environment, its often required to use the virutal sequences to sequence/bypass the lower level sequences
                                   Courtesy - Accellera UVM1.1 User guide

As per the guide,

     There are three ways in which the virtual sequencer can interact with its  subsequencers:
a) “Business as usual”—Virtual subsequencers and subsequencers send transactions simultaneously.
b) Disable subsequencers—Virtual sequencer is the only one driving.
c) Using grab() and ungrab()—Virtual sequencer takes control of the underlying driver(s) for a limited time


(b) and (c) makes the separation of sequencer and driver obvious and hence they are independent components in UVM. Without this seperation, its difficult for virtual sequencer to grab the control of the underlying drivers and achieve interesting scenarios at the SoC/full chip level testbench.

Wednesday, December 12, 2012

UVM Questions - 5

Q. In the accellera's UVM User guide, there are two monitors shown one at the agent level and another at the environment level, why ?
                                     Picture Courtesy- Accellera


A: There are variety of reasons why you need Monitor at different levels

    Any agent monitor also has a collector inside which collects only that data from DUT interfaces and forms a transaction which is destined to that particular agent.  As shown in the above diagram, Monitor will also have a UVM analysis ports to pass the transaction to other components in the environment like Scoreboard.

   However, the Monitor at the environment level (called as 'bus monitor' here) also snoops the DUT interface and forms the transactions destined to any master/slave agent on the bus but it won't pass the transactions to other components of the environment like scoreboard. This bus-level monitor uses those transactions to perform checking and coverage for the activities that are not necessarily related to a single agent.

Bus monitor is very useful for debugging at the SOC top level testbench environment where both source and destination of data flow (transactions) are within DUT itself. 

UVM Questions - 4

Q: What is the difference between uvm_component and uvm_object?
                       OR
Q: We already have uvm_object, why do we need uvm_component which is actually derived class of uvm_object?


A: uvm_component is a static entity and always tied(bind) to a given hardware and/or a TLM interface
 
   uvm_object is a dynamic entity and is not tied to any hardware/TLM interface

   uvm_component like uvm_driver is always connected to a particular DUT interface because throughout the simulation its job is fixed i.e. to drive the designated signals into DUT

   uvm_object like uvm_transaction is not connected to any particular DUT interface and its fields can take any random value based on randomization constraints.
 
   Though uvm_component is derived from uvm_object, uvm_component has got these additional interfaces

       * Hierarchy provides methods for searching and traversing the component hierarchy.
       * Phasing defines a phased test flow that all components follow, with a group of standard phase methods and an API for custom phases and multiple independent phasing domains to mirror DUT behavior e.g. power
       * Configuration provides methods for configuring component topology and other parameters ahead of and during component construction.
       * Reporting provides a convenience interface to the uvm_report_handler.  All messages, warnings, and errors are processed through this interface.
       * Transaction recording provides methods for recording the transactions produced or consumed by the component to a transaction database (vendor specific).
        * Factory provides a convenience interface to the uvm_factory. The factory is used to create new components and other objects based on type-wide and instance-specific configuration

Acronyms used:-
DUT - Design Under Test
TLM - Transaction Level Modelling
API - Application Programming Intefaces

Friday, December 7, 2012

UVM Questions - 3

Q. What is the advantage of using type_id::create() over new() while creating objects ?

There is nothing wrong in creating the objects for any uvm_component with constructor function new(), however if you are using UVM, there are some advantages of using factory way of creating objects i.e using

classname ::type_id::create("object name", parent)

This is what UVM1.1 Class Reference says

"Using the factory instead of allocating them directly (via new) allows different objects to be substituted for the original without modifying the requesting class"


Q: How to implement polymorphism in UVM?

The above advantage is illustrated through the polymorphism of a 'generic monitor' as follows:-

Any generic Monitor component's implementation will be

   class xyz_monitor extends uvm_monitor ;

      task run_phase ;
         // Implements monitor functionality here
      endtask
   endclass

Monitor has following modes of operation apart from basic xyz_monitor mode
     1. Mode1
     2. Mode2

   class monitor_mode1 extends xyz_monitor;
     // Implement monitor mode1
   endclass

   class monitor_mode2 extends xyz_monitor;
     // Implement monitor mode2
   endclass

    class parent extends uvm_env;
         .....
         ....
         xyz_monitor mon;
        mon = xyz_monitor::type_id::create("mon",this);
    endclass

Now during compilation you can specify which mode of the monitor you need for a particular simulation run using

    +uvm_set_type_override=<\req_type\>, <\overrid_type\>[,<\replace\>]

which work like the name based overrides in the factory--factory.set_type_override_by_name()

For the above example, If we need mode1 of monitor then the command line will be
    +uvm_set_type_override=xyz_monitor,monitor_mode1

For mode2, it would be
    +uvm_set_type_override=xyz_monitor,monitor_mode2

Effectively, there were no exclusive objects created for monitor mode1 or mode2, it basically override the object created for the object 'mon' which was originally of type 'xyz_monitor' and this is called Polymorphism because 'mon' object can potentially be any one of these types i.e. xyz_monitor or monitor_mode1 or monitor_mode2 for a given simulation run.

In fact, for the same monitor example if we have two instances(or objects) of xyz_monitor in your environment

    class parent extends uvm_env;
         .....
         ....
         xyz_monitor mon;
         xyz_monitor mon_extra;
        mon           = xyz_monitor::type_id::create("mon",this);
        mon_extra = xyz_monitor::type_id::create("mon",this);
    endclass

Now during compilation(command line) you can specify which modes of the monitor you need for a particular simulation run using
 +uvm_set_inst_override=<\req_type\>,<\overrid_type\>,<\full_inst_path\>

We can override 'mon' object to be of type monitor_mode1 using
 +uvm_set_inst_override=xyz_monitor,monitor_mode1,uvm_test_top.env.mon

We can override 'mon_extra' object to be of type monitor_mode2 using
 +uvm_set_inst_override=xyz_monitor,monitor_mode2,uvm_test_top.env.mon_extra

Please note that for 'uvm_set_inst_overrride', you need extra argument which is the path of 'object' and it has to start from uvm_test_top

Thursday, December 6, 2012

UVM Questions -2

Q. How to Create a scoreboard with add_item() , check_item() functions using UVM ?
A:  You need to first declare a class for the Scoreboard

    class scoreboard extends uvm_scoreboard;

Now you actually need two TLM ports one for the add_item() and another for check_item(). however UVM by default allows only one port per UVM 'component'. In order to have more ports you have to tell the factory in the following way, outside the class declaration.

UVM allows more than one imp ports to be declared which will not affect source of the analysis ports. Declaring two Analysis imp ports; one for the expected transaction and another for actual transaction

// In ocp imp port for the expected transaction (add_item())
`uvm_analysis_imp_decl(_add_item)

// Out ocp imp port for the actual transaction( check_item())
`uvm_analysis_imp_decl(_check_item)


Now you delcare these UVM analysis ports with the above extesions respectively.

   // Internally SCBD_ADD looks for the write_add_item() function
   uvm_analysis_imp_add_item#(transaction, scoreboard) SCBD_ADD;
   // Internally SCBD_CHECK looks for the write_check_item() function
   uvm_analysis_imp_check_item#(transaction, scoreboard) SCBD_CHECK;


where transaction is a 'uvm_transaction' and scoreboard is 'uvm_scoreboard'.

Now,  you need to create seperate constructors for the above imp ports

   function new(string name, uvm_component parent = null);  
       super.new(name, parent);
       SCBD_ADD  = new("SCBD_ADD", this);
       SCBD_CHECK = new("SCBD_CHECK",this);
   endfunction

 In order to implement the 'write()' functions of the producer of transaction i.e Monitor, we need the following functions in the scoreboard which is the consumer of the 'transaction'

   function void write_add_item( transaction t1);
       // Implement adding of the items to scoreoboard here
   endfunction

   function void write_check_item( transaction t2);

      // Implement checking of items against the expected
      // remove the expected item if match PASSES otherwise
      // fire an error
   endfunction

In reality,  UVM analysis port SCBD_ADD would get connected to the Monitor on 'Generator' which is giving expected data and SCBD_CHECK would get connected to the Collector which is providing actual data.

Tuesday, November 27, 2012

UVM Questions -1

Q. Why the heck there are so many UVM Run time phases ? I want to have freedom to write the test in my own way without the hassle of these phases. Why can't I?

A: No, that's UVM for you. UVM expects the Verification Engineer to be much more organised in the way tests are written. Imagine verification team of five to six verification engineers, all writing tests in their own way, they might be able to verify the DUT to good extent, but there won't be any standard *flow* in those tests and it will be highly time consuming for someone to understand/modify/maintain the tests written by someone else in the team. That's why UVM is prescribing the following predefined RUN phases which suites most of the verification environments:-


From Accellera's Universal Verification Methodology (UVM) 1.1 Class Reference:-

UVM Run-Time Phases  
The run-time schedule is the pre-defined phase
schedule which runs concurrently to the

uvm_run_phase global run phase.

uvm_pre_reset_phase Before reset is asserted.

uvm_reset_phase Reset is asserted.

uvm_post_reset_phase After reset is de-asserted.

uvm_pre_configure_phase Before the DUT is configured by the SW.

uvm_configure_phase The SW configures the DUT.

uvm_post_configure_phase After the SW has configured the DUT.

uvm_pre_main_phase Before the primary test stimulus starts.

uvm_main_phase Primary test stimulus.

uvm_post_main_phase After enough of the primary test stimulus.

uvm_pre_shutdown_phase Before things settle down.

uvm_shutdown_phase Letting things settle down.

uvm_post_shutdown_phase After things have settled down.

This way , irrespective who writes the test, one has to organise his tests using these phases. Effectively UVM enforces this 'test writing descipline' for the common benefit of the team of verification engineers which is also productive indeed.

Of course, one has to understand that you are not limited to/by above mentioned phases. One can always come up with new run_phase and add it this phase sequence for which UVM already has the support.

Bottomline is UVM is not curtailing the 'creative thinking' in writing testcases by verification engineer, rather its demanding you to be 'organised', that's it.

 

Tuesday, November 20, 2012

Top 12 Questions on Testbench

Verification Engineer can ask these general questions about the Verification Infrastructure or popularly known as Test-bench either at the beginning of the project or at the end of the project as check.

1. Is Verification infrastructure are nicely broken down into logical, appropriate Test-bench components to enable parallel development of those components ?

2. Have I understood the Requirement Specifications or Design specifications to the extent to by which I can handle ambiguity and take independent decisions during debug ?

3. Do I have the reasonable amount of practical knowledge of the off-the-shelf VIPs, if any used ?

4. If the Test-bench is inherited from the previous project, Is the due-diligence done on the various aspects of the Test-bench considering the current design? Have I identified the list of modifications to existing Test-bench?

5. Do I have the list of sanity test-cases which target the minimal set of design functionality?

6. Do I have a plan where I execute test-cases (or verification plan) systematically in the order of increasing complexity?

7. What is the strategy to connect the various Test-bench components and their unit of interaction. Has this been figured out?

8. Is the running of Test-cases 'push button' or single command-line?

9. Is the Verification infrastructure good enough to handle the Corner cases ? Consider interesting and overlapping of design features in a single scenario.

10. Have I investigated the possibility of replacing the Test-bench checkers with assertions in RTL?

11. Is my test-bench robust enough, means once all the regression PASSES, suppose a fault is introduced into the RTL, can the test-bench really catch this ?

12. What is the strategy on Functional Coverage ? It depends on the kind of design under test(DUT).         
              * If the design has predominantly 'data-path' kind of functionality, its generally sufficient just to cover the stimulus (means various fields of generated items)
              * If the design has predominantly 'control-path' kind of functionality, its required to cover for both stimulus and manifestation in an intelligent way

Monday, March 19, 2012

Templates in e

Haven't you still used templates to create your Testbench infrastructure or Framework? I would suggest start using it.

I thought of writing a small blog on Templates and then found this article at Cadence's specman website, which is quite good in explaining the basics of Template and how it is better than Macros in terms of the ease of creation and usage.

There is also another good article which illustrates the power of templates using the Generic Scoreboard as example. I say 'generic' because the basic code for Scoreboard doesn't need to have the what transaction type scoreboard will act on. 'Transaction type' is added when you are 'extend'ing the scoreboard in your individual testbenches. This is great way to build your Testbench framework which in turn can be used to build the individual testbenches.

Thursday, March 15, 2012

Macros in Vi:-


Macros in VI editor are very handy when it comes to quick modifications to a givenin a repititive fashion. Imagine you have a file which has a word "Loading" at the begining of every line in your fileand you want to move this word "Loading" to the end of each line in the file.
Then you can use 'map' command to create macros to get this done quick/smart way.In the VI command line just use


: map z /Loading^M^[yw$^[p


The above macro searches for "Loading" and then copies that word(yw) and goes to end of the line ($) and paste the word there using 'p' command and once the macro 'z' is created you can simply use this as a command in normal mode of the VI and each 'z' command will do this for a line.
To carry out this repetitively for n number of lines another macro called "rep' can be created


:map rep zzzzzzzzzzzzzzzzzzz



To execute macro for only the 'n'th line


: map ten 10z


More VI tricks next time...until then enjoy this VI trick

Saturday, March 3, 2012

Design Engineer, Verification Engineer and the Gap

Its often said that there is generally a 'gap' between Design Engineer(DE) and Verification Engineer(VE). Initially I always thought that Verification Engineer's knowledge about the design is limited and that's what is called as 'gap'. However, later I came to know that this gap is not all that bad and could have be both positive as well as negative shades.

By positive, I mean that VE can have his doubts about the design implementation or in some cases design(w.r.t Specification) itself and hence he won't be under the influence of the DE. This could really work out in favour of VE in most cases. Just to support my viewpoint, other day when I was talking to a DE, he told me that there is a *new* VE in his team who is able to find good number of bugs to his surprise and he also said this was possible because that VE doesnt know much about the protocol or design and he is able to hit the cases which were thought as invalid or illegal(though they are not). This new VE unknowingly brought the paradigm shift in the way verification was done.
The ability to question the 'status-quo' in this case is quite predominant because the new VE is not biased by the Designer's viewpoint or perspective.

This 'gap' also has negative shades since this curtails the VE's decision making progress in the course of verificaiton especially during debug. Generally VE starts on a 'debug journey' whenever a Testbench reports error; once its confirmed that its not a TB issue, then VE's thought/debug processes branches out in multiple directions and in the process he ends up making a decisions based on his previous experience or knowledge about the design. The path he takes could lead him to a bug or nowhere depending on how good the decission is. In order to make a good decision, depth of understanding of RTL/design will help in a big way. However, the real quality/ingenuity of the VE will be tested and how much unbiased/independentness he shows in making that decision will decide the fate of debug.
Generally in these cases, I have observed that VE being 'tenacious' can make a huge difference at the end. VE can be easily overriden by hugely experienced DEs( not necessarily good DEs) and this is where Management's role come into picture. If the issues is such that its neither concluded a design bug nor an issue which can be ignored, then management should always back the VE and ask DE to help out in debug till its root-caused.

Asking right questions to DE could be one of the ways through which VE can gain confidence. Some of the questions could be like these:-

1. I found this in specifications/standard and I see that this is not taken care ..what's your take on this?
2. I found that one block(A) in the design supports this functionality whereas same functionality is broken in other block(B). How can this be?
3. I happen to hit upon a illegal case but I didn't find in the documentation that after this illegal condition what is the intended behaviour by design ?
4. This implementaiton is well within what is specified by standards, However, I see that its not inline with the design intent based on design documentation. Is this correct?

This list can be really long and I am deciding to stop here. In my next blog, I would like to share what kind of questions a VE can ask himself ( about the Verificaiton Infrastructure).

Wednesday, December 7, 2011

When should you use a 'struct' and when 'unit' in Specman?

This is the question that I have asked most people in interview (including the engineers who claimed to know about specman). I didnt get satisfactory answer.

If I have to give analogy of a computer, think of 'unit' like a hardware and 'struct' like a software. Unit has to be tied to a physical entity and solely dedicated to that physical entity (like a port) . For example, you will unit to code your BFMs and Collectors. However any item say a 'packet' or 'frame' which you need to generate has to be 'struct'.

'Struct' isn't tied to any physical entity. any component can use the struct. For example, same packet 'struct' is used by many Port (BFMs and Collctors) to process/send/receive the packet or frame.

Lot of people give reasons like they will use 'unit' because they need 'tcm'( or notion of time). However this is only secondary reason behind using unit. Primary reason for using 'unit' should be whether the functionality which you want to implement is tied to physical entity or not.

Monday, December 22, 2008

Beware of conditional constraints!!

I was impressed by conditional(implied) constraining of specman unit's fields. But that impression didn't last longer. It costed me ONE day and night to realise and convince myself about the issues with implied constraints.



C:\Documents and Settings\bkumar1\Untitled.html





1 unit xyz_u {
2
3 field_A: uint;
4 keep soft field_A in [1..4];
5
6 field_B: uint;
7 // ************* COMMENTS ***********************
8 // I wanted here fieldB to have 1 when fieldA =1;
9 // fieldB = fieldA/2 if fieldA != 1
10 // you know what, it yielded me results
11 // when filed_A = 4 it gave me field_B = 1
12 // that is becuase when field_A !=1,
13 // this could be becuase the constraining can
14 // happen both the ways RHS to LHS and vice-versa
15 // and also specman never assures that it will
16 // satisfy both the below conditions. Specman
17 // only **tries** to generate the value which
18 // satisfy below equations.
19 // It may not satisfy always.
20 keep field_A == 1 => field_B == 1;
21 // since this is implied constr. you can't use 'soft'
22 keep filed_A != 1 => field_B == field_A/2;
23 // this is very very dangerous
24 };
25





* what is the Real problem?
Specman doesn't give any hint or information as how it has generated and what conditions(equations) are really satisfied. It keeps the user in *dark* and doesnt really help the user to debug in anyway.

* what is the way out?
1. Look out for ways to avoid the conditional constraints.
2. Try to avoid negative way of implied constraining ( !=), it opens up the space for specman to play with the conditions.
3. Suppose if you can't get rid of the implied constraints. Try to break it up( I am not sure whether it works out well!!!)

Saturday, October 18, 2008

My experiences with HVL

As today's seminconductor designs are becoming complicated. Complexity in verification of those designs are multiplying. so engineers envisaged High level Verification Languages(HVLs) to attack this problem. HVLs provide modularity, re-usability and extensibility and some of those even provide (aspect-orientedness) to verification infrastructure or commonly known as 'Testbench'. Now verification managers/engineers have variety of HVLs to choose from which is actually tough task because it has to be very custom and very much dependent on nature of design and verification requirements. I will stop here on this topic and I will try to list down the my experiences (which are actually features of HVLs) with specman in particular and HVLs in general.

* Specman basics are easy to pickup for those who are exposed to any kind of Programming Languages but user has to acquainted with this 'thread' business a lot. Basically handling of threads.
* When switched from Verilog based testbenches to Specman based testbenches you kind of feel that you are hands are getting tied because specman demands you to be lot of more disciplined in organising your code.
* Specman (or HVLs) provide this 'extensibility' which provides lot of flexibility to verification engineers. Verificaiton infrastructure can be expanded/upgraded/degraded very easily because of this.
* Sequences is another powerful construct provided in specman which gives user to create 'unthinkable' scenarios and helps to get to the 'coverage goal' far more quickly than otherwise.
* Another important thing is that we can actually build some kind of inter-communicating infrastructure of specman agents to streamline the functioning of the various verification components. Like inheritance is very affective in creating agents which has common baseline.

coming to limitations of specman tool
* memory management or popularly known as 'garbage collection' . Lot of times tool crashes becuase of this screwups in garbage collection for right and wrong reasons. I say wrong reasons here because the way the test/testbench is written also will sometimes create garbage collection issues.

I will write more on this in my coming blogs. stay tuned