Verification Martial Arts: A Verification Methodology Blog

Archive for the 'VMM 1.2' Category

The right name at the right space: using ‘namespace’ in VMM to set virtual interfaces

Posted by Amit Sharma on 7th September 2011

Abhisek Verma, CAE, Synopsys

A ‘namespace’ is an abstract container or environment created to hold a logical grouping of unique identifiers or names. Thus the same identifier can be independently defined in multiple namespaces and the the meaning associated with an identifier defined in one namespace may or may not have the same meaning as the same identifier defined in another namespace. ‘Namespace’ in VMM is used to group or tag different VMM objects, resources and transactions with a meaningful namespace for the different components across the testbench environment. This allows the user to identify them and access them efficiently. For example, a benefit of this approach is that it relieves the user from making cross module references to access the various resources. This can be seen in the context of accessing the interfaces associated with a driver or a monitor in the environment and goes a long way in making the code more scalable.

Accessing and assigning interface handles to a particular transactor can be done in various ways in VMM, as discussed in the following blogs: Transactors and Virtual Interface and Extending Hierarchical Options in VMM to work with all data types. In addition to these, one can leverage ‘namespaces’ in VMM to achieve this fairly elegantly. The idea here is to put the Virtual Interface instances in the appropriate namespace in the object hierarchy to be retrieved by the verification environment wherever required through simple APIs as shown in the following steps:

STEP 1:: Define a parameterized class extending form vmm_object to act as a wrapper for the interface handle.

STEP 2:: Instantiate the interface wrapper in the top-level MODULE and put in the “VIF” name space

STEP 3:: In environment, access interface wrapper from the VIF name space by querying for the same in the ‘VIF” namespace and use the retrieved handle to set the interface in the transactor

The example below demonstrates the implementation of the above

The Interface and DUT templates..

image

Step1: Parameterized wrapper class for the interface-

image

The Testbench Top:

image

The Program Block:

image

Posted in Configuration, Structural Components, VMM 1.2, VMM infrastructure | No Comments »

Extending Hierarchical Options in VMM to work with all data types

Posted by Amit Sharma on 2nd September 2011

Abhisek Verma, CAE, Synopsys

Tyler Bennet, Senior Application Consultant, Synopsys

Traditionally, to pass a custom data type like a struct or a virtual interface using vmm_opts, it is recommended to wrap it in a class and then use the set/get_obj/get_object_obj on the same. This approach has been explained in another blog here.  But wouldn’t you prefer to have the same usage for these data types as the simple use model you have for integers, strings and objects?  This blog describes how to create a simple helper package around vmm_opts that uses parameterization to pass user-defined types. It will work with any user-defined type that can be assigned with a simple “=”, including virtual interfaces.

Such a package can be created as follows:-

STEP1:: Create the parameterized wrapper class inside the package

image

The above vmm_opts_p class is used to encapsulate any custom data type which it takes as a parameter “t”.

STEP2:: Define the ‘get’ methods inside the package.

Analogous to vmm_opts::get_obj()/get_object_obj(), we define get_type and get_object_type. These static functions allow the user to get an option of a non-standard type. The only restriction is that the datatype must work with the assignment operator. Also note that since this uses vmm_opts::get_obj, these options cannot be set via the command-line or options file.

image

STEP3:: Define the ‘set’ methods inside the package.

Similarly, analogous to vmm_opts::set_object(), the custom package needs to declare set_type. This static function allows the user to set an option of a non-standard type. .

image

USE-MODEL

The above package can be imported and used to set/get virtual interfaces as follows :-

vmm_opts_p#(virtual dut_if)::set_type(“@BAR”, top.intf, null); //to set the virtual interface of type dut_if

tb_intf = vmm_opts_p#(virtual dut_if)::get_object_type(is_set, this, “BAR”, null, “SET testbench interface”, 0); //to get the virtual interface of type dut_if, set by the above operation.

The following template example shows the usage of the package in complete detail in the context of passing virtual interfaces

1. Define the interface, Your DUT

image

2. Instantiate the DUT, Interface and make the connections

image

3.  Leverage the Hierarchical options and the package in your Testbench

image

So, there you go.. Now , whether you are using your own user defined types, structs, queues , you can go ahead and use this package and thus have your TB components communicate and pass data structures  elegantly and efficiently..

Posted in Communication, Configuration, Customization, Organization, VMM 1.2 | No Comments »

Building & Configuring Coverage Model – VMM Style – Part-III

Posted by paragg on 25th June 2011

Parag Goel, Senior Corporate Application Engineer, Synopsys

In the final blog of this coverage modeling with VMM series, we focus on error coverage. Negative scenario testing is an integral part of verification. But again, we have this question – Whether I have covered all negative scenarios?

So it is important to ensure that the generic coverage model tracks all the error scenarios.

Let’s see, how a specific mechanism provided in VMM in the form of vmm_report_catcher helps to track error coverage efficiently and effectively. The VMM Log Catcher is able to identify/catch a specific string of any type any of the messages issue through the VMM reporting mechanism.

Typically, the Verification Environment issues messages to STDOUT when the DUT responds to an error scenario. These messages can be ‘caught’ by the Log Catcher to update the appropriate coverage groups. Let see how this is done in detail.

The Verification Environment would respond to each negative scenario by issuing a message with a unique text, specific to specific error messages.

In the context of the AXI in framework, we can introduce a wide-range of error scenarios and test if the DUT responds correctly or not. A few possible error scenarios in AXI are listed below for your reference.

clip_image001

However, all the scenarios may not be applicable always and hence configurability is required to enable only the required set of coverpoints tied to the relevant negative scenarios. Thus, we should have similar configurability for error coverage as I talked about in the earlier blogs.

Let’s see how we can catch the relevant responses and sample the appropriate covergroups.

As mentioned earlier, in the example below, we make use of the unique message issued as a result of a negative scenario.

This is how we use the VMM Log catcher.

1. The error coverage class is extended from vmm_log_catcher – VMM base class.

2. The vmm_log::caught() API is utilized as means to qualify the covergroup sampling.

clip_image001[11]

In the code above, whenever a message with the text “AXI_WRITE_RESPONSE_SLVERR “ is issued from anywhere in the verification environment, the ‘caught’ method is invoked which in turn samples the appropriate covergroup. Additionally, you an specify more parameters in the caught API, to restrict what ‘scenarios’ should be caught.

vmm_log_catcher::caught(

string name = “”,

string inst = “”,

bit recurse = 0,

int typs = ALL_TYPS,

int severity = ALL_SEVS,

string text = “”);

The above API, installs the specified message handler to catch any message of the specified type and severity, issued by the specified message service interface instances specified by name and instance arguments, which contains the specified text. By default, this method catches all messages issued by this message service interface instance.

Hope these set of articles would be relevant and useful to you.. I have made an attempt to leverage some of the built-in capabilities of the SV languages and the VMM base classes to target some of the challenges in creating configurable coverage models.. These techniques can be improvised further to make them more efficient and scalable. I would be waiting to hear from you all any inputs that you, have in this area.

Posted in Automation, Configuration, Coverage, Metrics, Reuse, Structural Components, Uncategorized, VMM, VMM 1.2, VMM infrastructure | No Comments »

Building & Configuring Coverage Model – VMM Style – Part-II

Posted by paragg on 25th June 2011

Parag Goel, Senior Corporate Application Engineer, Synopsys

In the previous post, we looked at how you can enable/disable different types of coverage encapsulated in the Coverage Model wrapper class. In this post, let’s look at how we can easily create an infrastructure to pass different inputs to the wrapper class so as to able to configure the coverage collection based on user. The infrastructure ensure that these elements values percolate down to the to the sub-coverage model groups.

The following are some of the key inputs that needs to be passed to the difference coverage component classes

1. SV Virtual Interfaces so that different signal activity can be accessed

2. The Transactions observed and collected by the physical level monitors

3. The ‘Configuration’ information

Picture7

Let’s look at how the we can easily pass the signal level information to the Coverage Model

Step I: Encapsulation of the interface in the class wrapper.

class intf_wrapper extends vmm_object;

virtual axi_if v_if ;

function new (string name, virtual axi_if mst_if);
super.new(null, name);
this.v_if = mst_if;
endfunction

endclass: master_port

Step II: In the top class/environment- Set this object using vmm_opts API.

class axi_env extends vmm_env;
`vmm_typename(axi_env)
intf_wrapper mc_intf;

function void build_ph();
mc_intf = new(“Master_Port”, tb_top.master_if_p0);
// Set the master port interface
vmm_opts::set_object(“VIP_MSTR:vip_mstr_port“, mc_intf, env);
endfunction:build_ph
endclass: axi_env

Step III: Connecting in the coverage class.

A. Get the object containing interface in the coverage model class using vmm_opts.

assert($cast(this.mst_port_obj, vmm_opts::get_object_obj(is_set, this, “vip_mstr_port“)));

B. Connecting local virtual interface to one contained in the object.

this.cov_vif = mstr_port_obj.v_if;

Now, we need to pass the collected transaction object from the monitor needs to the coverage collector. This can be conveniently done in VMM using TLM communication. This is achieved through the vmm_tlm_analysis_port, which establishes the communication between a subscriber & an observer.

class axi_transfer extends vmm_data;

. . .

class axi_bus_monitor  extends  vmm_xactor;

vmm_tlm_analysis_port#(axi_bus_monitor, axi_transfer)  m_ap;
task collect_trans();

//Writing to the analysis port.

m_ap.write(trans);
endtask
endclass

class axi_coverage_model extends vmm_object;
vmm_tlm_analysis_export #( axi_coverage_model, axi_transfer) m_export;

function new (string inst, vmm_object parent = null);
m_export = new(this, “m_export”);

endfunction

function void write(int id, axi_transfer trans);

//Sample the appropriate covergroup, once the transaction is received

in the write function.

endfunction

endclass

To set up the TLM Connections in the agent/environment, we need to do the following:

class axi_subenv extends vmm_group;

//Instantiate the model classes and creates them.

axi_bus_monitor mon;

axi_coverage_model cov;

. . .

virtual function void build_ph;
mon = new( “mon”, this);
cov = new( “cov”, this);
endfunction
virtual function void connect_ph;

//Bind the TLM ports via VMM – tlm_bind

monitor.m_ap.tlm_bind( cov.m_export );

endfunction

To make the Coverage Model truly configurable, we need to look at some of the other key requirements as well at different level of granularity. This can be summarized as the ability to do the following.

1. Enable/Disable coverage collection for each covergroup defined . Every covergroup should be created only if a user wishes to do so. So there should be a configuration parameter which restricts the creation of the covergroup altogether. And this should also be used to control the sampling of a covergroup.

2. The user must be able to configure the limits on the individual values being covered in the coverage model within a legal set of values. Say for example, transaction field BurstLength – user should be able to guide the model what are the limits on this field that one wishes to get coverage on within a legal set of values ranging from ‘1’ to ‘16’ as per AXI spec. So providing lower and upper limits for transaction parameters like burst size, burst length, address etc. makes it re-usable. This limits should be modeled as variables which can be overwritten dynamically

3. The user should be able to control the number of bins to be created. For example in fields like address. auto_bin_max option can be exploited to achieve this in case the user doesn’t have explicitly defined bins..

4. The user must be able to control the number of hits for which a bin can be considered as covered. option.atleast can be used for this purpose and the input to this can be a user defined parameter.

5. The user should also have the control to specify his coverage goal, i.e. when the coverage collector should show the covergroupcovered” even though the coverage is not 100%. This can be achieved by using option.goal, where goal is again a user defined parameter.

All the parameters required to meet the above requirements can be encapsulated in the class (i.e. coverage configuration class) and this can be set and retrieved in a similar fashion described for setting & getting the interface wrapper class using vmm_opts API’s.

class coverage_cfg extends vmm_object;
  int disable_wr_burst_len;
   . . .
  function new( vmm_object parent=null, string name);
     super.new(parent, name);
  endfunction
  coverage_cfg cfg;
  function new(vmm_object parent=null, string name);
     bit is_set;
     super.new(parent, name);
     $cast(cfg, vmm_opts::get_object_obj(is_set, this,
                                           "COV_CFG_OBJ”));
  endfunction

Wei Hua presents another cool mechanism of collecting this parameters using vmm_notification mechanism in this earlier blog  :

A Generic Functional Coverage Solution Based On vmm_notify

Hope you found this useful. I will be talking about how to track Error Coverage in my next blog, so stay tuned!

Posted in Communication, Configuration, Coverage, Metrics, Reuse, Structural Components, Uncategorized, VMM, VMM 1.2, VMM infrastructure | No Comments »

Building & Configuring Coverage Model – VMM Style – Part-I

Posted by paragg on 24th June 2011

Parag Goel, Senior Corporate Application Engineer, Synopsys

To minimize wasted effort, coverage is used as a guide for directing verification resources by identifying tested and untested portions of the design.”

- IEEE Standard for System Verilog (IEEE Std. 1800-2009)

Configurability & reusability are the buzz^^^ words in the verification of chips and this are enabled to a big extent by the present day verification methodologies. Through a set of blogs, I plan to show how we can create configurable coverage models in VMM based environments. Given that, AMBA – AXI is one of the most commonly used protocols in industry for communication amongst the SOC peripherals, I chose protocol AXI based framework for my case study.

The idea here is to create a configurable coverage model leveraging some of the base classes provided in the methodology so that we can make it completely reusable as we move from the block to system level or as we move across projects. Once, we enable that, we can move the coverage model inside the Sub-environment modeled by vmm_group or vmm_subenv which are the units of reuse.

Picture1

Primary Requirements of Configuration Control:

Two important requirements that are needed to be met to ensure that the coverage model is made a part of reusable components are:

1. Ability to enable/disable the coverage model whenever required.

2. Ability to Turn ON/OFF different subgroups at the desired granularity. For example, an user may not always want the Error Coverage to be enabled, unless under specific circumstances.

To meet the above requirements, we make use of the VMM Global and Hierarchical Configurations

Through the vmm_opts base classes, VMM provides a mechanism to control the configuration parameters of a verification environment. This can be done in a hierarchical as well as in a global manner. These options are summarized below:

Picture6

In the environment, the coverage_enable is by default set to 0, i.e. disabled.

coverage_enable = vmm_opts::get_int(“coverage_enable”, 0);

Now, the user can enable the coverage via either of the two mechanisms.

1. From user code using vmm_opts.

The basic rule is that you need to ‘set’ it *before* the ’get’ is invoked and during the time where the construction of the components take place.  As a general recommendation, for the construction of structural configuration, the build phase is the most appropriate place.
function axi_test::build_ph();
// Enable Coverage.
vmm_opts::set_int(“@%*:axi_subenv:enable_coverage”, 1);
endfunction

2. From command line or external option file. The option is specified using the command-line +vmm_name or +vmm_opts+name.
./simv
+vmm_opts+enable_coverage=1@axi_env.axi_subenv

The command line supersedes the option set within code as shown in 1.

User can also specify options for specific instances or hierarchically using regular expressions.

Picture3

Now let’s look at the typical classification of a coverage model.

From the perspective of AXI protocol, we can look at the 4 sub-sections.

Transaction coverage: coverage definition on the user-controlled parameters usually defined in the transaction class & controlled through sequences.

Error coverage: coverage definition on the pre-defined error injection scenarios

Protocol coverage: This is protocol specific ((AXI Handshake coverage)). In case of AXI, it is mainly for coverage on the handshake signals i.e. READY & VALID on all the 5 channels.

Flow coverage: This is again protocol specific and for AXI it covers various features like, outstanding, inter-leaving, write data before write address etc…







clip_image001[11]

At this point, let’s look at how these different sub-groups with the complete coverage model can be enabled or disabled. Once the coverage configuration class is built and passed on to the main coverage model, we need a fine grain control to enable/disable individual coverage models. The code shows how the user can control all the coverage models in the build phase of the main coverage class.

Here too, we can see how we use vmm_opts comes to meet the requirements of controlling individual parameters.

vmm_opts::set_int(“@%*:disable_transaction_coverage”, 0);
vmm_opts::set_int(“@%*:disable_error_coverage”, 0);
vmm_opts::set_int(“@%*:disable_axi_handshake_coverage”, 0);

vmm_opts::set_int(“@%*:disable_flow_coverage”, 0);

In my next blog, I show how the hierarchical VMM Configurations is used to dynamically pass on signal level and other configuration related information to the coverage model. Also, we shall discuss the usage of VMM TLM feature, towards fulfilling the goal of configurable coverage model. Stay tuned!

Posted in Configuration, Coverage, Metrics, Organization, Reuse, SystemVerilog, Uncategorized, VMM, VMM 1.2, VMM infrastructure | No Comments »

Blocking and Non-blocking Communication Using the TLI

Posted by John Aynsley on 31st March 2011

John Aynsley, CTO, Doulos

In the previous blog post I introduced the VCS TLI Adapters for transaction-level communication between SystemVerilog and SystemC. Now let’s look at the various coding styles supported by the TLI Adapters, and at the same time review the various communication options available in VMM 1.2.

We will start with the options for sending transactions from SystemVerilog to SystemC. VMM 1.2 allows transactions to be sent through the classic VMM channel or through the new-style TLM ports, which come in blocking- and non-blocking flavors. Blocking means that the entire transaction completes in one function call, whereas non-blocking interfaces may required multiple function calls in both directions to complete a single transaction:

image

On the SystemVerilog side, transactions can be sent out through blocking or non-blocking TLM ports, through VMM channels or through TLM analysis ports. On the SystemC side, transactions can be received by b_transport or nb_transport, representing the loosely-timed (LT) and approximately-timed (AT) coding styles, respectively, or through analysis exports. In the TLM-2.0 standard any socket supports both the LT and AT coding styles, although SystemVerilog does not offer quite this level of flexibility, and hence neither does the TLI.

Now we will look at the options for sending transactions from SystemC back to SystemVerilog. Not surprisingly, they mirror the previous case:

image

On the SystemC side, transactions can be sent out from LT or from AT initiators or through analysis ports. On the SystemVerilog side, transactions can be received by exports for blocking- or non-blocking transport, by vmm_channels, or by analysis subscribers.

Note the separation of the transport interfaces from the analysis interfaces in either direction. The transport interfaces are used for modeling transactions in the target application domain, whereas the analysis interfaces are typically used internally within the verification environment for coverage collection or checking.

In the SystemVerilog and SystemC source code, the choice of which TLI interface to use is made when binding ports, exports, or sockets to the TLI Adapter, for example:


// SystemVerilog
`include “tli_sv_bindings.sv”
import vmm_tlm_binds::*;           // For port/export
import vmm_channel_binds::*;       // For channel

tli_tlm_bind(m_xactor.m_b_port,    vmm_tlm::TLM_BLOCKING_EXPORT,    “sv_tlm_lt”);
tli_tlm_bind(m_xactor.m_nb_port,   vmm_tlm::TLM_NONBLOCKING_EXPORT, “sv_tlm_at”);
tli_tlm_bind(m_xactor.m_b_export,  vmm_tlm::TLM_BLOCKING_PORT,      “sc_tlm_lt”);
tli_tlm_bind(m_xactor.m_nb_export, vmm_tlm::TLM_NONBLOCKING_PORT,   “sc_tlm_at”);
tli_channel_bind(m_xactor.m_out_at_chan, “sv_chan_at”, SV_2_SC_NB);

// SystemC
#include “tli_sc_bindings.h”
tli_tlm_bind_initiator(m_scmod->init_socket_lt, LT, “sc_tlm_lt”,true);
tli_tlm_bind_initiator(m_scmod->init_socket_at, AT, “sc_tlm_at”,true);
tli_tlm_bind_target   (m_scmod->targ_socket_lt, LT, “sv_tlm_lt”,true);
tli_tlm_bind_target   (m_scmod->targ_socket_at, AT, “sv_tlm_at”,true);
tli_tlm_bind_target   (m_scmod->targ_socket_chan_at, AT, “sv_chan_at”,true);


Note how the tli_tlm_bind calls require you to specify in each case whether the LT or AT coding style is being used. The root cause of this inflexibility is certain language restrictions in SystemVerilog, in particular the lack of multiple inheritance, which makes it harder to create sockets that support multiple interfaces. Hence, in SystemVerilog, the blocking- and non-blocking interfaces get partitioned across multiple ports and exports. In the SystemC TLM-2.0 standard there is only a single kind of initiator socket and a single kind of target socket, each able to forward method calls of any of the core interfaces, namely, the blocking transport, non-blocking transport, direct memory, and debug interfaces.

In summary, the VCS TLI provides a simple and straightforward mechanism for passing transaction in both directions between SystemVerilog and SystemC by exploiting the TLM-2.0 standard.

Posted in SystemC/C/C++, SystemVerilog, Transaction Level Modeling (TLM), VMM 1.2 | No Comments »

VMM-to-SystemC Communication Using the TLI

Posted by John Aynsley on 22nd March 2011

John Aynsley, CTO, Doulos

I have said several times on this blog that the presence of TLM-2.0 features in VMM 1.2 should ease the task of communicating between a SystemVerilog test bench and a SystemC reference model. Now, at last, let’s see how to do this – using the VCS TLI or Transaction Level Interface from Synopsys.

The parts of the TLI in question are the VCS TLI Adapters between SystemVerilog and SystemC. These adapters exploit the TLM-2.0-inspired features introduced into VMM 1.2 on the SystemVerilog side and the OSCI TLM-2.0 standard itself on the SystemC side in order to pass transactions between the two language domains within a VCS simulation run. The TLI Adapters do not provide a completely general solution out-of-the-box for passing transactions between languages in that they are restricted to passing TLM-2.0 generic payload transactions (as discussed in a previous blog post). However, the Adapters can be extended by the user with a little work.

Clearly, the VCS TLI solution will only be of interest to VCS users. As an alternative to the VCS TLI, it is possible to pass transactions between SystemVerilog and SystemC using the SystemVerilog DPI as described in SystemVerilog Meets C++: Re-use of Existing C/C++ Models Just Got Easier, and the Accellera VIP Technical Subcommittee are discussing a proposal to add a similar capability to UVM.

If you want to pass user-defined transactions between SystemVerilog and SystemC you are going to have to jump through some hoops, whether you choose to use the VCS TLI or the DPI. However, for the TLM-2.0 generic payload, the VCS TLI provides a simple ready-to-use solution. Let’s see how it works.

image

The TLI Adapters are provided as part of VCS. All you have to do is to include the appropriate file headers in your source code on both the SystemVerilog and SystemC sides, as shown on the diagram. The adapters themselves get compiled and instantiated automatically. The SystemVerilog side needs to use the VMM TLM ports, exports, or channels (as described in previous blog posts). The SystemC side needs to use the standard TLM-2.0 sockets. You then need to add a few extra lines of code on each side to bind the two sets of sockets together, and the TLI Adapters take care of the rest.
From the point of view of the source code, the adapter is invisible apart from the presence of the header files. Each binding needs to be identified by giving it a name, with identical names being used on the SystemVerilog and SystemC sides to tie the two sets of ports or sockets together. Here is a trivial example:

// SystemVerilog
`include “tli_sv_bindings.sv”

vmm_tlm_b_transport_port #(my_xactor, vmm_tlm_generic_payload) m_b_port;

tli_tlm_bind(m_xactor.m_b_port, vmm_tlm::TLM_BLOCKING_EXPORT, “abc”);

// SystemC
#include “tli_sc_bindings.h”

tlm_utils::simple_target_socket<scmod>  targ_socket_lt;

tli_tlm_bind_target (m_scmod->targ_socket_lt, LT, “abc”, true);


Note that the same name “abc” has been used on both the SystemVerilog and SystemC sides to tie the two ports/sockets together. On the SystemVerilog side we can now construct transactions and send them out through the TLM port:

// SystemVerilog
tx = new;
assert( tx.randomize() with { m_command != 2; } );
m_b_port.b_transport(tx, delay);


On the SystemC side, we receive the incoming transaction:

// SystemC
void scmod::b_transport(tlm::tlm_generic_payload& tx, sc_time& delay) {

tx.set_response_status(tlm::TLM_OK_RESPONSE);
}

The TLI Adapter takes care of converting the generic payload transaction from SystemVerilog to SystemC, and also takes care of the synchronization between the two languages. The VCS TLI provides a great ready-made solution for this particular use case. In the next blog post I will look at the VCS TLI support for various TLM modeling styles.

Posted in SystemC/C/C++, Transaction Level Modeling (TLM), VMM 1.2 | 1 Comment »

Channels versus Non-blocking Transport in VMM 1.2

Posted by John Aynsley on 17th January 2011

 

John Aynsley, CTO, Doulos

The original VMM book recommended ways of using the VMM channel to model non-atomic, pipelined, and out-of-order transaction execution. The TLM-2.0 standard addresses the same issues in a very different way. Now that TLM-2.0-like features are part of VMM and the Accellera Verification IP Technical Committee is looking at how to incorporate similar features into UVM, I thought it might be worthwhile to compare and contrast the two approaches. Choice is a good thing as long as you are properly equipped to understand the choices on offer.

Both the VMM channel and the TLM-2.0 standard address non-atomic and pipelined transactions using a non-blocking completion model. Whenever a producer sends out a transaction, control is immediately returned to the producer so that it has the option to send further transactions while the first is still being processed downstream. With the VMM channel, in-flight transactions may be held in the channel until they are processed, or may be buffered within some transactor downstream of the channel. The VMM channel can become full or empty, and dealing with this behavior is a necessary part of the interface between transactors. With TLM-2.0 there is no channel: any buffering is part of the behavior of the transactors rather than being part of the communication interface.

With VMM, the automatic garbage collection of SystemVerilog takes care of re-using the transaction object when there are no remaining references. In the SystemC implementation of TLM-2.0 each transaction has an explicit memory manager which provides a hook to represent the lifetime of the transaction, and in-flight transactions continue to live until the protocol has played itself out and every component has relinquished access to the transaction object.

In VMM, a downstream transactor is expected to signal to an upstream transactor when a transaction is complete. All VMM transactions that extend the base class vmm_data have embedded within them VMM notifications vmm_data::STARTED and vmm_data::ENDED which can be used for this purpose (and there are other related notifications within the channel itself). Effectively, the VMM transaction carries with it synchronization objects which the transactors can agree to use to signal significant timing points during the lifetime of the transaction. Any status information that needs to be associated with these timing points can be either attached to the notifications or sent as separate objects through the channel.

With both VMM and TLM-2.0, transactors can track outstanding transactions by maintaining references to the transaction objects. With the TLM-2.0 standard, each transaction is represented by exactly one transaction object which holds all the attributes associated with the transaction and with any response. With VMM, it is possible to create separate response objects (each of which should include a reference to the original transaction) and send these back to the producer through a separate channel in the reverse direction.

The mechanisms used to model multiple timing points within the lifetime of a single transaction are very different between classic VMM and TLM-2.0. As we have seen above, VMM uses notifications embedded within the transaction object (and channel) and also allows separate response or status descriptors to be associated with a transaction. TLM-2.0, on the other hand, does not allow either of these approaches. With TLM-2.0, multiple timing points are represented by the phase, which is an argument to the non-blocking transport call and is not part of the transaction object. With TLM-2.0, a set a phases is chosen to model the timing points of any given protocol and those phases are annotated onto the non-blocking transport method calls in order to indicate the state of each hop, or point-to-point link between transactors. All communication between transactors is signaled by making explicit calls to nb_transport_fw or nb_transport_bw. All associated attributes and status information are part of the transaction object, and the value of the phase argument is used by each transactor to determine the kind of access it is allowed to the transaction object, that is, which attributes are valid and which attributes may be updated at that time.

So, we have seen that classic VMM and the TLM-2.0 standard address the issue of having multiple timing points within the lifetime of a transaction in rather different ways. The VMM channel is usually the preferred approach within native VMM testbenches, but the VMM user can now choose between using channels and using the TLM-2.0 standard when interfacing the external models.

Posted in Transaction Level Modeling (TLM), VMM 1.2 | 1 Comment »

Verification in the trenches: A SystemC implementation of VMM1.2

Posted by Ambar Sarkar on 16th December 2010

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

VMM1.2 class library is now also implemented in SystemC(VMM-SC).

Will it help your project? Please take a few minutes to consider this, especially if you have been using or thinking about C/C++/SystemC models in your environment.

Following are the some use cases that I have come across or can anticipate among our clients. With each use case, I have put down some thoughts on why VMM-SC may(or may not) be of any benefit. Do you agree?

Use Case 1. Using SystemC as the primary verification language for unit level verification

Many teams today use SystemC as their primary verification language for all unit and system-level tests. However, with the increasing popularity of SystemVerilog, they often adopt a hybrid model. They do use C++/SystemC as the primary language for testbench creation, but complement it using SystemVerilog language features for assertions, functional coverage analysis, and constrained random generation.

Such teams often consider moving to SystemVerilog based environments, but are concerned about the reuse of their existing code, and cannot justify the ROI against the resources needed to make the transition to SystemVerilog completely. Ideally, they would like to have a multi-language solution that can mix and match SystemVerilog and SystemC components.

For this class of users, VMM-SystemC can ease their adoption of a multi-language solution. First, they can create newer environments in VMM-SC, and encapsulate preexisting VIP within VMM-SC components using thin wrappers. Once transitioned to VMM-SC, they can easily interoperate with other VMM-SV based environments and components. As an added benefit of the SystemVerilog-SystemC interoperability, the VMM-SV applications such as RAL/Scoreboarding etc. can now be made available to the SystemC side.

Use Case 2. Using SystemC as the primary verification language for system-level verification

Some teams decide to write their system level verification environments primarily in C/C++, as it is often used by the SW team or in the lab. Depending on the sophistication of these teams, these environments may range from being simple directed C testbenches to those that are highly sophisticated and use SystemC. Adopting VMM-SC as the system-level methodology can make it easier to cleanly pull in various environments and components by encapsulating them as VMM objects and making them work together taking advantage of VMM-SC support for phasing, TLM ports etc.

For this class of users, adopting VMM-SC as the top-level glue environment will be a big win.

Use Case 3. Planning to move to SystemVerilog and adopt industry standard practices.

Often, teams are willing to start from scratch for new projects as they realize their existing environments have become outdated and simply cannot scale. With the maturity of SystemVerilog, they would likely adopt it as the primary HVL language of choice. However, they would still like to preserve a number of previously developed components.

This is an ideal application for using VMM-SC. Pre-existing transactors can be converted to VMM-SC components by deriving them from vmm_xactor/vmm_unit classes(see 4.3 below). The new environment can now be written in VMM-SV, which can pull in the legacy components using VMM-SC/SV interoperability solution. All VMM features, such as cross language option setting, communicating transactions in a language agnostic way between source and target components using TLM, coordinated phasing etc. make the SystemVerilog adoption process much easier.

Use Case 4.  Using SystemC to develop ESL environments and reference models.

There are users who are primarily interested in creating models at various levels of abstraction. These models can be used in multiple applications, such as performance modeling and architectural exploration. In some cases, such models may not be of sufficient detail to use in functional verification.

At the minimum, such models should be created using TLM2.0 ports to enable easy plug and play in ESL contexts. Adopting VMM-SC as the primary methodology for developing such components can be of benefit, since it offers a rich set of features that can help in controlling and coordinating the components, while maintaining strong interoperability with verification environments.

 

So, to which one of these use cases do you belong? Any other use case that I missed?

This article is the 9th 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 SystemC/C/C++, Transaction Level Modeling (TLM), VMM 1.2 | 1 Comment »

How you can figure how you configure (a VMM testbench): Part 2

Posted by JL Gray on 13th December 2010

Jonathan Bromley, Verilab Inc, Austin, Tx

Part 2: An interesting way to use VMM 1.2’s configuration features

Part 1

examined the use of descriptor objects to pass configuration information around the testbench.  In VMM 1.2, though, the available toolkit has grown dramatically, inviting us to reconsider our approach.
 

 

Configuration in VMM 1.2

VMM1.2 provides powerful additional configuration features.  Other articles in this series, Verification in the trenches: Configuring your environment using VMM1.2 and Sharing RTL Configuration with the Testbench

, offer a great overview of the new mechanisms and how to use them.  The vmm_opts facilities make it easy to control configuration values deep in the test environment from top-level code, or even from scripts thanks to the built-in command-line and file reading features.  Within any vmm_unit you can use the vmm_unit_config macros to grab configuration values that were set up from the top level, picking up default values if the values were not set.  Within any vmm_object you can use vmm_opts::get_object_***() function calls to discover whether a given option has been explicitly set, and set a variable appropriately.
Given this new ability to set and grab arbitrary configuration values by name, is there still a role for the trusty configuration object?  I believe there is, for at least two reasons.

 

Legacy components

First, you will surely have some traditional transactors and subenvs in your VMM1.2 environments.  They will use config objects.  The two mechanisms can happily coexist, using VMM1.2 options to populate fields of the config objects before passing them to the transactors that need them:
class MagicToEth_gp extends vmm_group;
  `vmm_typename(MagicToEth_gp)
  MagicPacketXactor magic_xactor;
  EthernetXactor eth_xactor;
  bit has_voodoo;
  …
  function void build_ph();
    …
    MagicPacketXactor_cfg magic_cfg = new;
    …
    magic_cfg.SupportsVoodooMode = has_voodoo;
    magic_xactor = new(…., magic_cfg);
  endfunction
  …
  `vmm_unit_config_boolean(has_voodoo,
         “turn this on to enable MagicVoodoo”,
         0, MagicToEth_gp)
endclass

 

Configure just the variables you care about

Configuration using the new mechanisms is wonderfully flexible, but it needs to be thought through.  Used carelessly it can turn your testbench configuration into a grab-bag of hundreds of individual configuration values with no obvious relationships among them.  Using objects to group together a bunch of related configuration values allows you to use constrained randomization to enforce relationships among the values that were not specified from above, so that you can specify just those values you want to nail down and allow the remaining values to be randomized.  Making that work requires just a little bit of extra effort, and just a tiny bit of guru-level SystemVerilog randomization.
 

 

Selective configuration and randomization

For example, let’s go back to the configuration of our MagicPacket transactor.  We already have a configuration object for it – but now we must take care to derive from vmm_object so that the hierarchical configuration mechanism knows about it:
class MagicPacketXactor_cfg extends vmm_object;
  rand shortint unsigned MaxLength;
  rand bit SupportsVoodooMode;
    constraint c_valid_packet {
      if (SupportsVoodooMode) { MaxLength inside {[64:16384]}; }
      else                    { MaxLength == 1024; }
    }

Now we can play some interesting games with VMM configuration and SystemVerilog constrained randomization to make the configuration as flexible as possible:

function new(string name, vmm_object parent = null);
  bit is_set;
  super.new(parent, name);  // as usual for any vmm_object
  SupportsVoodooMode = vmm_opts::get_object_int(
    is_set,   // reports whether the option was set from above
    this,     // we’re interested in options applying to this object
    “SupportsVoodooMode”,  // identifying name of the option
    0,        // default value
    “some helpful documentation text” );
  if (is_set)  // This variable was explicitly configured.
               // Disable randomization of this variable.
    SupportsVoodooMode.rand_mode(0);
  MaxLength = vmm_opts::get_object_int(
    is_set,   // reports whether the option was set from above
    this,     // we’re interested in options applying to this object
    “MaxLength”,  // identifying name of the option
    1024,     // default value
    “some helpful documentation text” );
  if (is_set)  // This variable was explicitly configured.
               // Disable randomization of this variable.
    MaxLength.rand_mode(0);
endfunction

Why all this complexity?  Because of the huge flexibility it gives us.  The key is in understanding what happens later, when we randomize() this object.  If neither of the options was set, then rand_mode is true (its default) on both variables and randomization proceeds as normal.  If just one of the variables was configured, that variable now has rand_mode(0) and so it will not be altered by randomization – you have fixed it from the options.  The other variable is randomized, but respecting all constraints imposed by the variable that is already configured.  For example, suppose we configure MaxLength=5000 from the command line.  Thanks to our ingenious constructor code, that variable is fixed and won’t be randomized.  Other variables in the object are randomized, though, so the SystemVerilog constraint solver tries to find a value for SupportsVoodooMode that will satisfy the constraints.  Of course, that value must be true because of the if…else constraint – a false value is possible only if MaxLength is equal to 1024.

Finally, suppose we configure both variables from option values.  Now, any attempt to randomize() the configuration object will have no effect on the variables, because randomization has been disabled for both.  But randomization is still useful to us, because it will give a constraint violation error if the two options have been given contradictory values.

Getting the balance right is tricky – if you try to enforce too tight a structure on your collections of configuration data it will prove inflexible as verification requirements change, but leaving the configuration as a bunch of scattered, unrelated variables will soon become a maintenance nightmare.  Creative use of get_object_* options methods and randomization can offer a useful new set of compromises between flexibility and ease of deployment, by allowing you to specify just a few of an object’s configuration values and allowing randomization to choose a consistent set of values for the remaining variables.

Posted in Configuration, VMM 1.2 | No Comments »

How you can figure how you configure (a VMM testbench): Part 1

Posted by JL Gray on 7th December 2010

Jonathan Bromley, Verilab Inc, Austin, Tx

Part 1: Using configuration objects


Each VMM transactor class should have a companion config class, where you create data members for all critical “vital statistics” of the transactor.  Just before constructing the transactor object, an enclosing subenv would create one of these config objects and then pass it to the transactor as a constructor argument.  Every transactor should also provide a reconfigure method allowing other parts of the environment to set up a new configuration for it at any time.

 

Objects to control objects
Here’s an imaginary example of a transactor configuration class:

class MagicPacketXactor_cfg;
  rand shortint unsigned MaxLength;
  rand bit SupportsVoodooMode;
    constraint c_valid_packet {
      if (SupportsVoodooMode) { MaxLength inside {[64:16384]}; }
      else { MaxLength == 1024; }
    }
endclass

Note how the class contains rand data members for all the transactor’s configurable attributes, and also has constraints so that it will yield a meaningful and interesting set of configuration values when randomized.  Of course, further constraints can easily be added to enforce specific configurations.

The corresponding transactor code might be something like this:

class MagicPacketXactor extends vmm_xactor;
  …
  local MagicPacketXactor_cfg cfg;
  function new( … // usual VMM constructor arguments, and then…
                MagicPacketXactor_cfg cfg = null);
    …
    if (cfg == null) begin
      cfg = new;
      cfg.randomize();
    end
    this.cfg = cfg;
    …
  endfunction
  function void reconfigure(MagicPacketXactor_cfg cfg);
    this.cfg = cfg;
  endfunction

In the transactor’s main() task, or elsewhere, we can now do things like

if (this.cfg.SupportsVoodooMode)
  castSpell(…);

It’s really important to note that the transactor takes no responsibility for setting up its own configuration.  It merely assumes that a configuration object has been supplied from outside, and then makes use of the values within that configuration object.  If the enclosing environment fails to provide a configuration object, as a last resort the transactor constructs its own randomized configuration.

This is a good example of the notion of encapsulating configuration in a single object.  By gathering all important attributes of a component into a class:
•    we can pass the entire configuration around as a single object or reference;
•    it becomes easy to write randomization constraints that establish relationships among configuration attributes;
but most important of all:
•    it is straightforward to assemble several configuration objects into a single, larger configuration object suitable for use at the next level up the hierarchy– typically at the vmm_subenv level.

Environment configuration
A verification environment for a MagicPacket-to-Ethernet bridge will of course contain both MagicPacket and Ethernet transactors.  The environment or subenv gets its own configuration class, containing references to configuration objects for both its transactors:

class MagicToEthernet_subenv_cfg;
  rand MagicPacketXactor_cfg magic_cfg;
  rand Ethernet_cfg eth_cfg;
endclass

Configuration proceeds in much the same way as for the transactors.  The environment’s constructor takes one of these objects as an argument, and then passes on its inner configuration objects to the corresponding transactors as it constructs them.  Reconfiguring the environment is equally straightforward:

class MagicToEthernet_subenv extends vmm_subenv;
  MagicPacketXactor magic_xactor;
  EthernetXactor eth_xactor;
  …
  function void reconfigure(MagicToEthernet_subenv_cfg cfg);
    magic_xactor.reconfigure(cfg.magic_cfg);
    eth_xactor.reconfigure(cfg.eth_cfg);
  endfunction

Finally, the code that launches your VMM test can create and populate all the necessary configuration objects, assemble them into environment-wide configuration objects, and pass them into constructors as needed.  It is also very easy to configure multiple transactors to match a common configuration simply by passing the same configuration object to all of them.

Testbench configuration vs. test configuration
The configuration mechanism we’ve explored is neat, powerful and straightforward.  However, it doesn’t offer very much help in separating the two rather different concerns of configuring the test environment and configuring the test.

Test environment configuration gets you the right structure – correct number of transactors, correct choice of active vs. passive transactors, choice of reference model or scoreboard – to match the chosen device-under-test.  Using that test environment, though, you probably wish to run a large and ever-growing battery of testcases as you develop new stimulus to hit elusive coverage objectives.  From a programming point of view, configuring the test is not very different from configuring the testbench –a matter of passing appropriate configuration objects to the constructors of various components.  From an organizational point of view, though, there are big differences.   Testbench configuration generally needs to be at least partly driven by parameters of the DUT and test harness, whereas testcase configuration is likely to be much more flexible and dynamic, and will vary from run to run.

When using configuration objects in this style, I’ve learnt the value of keeping a strict separation between these two kinds of configuration to simplify those organizational concerns.

In the second part of this article we’ll look at the impact of the extensive new configuration facilities in VMM 1.2, and explore a novel way to manage groups of inter-related configuration options.

 

Posted in Configuration, VMM 1.2 | 1 Comment »

Communication Options in VMM 1.2

Posted by John Aynsley on 30th November 2010

 

John Aynsley, CTO, Doulos

Having given an example of transaction-level communication in VMM in my previous post, I am now going to say a little about each of the communication options available in VMM 1.2. The VMM user is presented with an array of communication options from which to chose, but which-is-which and which is best?

Blocking Transport

Blocking transport is used to send a single payload representing a transaction from an initiator to a target where very little timing information is required. Each transaction can have a begin time and an end time, but there is no more structure or detail to the lifetime of the transaction than that. It is possible to annotate timing information onto the b_transport call to offset the begin and end times of the transaction from the actual times as which the function is called and returned, but not to add further timing points or events during the lifetime of the transaction. The b_transport function is called with a transaction object as an argument, and returns only when the processing of that transaction at the target is complete. Blocking transport is the cleanest and simplest way to send a payload from A to B.

Non-blocking Transport

Like blocking transport, non-blocking transport is used to send a single payload representing a transaction from an initiator to a target. Unlike blocking transport, non-blocking transport allows significant events within the lifetime of the transaction to be modeled to whatever degree of timing granularity you like, and also allows multiple pipelined transactions to be in-flight at the same time. This is achieved by allowing multiple calls to nb_transport_fw and nb_transport_bw, in the forward and backward directions respectively, associated with a single transaction. The ability to model multiple timing points and pipelining comes at a cost in terms of the complexity of the interface, however. In the context of VMM, non-blocking transport is only of interest if you need to communicate with an existing SystemC TLM-2.0 model that uses this same interface.

Analysis Interface

The analysis interface is the third import to VMM from the TLM-2.0 standard. The analysis interface is used to broadcast a single payload to passive subscribers (aka observers or listeners). The defining characteristics of the analysis interface are firstly that there can be any number of subscribers to a single call and secondly that the subscribers are not permitted to modify the transaction object. Hence the analysis interface is ideal for distributing transactions to passive components such as checkers, scoreboards, and coverage collectors within a verification environment. The analysis interface is non-blocking and does not have any associated timing or status information.

Channels

Channels are the classic way to send payloads around a VMM verification environment. Unlike the three transaction-level interfaces described above, a channel is more than a function call. A channel is a FIFO buffer that can store multiple outstanding transactions. A transaction can be accessed by both producer and consumer transactors while it remains in the so-called active slot of the channel, and it is possible to model multiple timing points at that stage by having VMM notifications associated with the channel or with the transaction object. Channels are still the preferred mechanism used to model the timing and synchronization details of specific protocols within VMM, while blocking transport is preferred where a more abstract model is adequate.

Callbacks

In some respects callbacks play the same role as the analysis interface described above, while in other respects there are fundamentally different. Callbacks are like the analysis interface in the sense that they distribute function calls to any subscriber that has register itself with the transactor making the calls. They are different in that a callback is allowed to modify transactions passed as arguments to the function call whereas the analysis interface does not allow transactions to be modified. Also, callbacks are more flexible in the sense that both the callback function names and their argument lists are user-defined, which is not true of the analysis interface. In VMM, callbacks are the preferred mechanism where the behavior of a transactor needs to be modified by tweaking the contents of a transaction.

Notifications

VMM notifications are preferred for data-less synchronization where transactors need to synchronize without passing a payload. The analysis interface is preferred when passing around payloads. VMM notifications are also built into the transaction and channel base classes, so can be used to introduce additional timing points during the lifetime of a transaction when using VMM channels for communication as described above.

So, those are the six main choices for communication available to you in VMM. You can read more details in the VMM 1.2 Standard Library User Guide.

Posted in Communication, Transaction Level Modeling (TLM), VMM 1.2 | 1 Comment »

Example of Transaction-Level Communication in VMM 1.2

Posted by John Aynsley on 9th September 2010

John Aynsley, CTO, Doulos

Having introduced many of the technical details of transaction-level communication in VMM 1.2 in previous posts on this blog, we will now look at an example highlighting the various transaction-level communication mechanisms available in VMM 1.2 so that we can get a feel for the roles they perform and how they work together.
Let’s start with a producer that generates a stream of transactions:

 

class  my_gen  extends  vmm_xactor;

  vmm_tlm_b_transport_port #(my_gen, my_tx)  m_port;
  vmm_tlm_analysis_port    #(my_gen, my_tx)  m_ap;
  …

  begin: loop
    assert( randomized_tx.randomize() ) …
    $cast(tx, randomized_tx.copy());

    `vmm_callback(my_gen_callbacks,  pre_trans(this, tx));

    m_port.b_transport(tx, delay);

    `vmm_callback(my_gen_callbacks,  post_trans(this, tx));
    m_ap.write(tx);
  end
  …

The example above makes use of a blocking transport port, an analysis port, and callbacks. After randomizing and copying the next transaction in the stream, the producer offers the transaction to the pre_trans callback, giving a test the chance to modify the transaction before it is sent downstream. The transaction is then sent through the blocking transport port, with the advantage that the simple completion semantics of b_transport makes the producer code very clean. b_transport only returns when the transaction is finished, at which point the transaction is offered to another callback post_trans, which gets the chance to modify the transaction once more. Finally the transaction is sent out through the analysis port for broadcast to passive verification components for checking and coverage collection. The analysis port may be connected to zero, one, or many such passive components.
Now for the consumer that receives the transaction:

 


class  my_bfm  extends  vmm_xactor;
  my_channel  m_chan;
  vmm_tlm_analysis_port  #(my_bfm, my_tx)  m_ap;
  …
  begin: loop
    `vmm_callback(my_bfm_callbacks, pre_trans(this, tx));

    m_chan.activate(tx);
    m_chan.start();
    @(i_f.bus_cb); …
    m_chan.complete();
    m_chan.remove();

    `vmm_callback(my_bfm_callbacks, post_trans(this, tx));
    m_ap.write(tx);
  end


The consumer transactor makes use of callbacks and an analysis port in exactly the same way as the consumer, but does not use b_transport. Rather, it receives the incoming transaction using a vmm_channel, which gives more flexibility in interacting with the transaction during its lifetime. VMM recommends the use of vmm_channel when modeling slave-like transactors. The start and complete methods each cause notifications within the transaction, which may be significant for transaction recording or debug. The remove method removes the transaction from the channel, which in this example will have the effect of unblocking the call to b_transport from the producer.
Finally, the producer and consumer are connected together in the environment:

 


class  tb_env  extends  vmm_group;

  virtual function void  build_ph;
    m_tx_chan  = new( “my_channel”, “m_tx_chan” );
    m_tx_chan.reconfigure(1);
    m_gen      = new( “m_gen”, this );
    m_bfm      = new( “m_bfm”, this );
  endfunction

  function void  connect_ph();
    vmm_connect #(.D(my_tx))::tlm_bind(m_tx_chan, m_gen.m_port,
                              vmm_tlm::TLM_BLOCKING_EXPORT );
    m_bfm.m_chan = m_tx_chan;
  endfunction
  …


It is important to note that the channel is reconfigured with a full level of exactly 1 so that the blocking transport call will indeed block until the one-and-only transaction is removed from the channel by the consumer. If the full level were greater than 1, b_transport would return immediately and the communication scheme would be broken.
In order to bind the blocking transport port of the producer to the input channel of the consumer, it is necessary to use the tlm_bind method of the vmm_connect utility, as discussed in previous posts.

So, we have seen how the transaction-level ports, analysis ports, and callbacks each have their own role to play in constructing a VMM transactor.

 

 

Posted in Communication, Transaction Level Modeling (TLM), VMM 1.2 | No Comments »

Blocking/Non-blocking Transport Adaption in VMM 1.2

Posted by John Aynsley on 1st September 2010

John Aynsley, CTO, Doulos

One neat feature of the SystemC TLM-2.0 standard is the ability provided by the so-called simple target socket to perform automatic adaption between the blocking and non-blocking transport calls; an initiator that calls b_transport can be connected to a target that implements nb_transport, and vice-versa. VMM 1.2 provides similar functionality using the vmm_connect utility.

vmm_connect serves four distinct purposes in VMM 1.2.

•    Connecting one channel port to another channel port, taking account of whether each channel port is null or actually refers to an existing channel object
•    Connecting a notify observer to a notification
•    Binding channels to transaction-level ports and exports
•    Binding a transaction-level port to a transaction-level export where one uses the blocking
transport interface and the other the non-blocking transport interface. This is the case we are considering here.

When making transaction-level connections I think of vmm_connect as covering the “funny cases”.

To illustrate, suppose we have a transactor that acts as an initiator and calls b_transport. The following code fragment also serves as a reminder of how to use the blocking transport interface in VMM:

class initiator extends vmm_xactor;
`vmm_typename(initiator)

vmm_tlm_b_transport_port  #(initiator, vmm_tlm_generic_payload) m_b_port;

virtual task run_ph;
forever begin: loop
vmm_tlm_generic_payload tx;

// Create valid generic payload
assert( randomized_tx.randomize() with {…} )
else `vmm_error(log, “tx.randomize() failed”);

$cast(tx, randomized_tx.copy());

// Send copy through port
m_b_port.b_transport(tx, delay);

// Check response status
assert( tx.m_response_status == vmm_tlm_generic_payload::TLM_OK_RESPONSE );


Further, suppose we have another transactor that acts as a target for nb_transport calls, and which therefore implements nb_transport_fw to receive the request and subsequently calls nb_transport_bw to send the response. The code fragment below is just an outline, but it does show the main idea that non-blocking transport allows timing points to be modeled by having multiple method calls in both directions (as opposed to a single method call in one direction for b_transport):

class target extends vmm_xactor;
`vmm_typename(target)

vmm_tlm_nb_transport_export #(target, vmm_tlm_generic_payload) m_nb_export;

// Implementation of nb_transport method
virtual function vmm_tlm::sync_e nb_transport_fw(
int id=-1, vmm_tlm_generic_payload trans,
ref vmm_tlm::phase_e ph, ref int delay);

-> ev;
return vmm_tlm::TLM_ACCEPTED;
endfunction : nb_transport_fw

// Process to send response by calling nb_transport on backward path
virtual task run_ph;
forever  begin: loop
vmm_tlm::phase_e phase = vmm_tlm::BEGIN_RESP;
@(ev);
tx.m_response_status = vmm_tlm_generic_payload::TLM_OK_RESPONSE;
status = m_nb_export.nb_transport_bw(tx, phase, delay);
end
endtask: run_ph

Now for the main point. We can use tlm_connect to bind the two components together, despite the fact that one uses blocking calls and the other non-blocking calls:

virtual function void build_ph;
m_initiator = new( “m_initiator”, this );
m_target    = new( “m_target”,    this );
endfunction: build_ph

virtual function void connect_ph;

vmm_connect #(.D(vmm_tlm_generic_payload))::tlm_transport_interconnect(
m_initiator.m_b_port, m_target.m_nb_export, vmm_tlm::TLM_NONBLOCKING_EXPORT);

endfunction: connect_ph

That’s all there is to it! Notice that tlm_transport_interconnect is a static method of vmm_connect so its name is prefixed by the scope resolution operator and an instantiation of the vmm_connect parameterized class with the appropriate transaction type, namely the generic payload. The first argument is the port, the second argument the export, and the third argument indicates that it is the export that is non-blocking.
It is also possible to connect a non-blocking initiator to a blocking target: you would simply replace TLM_NONBLOCKING_EXPORT with TLM_NONBLOCKING_PORT. The objective of this post has been to show that VMM has all the bases covered when it comes to connecting together transaction-level ports.

Posted in Interoperability, Reuse, SystemC/C/C++, Transaction Level Modeling (TLM), VMM 1.2 | No Comments »

TLM and VMM – What is it all for?

Posted by John Aynsley on 18th August 2010

John Aynsley, CTO, Doulos

Having discussed some of the technical details of the implementation of the TLM-2 standard in VMM 1.2 in previous posts, it is time to stand back and ask what it is all for, especially considering that VMM must now co-exist alongside UVM in some projects. Fortunately, using the OSCI TLM standard as a basis for communication takes us a long way down the road toward interoperability, both between VMM and UVM and between VMM and SystemC.

We have seen that VMM 1.2 now supports the concept of ports and exports borrowed from SystemC and the closely related concept of sockets from the TLM-2 standard. Armed with these new concepts, VMM now offers two alternative communication mechanisms: communication between a producer and a consumer through an intermediate channel (the vmm_channel), and communication using direct function calls from producer to consumer (and vice versa) through ports and sockets. So what? Well, the benefits of direct communication were reviewed in an earlier post, but in summary, the simplicity of direct communication can speed up simulation by removing the number of context switches between processes and can provide an easy-to-follow completion model for knowing when a transaction is over. VMM users now have the choice between channel-based communication and direct communication. Channel-based communication works just fine, and may be preferred in native VMM environments. Direct communication is closer to the communication model used in UVM and in SystemC TLM-2.0, so may be preferred when working in a mixed environment, such as when integrating VMM and UVM components or when driving SystemC models from a VMM test bench.

We have also seen that VMM 1.2 supports the generic payload and extension mechanism from the SystemC TLM-2.0 standard. Frankly, this addition is unlikely to be of much interest in native VMM environments, but could be critical when it comes to including SystemC reference models in a VMM test bench. Say you have an existing SystemC reference model written to the TLM-2.0 standard, and you want to drive it from a VMM test bench. The new features in VMM 1.2 would allow you to construct a transaction within the VMM environment that has precisely the attributes expected by the TLM-2.0 standard generic payload, and then to pass that transaction over the fence from SystemVerilog to SystemC. It is possible to code the SystemVerilog-to-SystemC interface yourself using the DPI (for details see http://www.doulos.com/knowhow/sysverilog/DVCon10_dpi_paper) or to use the TLI (Transaction Level Interface) provided by Synopsys. I will say more about the TLI in a later post.

I have heard some VMM users say that they like the idea of being able to use the industry standard blocking transaction-level interface in VMM. Indeed, given the relatively small size of the overall hardware verification community and the cost of maintaining multiple standards, the sharing of ideas between standards in this way has to be a good thing. The early adopter release of UVM, the Universal Verification Methodology from Accellera, uses communication based on the SystemC TLM-1 standard. Even as I write this post, Accellera are considering the best way to incorporate the TLM-2-style interfaces as used in VMM into UVM, which should help make transaction-level communication between the two methodologies a little easier.

Posted in Reuse, SystemC/C/C++, Transaction Level Modeling (TLM), VMM 1.2 | No Comments »

TLM Sockets in VMM 1.2

Posted by John Aynsley on 12th August 2010

John Aynsley, CTO, Doulos

Having introduced both the blocking and the non-blocking transport interfaces in previous blog posts, it’s now time to look at TLM sockets in VMM 1.2.

In the SystemC TLM-2.0 standard, sockets are a mechanism that simplifies the instantiation and binding of multiple ports and exports for the various standard transaction-level interfaces by encapsulating several interfaces in a single object, the so-called socket. One initiator socket is bound to one target socket using one bind operator, and it is then possible to call all of the standard TLM-2.0 interface methods through that one pair of sockets. Moreover the socket has a BUSWIDTH parameter which represents the width of the data word transferred over the bus on each beat and which prevents sockets of different widths being inadvertently connected together.

Because VMM supports neither the full set of interfaces from the TLM-2.0 standard, nor the functionality of specified bus widths, nor the interoperability achieved by mandating the use of standard socket types, the value of sockets is considerably reduced in VMM compared to the SystemC TLM-2.0 standard. Nonetheless, the TLM sockets in VMM do allow both blocking and non-blocking transport method calls to be made through a single pair of sockets.

Let’s look at an example:

class initiator extends vmm_xactor;
`vmm_typename(initiator)
vmm_tlm_initiator_socket #(initiator, vmm_tlm_generic_payload) m_socket;

begin

m_socket.b_transport(tx, delay);

end

begin

status = m_socket.nb_transport_fw(tx, phase, delay);

end

virtual function vmm_tlm::sync_e nb_transport_bw( int id=-1,
vmm_tlm_generic_payload trans, ref vmm_tlm::phase_e ph, ref int delay);

endfunction : nb_transport_bw

endclass: initiator


As you can see above, the vmm_tlm_initiator_socket allows both b_transport and nb_transport_fw calls to be made through a single socket, as well as being able to accept incoming nb_transport_bw calls.

On the target side, the vmm_tlm_target_socket accepts incoming calls to both b_transport and nb_transport_fw as well as allowing outgoing calls to nb_transport_bw:


class target extends vmm_xactor;
`vmm_typename(target)
vmm_tlm_target_socket #(target, vmm_tlm_generic_payload) m_socket;

task b_transport(int id = -1, vmm_tlm_generic_payload trans, ref int delay);

endtask : b_transport

virtual function vmm_tlm::sync_e nb_transport_fw( int id=-1,
vmm_tlm_generic_payload trans, ref vmm_tlm::phase_e ph, ref int delay);

endfunction : nb_transport_fw


begin

status = m_socket.nb_transport_bw(tx, phase, delay);

end

endclass: target


Finally, at the top level, there is just a single pair of sockets to bind:

class tb_env extends vmm_group;
`vmm_typename(tb_env)
initiator  m_initiator;
target     m_target;

virtual function void build_ph;
m_initiator = new( “m_initiator”, this );
m_target    = new( “m_target”,    this );
endfunction: build_ph

virtual function void connect_ph;

m_initiator.m_socket.tlm_bind( m_target.m_socket );

endfunction: connect_ph

endclass: tb_env


That’s all there is to it!

The SystemC TLM-2.0 standard provides so-called convenient sockets, some of which can automatically convert incoming calls from b_transport to nb_transport and vice-versa. The VMM implementation achieves a similar result using the vmm_connect utility, which I will describe in a future post.

Posted in SystemC/C/C++, Transaction Level Modeling (TLM), VMM 1.2 | 1 Comment »

Learn about VMM adoption from customers – straight from SNUG India 2010

Posted by Srinivasan Venkataramanan on 1st July 2010

…Reflections form core engineering team of CVC, fresh from SNUG India 2010

Jijo PS, Thirumalai Prabhu, Kumar Shivam, Avit Kori, Praveen & Nikhil – TeamCVC www.cvcblr.com

Here is a quick collection of various VMM updates from SNUG India 2010 – as seen by TeamCVC. Expect to hear more on VMM1.2 soon from us as now I have a young team all charged up with VMM 1.2 (thanks to Amit @SNPS). All the papers and presentations can be accessed through: http://www.synopsys.com/Community/SNUG/India/Pages/IndiaConferenceataGlance.aspx

TI’s usage of VMM 1.2 & RAL

In one of the well received papers, TI Bangalore talked about “Pragmatic Approach for Reuse with VMM1.2 and RAL “. The design is a complex digital display subsystem involving numerous register configurations. Not only handling the register configurations is a challenge, but also the ability to reuse of block level subenvs at system level with ease, and with minimal rework and reduced verification time. The author presented their success with VMM 1.2 & RAL to address these challenges.

Key elements touched up on advanced VMM are:

· TLM 2.0 communication mechanism

· VMM Multi-Stream Scenario gen (MSS)

· VMM RAL

Automated Coverage Closure with ECHO

It is real and live – automated coverage closure is slowly becoming reality atleast in select designs & projects. Having been attempted by various vendors for a while (see: http://www.cvcblr.com/blog/?tag=acc) VCS has added this under ECHO technology. At SNUG, TI presented their experience with ECHO & VMM-RAL. In their paper titled “Automating Functional Coverage Convergence and Avoiding Coverage Triage with ECHO Technology” TI described how an ECHO based methodology in a VMM RAL based environment, can in an automated manner close the feedback loop in targeting coverage groups involving register configuration combinations resulting in significant reduction in verification time.

WRED Verification with VMM

In her paper on “WRED verification with VMM”, Puja shared her usage of advanced VMM capabilities for a challenging verification task. Specifically she touched upon:

· VMM Multi-Stream Scenario gen

· VMM Datastream Scoreboard with its powerful “with_loss” predictor engine

· VMM RAL to access direct & indirect RAMs & registers

What we really liked is to see real application of some of these advanced VMM features – we were taught all of these during our regular CVC trainings and we even tried many of them on our own designs. It feels great to hear form peers on similar usage and to appreciate the value we derive out of VMM @CVC and the vibrant ecosystem that CVC creates around the same.

System-Level verification with VMM

Ashok Chandran, of Analog Devices presented their use of specialized VMM components in a system-level verification project. Specifically he touched upon specialized VMM base classes like vmm_broadcast and vmm_scheduler

At the end the audience learnt what are some of the unique challenges a SoC verification project can present. Even more interesting was the fact that the ever growing VMM seems to have solution for a wide variety of such problems, well thought-out upfront – Kudos to the VMM developers!

Ashok also briefed on his team’s usage of relatively new features in VMM such as vmm_record and vmm_playback and how it helps us to quickly replay streams.

On the tool side, a very useful feature for regressions is the usage of separate compile option in VCS.

VMM 1.2 for VMM users

Amit from SNPS gave a very useful and upto-the-point update on VMM 1.2 for long time VMM users. It was rejuvenating to listen to the VMM 1.2 run_tests feature and the implicit phasing techniques. Though look like little “magic” these features are bound to improve our productivity as there are lesser things to code-debug and move-on..

Amit also touched upon the use of TLM 2.0 ports and how they can be nicely used for integrating functional coverage, instead of using the vmm_callbacks.

The hierarchical component creation and configurations in VMM 1.2 puts us on track for the emerging UVM and is very pleasing to see how the industry keeps moving to more-n-more automation.

A truly vibrant ecosystem enabled by CVC -VMM Catalyst member

A significant addition to this year’s SNUG India was the DCE – Designer Community Expo – a genuine initiative by Synopsys to bring in partners to serve the larger customer base better all under one roof. CVC (www.cvcblr.com) being the most active VMM catalyst member in this region was invited to setup a booth showcasing its offerings. We gave away several books including our popular VMM adoption book http://systemverilog.us/?p=14 and all the new SVA Handbook 2nd edition http://systemverilog.us/?p=16 .

Here is a snapshot of CVC’s booth with our VMM and other offerings.

clip_image002

Posted in Coverage, Metrics, Register Abstraction Model with RAL, VMM, VMM 1.2 | 1 Comment »

Non-blocking Transport Communication in VMM 1.2

Posted by John Aynsley on 24th June 2010

John Aynsley, CTO, Doulos

When discussing the TLM-2.0 transport interfaces my posts on this blog have referred to the blocking transport interface alone. Now it is time to take a brief look at the non-blocking transport interface of the TLM-2.0 standard, which offers the possibility of much greater timing accuracy.

The blocking transport interface is restricted to exactly two so-called timing points per transaction, marked by the call to and the return from the b_transport method, and by convention corresponding to the start of the transaction and the arrival of the response. The non-blocking transport interface, on the other hand, allows a transaction to be modeled with any number of timing points so it becomes possible to distinguish between the start and end of an arbitration phase, address phase, write data phase, read data phase, response phase, and so forth.

image

As shown in the diagram above, b_transport is only called in one direction from initiator to target, and the entire transaction is completed in a single method call. nb_transport, on the other hand, comes in two flavors: nb_transport_fw, called by the initiator on the so-called forward path, and nb_transport_bw, called by the target on the backward path. Whereas b_transport is blocking, meaning that it may execute a SystemVerilog event control, nb_transport is non-blocking, meaning that it must return control immediately to the caller. A single transaction may be associated with multiple calls to nb_transport in both directions, the actual number of calls (or phases) being determined by the protocol being modeled.

With just one call per transaction, b_transport is the simplest to use. nb_transport allows more timing accuracy, with multiple method calls in both directions per transaction, but is considerably more complicated to use. b_transport is fast, simple, but inaccurate. nb_transport is more accurate, supporting multiple pipelined transactions, but slower and more complicated to use.

In VMM the role of the TLM-2.0 non-blocking transport interface is usually played by vmm_channel, which allows multiple timing points per transaction to be implemented using the notifications embedded within the channel and the vmm_data transaction object. The VMM user guide still recommends vmm_channel for this purpose. nb_transport is provided in VMM for interoperability with SystemC models that use the TLM-2.0 standard.

Let’s take a quick look at a call to nb_transport, just so we can get a feel for some of the complexities of using the non-blocking transport interface:


class initiator extends vmm_xactor;
`vmm_typename(initiator)
vmm_tlm_nb_transport_port #(initiator, vmm_tlm_generic_payload) m_nb_port;

begin: loop
vmm_tlm_generic_payload tx;
int                     delay;
vmm_tlm::phase_e        phase;
vmm_tlm::sync_e         status;

phase  = vmm_tlm::BEGIN_REQ;

status = m_nb_port.nb_transport_fw(tx, phase, delay);
if (status == vmm_tlm::TLM_UPDATED)

else if (status == vmm_tlm::TLM_COMPLETED)

From the above, you will notice some immediate differences with b_transport. The call to nb_transport_fw takes a phase argument to distinguish between the various phases of an individual transaction and returns a status flag which signals how the values of the arguments are to be interpreted following the return from the method call. A status value of TLM_ACCEPTED indicates that the transaction, phase, and delay were unchanged by the call, TLM_UPDATED indicates that the return from the method call corresponds to an additional timing point and so the values of the arguments will have changed, and TLM_COMPLETED indicates that the transaction has jumped to its final phase.

You are not recommended to use nb_transport except when interfacing to a SystemC model because the rules are considerably more complicated than those for either b_transport or vmm_channel.

Posted in Communication, Interoperability, Reuse, Transaction Level Modeling (TLM), VMM 1.2 | No Comments »

Generic Payload Extensions in VMM 1.2

Posted by John Aynsley on 22nd June 2010

John Aynsley, CTO, Doulos

In a previous post I described the TLM-2 generic payload as implemented in VMM 1.2. In this post I focus on the generic payload extension mechanism, which allows any number of user-defined attributes to be added to a generic payload transaction without any need to change its data type.

Like all things TLM-2, the motivation for the TLM-2.0 extension mechanism arose in the world of virtual platform modeling in SystemC. There were two requirements for generic payload extensions: firstly, to enable a transaction to carry secondary attributes (or meta-data) without having to introduce new transaction types, and secondly, to allow specific protocols to be modeled using the generic payload. In the first case, introducing new transaction types would have required the insertion of adapter components between sockets of different types, whereas extensions permit meta-data to be transported through components written to deal with the generic payload alone. In the second case, extensions enable specific protocols to be modeled on top of the generic payload, which makes it possible to create very fast, efficient bridges between different protocols.

Let us have a look at an example that adds a timestamp to a VMM generic payload transaction using the extension mechanism. The first task is to define a new class to represent the user-defined extension:

class my_extension extends vmm_tlm_extension #(my_extension);

int timestamp;

`vmm_data_new(my_extension)
`vmm_data_member_begin(my_extension)
`vmm_data_member_scalar(timestamp, DO_ALL)
`vmm_data_member_end(my_extension)

endclass


The user-defined extension class extends vmm_tlm_extension, which should be parameterized with the name of the user-defined extension class itself, as shown. The extension can contain any number of user-defined class properties; this example contains just one, the timestamp.

The initiator of the transaction will create a new extension object, set the value of the extension, and add the extension to the transaction before sending the transaction out through a port:


class initiator extends vmm_xactor;
`vmm_typename(initiator)

vmm_tlm_b_transport_port #(initiator, vmm_tlm_generic_payload) m_port;

vmm_tlm_generic_payload randomized_tx;

begin: loop
my_extension ext = new;

$cast(tx, randomized_tx.copy());
ext.timestamp = $time;
tx.set_extension(my_extension::ID, ext);
m_port.b_transport(tx, delay);


Note the use of the extension ID in the call to the method set_extension: each extension class has its own unique ID, which is used as an index into an array-of-extensions within the generic payload transaction.

Any component that receives the transaction can test for the presence of a given extension type and then retrieve the extension object, as shown here:


class target extends vmm_xactor;
`vmm_typename(target)

vmm_tlm_b_transport_export #(target, vmm_tlm_generic_payload) m_export;

task b_transport(int id = -1, vmm_tlm_generic_payload trans, ref int delay);

my_extension ext;

$cast(ext, trans.get_extension(my_extension::ID));

if (ext)
$display(“Target received transaction with timestamp = %0d”, ext.timestamp);


Note that once again the extension type is identified by using its ID in the call to method get_extension. If the given extension object does not exist, get_extension will return a null object handle. If the extension is present, the target can retrieve the value of timestamp and, in this example, print it out.

The neat thing about the extension mechanism is that a transaction can carry extensions of many types simultaneously, and those transactions can be passed to or through transactors that may not know of the existence of particular extensions.

image

In the diagram above, the initiator sets an extension that is passed through an interconnect, where the interconnect knows nothing of that extension. The interconnect adds a second extension to the transaction that is only known to the interconnect itself and is ignored by the other transactors.

And the point of all this? The generic payload extension mechanism in VMM will permit transactions to be passed to SystemC virtual platform models, where the TLM-2.0 extension mechanism is heavily used.

Posted in Communication, Interoperability, Reuse, Transaction Level Modeling (TLM), VMM 1.2 | No Comments »

VMM 1.2.1 is now available

Posted by Janick Bergeron on 15th June 2010

We, in the VMM team, have been so busy working on improving VMM that we only recently noticed that it has been almost a full year since we released an Open Source distribution of VMM. With the release of VCS 2010.06, we took the opportunity to release an updated Open Source distribution that contains all of the new features and capability in VMM now available in the VCS distribution.

I am not going to repeat in details what changed (you can refer to the RELEASE.txt file for that), but I will point two of the most important highlights…

First, this version supports the VMM/UVM interoperability package (also available from download). This interoperability package will allow you to use UVM verification assets in your VMM verification environment (and vice-versa). Note that the VMM/UVM interoperability package is also included in the VCS distribution (along with the UVM-1.0EA release) in VCS2010.06.

Second, many new features were added to the VMM Register Abstraction Layer (RAL). For example, RAL now supports automatic mirroring of registers by passively observing read/write transaction or by actively monitoring changes in the RTL code itself. Another important addition is the ability to perform sub-register accesses when fields are located in individual byte lanes.

The Open Source distribution is the exact same source code as the VMM distribution included in VCS. Therefore, you can trust its robustness acquired in the field through many hundreds of successful verification projects.

Posted in Announcements, Interoperability, Register Abstraction Model with RAL, VMM 1.2 | 1 Comment »

Diagnosing Transaction-Level Connections in VMM 1.2

Posted by John Aynsley on 7th June 2010

John Aynsley, CTO, Doulos

In my previous post on this blog I discussed hierarchical transaction-level connections in VMM 1.2. In this post I show how to remove connections, and also discuss the various diagnostic methods that can help when debugging connection issues.

Actually, removing transaction-level connections is very straightforward. Let’s start with a consumer having an export that permits multiple bindings:

class consumer extends vmm_xactor;

vmm_tlm_b_transport_export #(consumer, vmm_tlm_generic_payload) m_export;

function new (string inst, vmm_object parent = null);
super.new(get_typename(), inst, -1, parent);
m_export = new(this, “m_export”, 4);
endfunction: new

Passing the value 4 as the third argument to the constructor permits up to four different ports to be bound to this one export. These ports can be distinguished using their peer id, as described in a previous blog post.

function void start_of_sim_ph;
vmm_tlm_port_base #(vmm_tlm_generic_payload) q[$];
m_export.get_peers(q);
m_export.tlm_unbind(q[0]);

TLM ports have a method get_peer (singular) that returns the one-and-only export bound to that particular port. TLM exports have a similar method get_peers (plural) that returns a SystemVerilog queue containing all the ports bound to that particular export. The method tlm_unbind can then be called to remove a particular binding, as shown above.

There are several other methods that can be helpful when diagnosing connection problems. For example, the method get_n_peers returns the number of ports bound to a given export:

$display(“get_n_peers() = %0d”, m_export.get_n_peers());

There are also methods for getting a peer id from a peer, and vice-versa, as shown in the following code which loops through the entire queue of peers returned from get_peers:

m_export.get_peers(q);
foreach(q[i])
begin: blk
int id;
id = m_export.get_peer_id(q[i]);
$write(“id = %0d”, id);
$display(“, peer = %s”, m_export.get_peer(id).get_object_hiername());
end

In addition to these low-level methods that allow you to interrogate the bindings of individual ports and exports, there are also methods to print and check the bindings for an entire transactor. The methods are print_bindings, check_bindings and report_unbound, which can be called as follows:

class tb_env extends vmm_group;

virtual function void start_of_sim_ph;
$display(“\n——– print_bindings ——–”);
vmm_tlm::print_bindings(this);
$display(“——– check_bindings ——–”);
vmm_tlm::check_bindings(this);
$display(“——– report_unbound ——–”);
vmm_tlm::report_unbound(this);
$display(“——————————–”);
endfunction: start_of_sim_ph

print_bindings prints information concerning the binding of every port and export below the given transactor. check_bindings checks that every port and export has been bound at least the specified minimum number of times. report_unbound generates warnings for any unbound ports or exports, regardless of the specified minimum.

In summary, VMM 1.2 allows you easily to check whether all ports and exports have been bound, whether a given port or export has been bound, to find the objects to which a given port or export has been bound, and even to remove the bindings when necessary.

Posted in Communication, Interoperability, Reuse, Transaction Level Modeling (TLM), VMM 1.2 | No Comments »

Implicit vs. Explicit Phasing

Posted by JL Gray on 3rd June 2010

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

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

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

Posted in Phasing, Tutorial, VMM 1.2 | No Comments »

Verification in the trenches: TLM2.0 or vmm_channel? Communicating with other components using VMM1.2

Posted by Ambar Sarkar on 1st June 2010

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

Did life get easier with the availability of TLM2.0 style communication in VMM1.2?

Or the other way around? Are you asking: Should I use a vmm_tlm port or just stick to the tried and trusted vmm_channel as my communication method within the verification environment? You are not alone.

As you are aware, VMM1.2 provides the following interfaces for exchanging transactions between components:

  1. vmm_channel (Pre VMM1.2)
  2. vmm_tlm based blocking and non-blocking interfaces (TLM based)
  3. vmm_analysis_port (TLM based)
  4. vmm_callback (Pre VMM1.2)

Which option is the best for communicating between components? Under what circumstances?

There are two real requirements here,

  1. Maintain the ability to work with existing VMM (pre VMM 1.2) components.
  2. Be forward compatible with components created with TLM based ports, as is expected as the industry moves toward UVM (Yes, the early adopter version was released recently!).

TLM2.0 based communication mechanism offers a flexible, sufficient, efficient, and clear and well-defined semantics for communication between two components, and the industry as a whole is moving towards a TLM based approach. For these reasons, I recommend going forward that any new VIP using only the TLM2.0 based communication.

Since VMM1.2 provides complete interoperability between vmm_channel and tlm 2.0 style ports, the user is guaranteed that the created component will keep on working with vmm_channel based counterparts:

class subenv extends vmm_group;
initiator i0;
target t0;

virtual function void connect_ph();
vmm_connect #(.D(my_trans))::tlm_bind(
t0.in_chan, // Channel
i0.b_port, // TLM port
vmm_tlm::TLM_BLOCKING_EXPORT);
endfunction: connect_ph

endclass: subenv

Similarly, any vmm_notify based callback events can be communicated using tlm_analysis ports. For details, see example 5-48 in the Advanced Usage section in the user guide.

By creating components that solely depend on TLM style communication schemes will greatly facilitate interoperability and migration of VIP implementations to currently evolving statndard of UVM.

The following summarizes my recommendations:

Type of interaction

Recommended mechanism

Issuing and receiving transactions vmm_tlm based blocking interface
Issuing notification to passive observers vmm_analysis_port

For issuing transactions to other components on a point-to-point manner, typically seen in master-slave based communications, use the vmm_tlm based blocking port interfaces.

For slave-like transactors which expect to receive transactions from other transactors, use vmm_tlm based blocking export interface.

For reactive transactors, define additional vmm_tlm based blocking export interface.

For broadcast transactions to be communicated to multiple consumers such scoreboards, functional coverage models, etc, use vmm_analysis_port.

So, did life get easier with TLM? I believe so. Especially if you want to be forward compatible with the new and upcoming methodologies.

This article is the 7th 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 Communication, Transaction Level Modeling (TLM), Tutorial, VMM 1.2 | No Comments »

Phases and Threads

Posted by JL Gray on 27th May 2010

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

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

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

Posted in Phasing, Tutorial, VMM 1.2 | 1 Comment »

Hierarchical Transaction-Level Connections in VMM 1.2

Posted by John Aynsley on 19th May 2010

John Aynsley, CTO, Doulos

In a previous blog post I described ports and exports in VMM 1.2, and explored the issue of binding a port of one transactor to the export of another transactor, where the two transactors are peers. Now let us look at how we can make hierarchical connections between ports and exports in the case where one transactor is nested within another.

Let’s start with ports. Suppose we have a producer that sends transactions out through a port and is nested inside another transactor:

class producer extends vmm_xactor;
vmm_tlm_b_transport_port #(producer, vmm_tlm_generic_payload) m_port;

virtual task run_ph;

vmm_tlm_generic_payload tx;

m_port.b_transport(tx, delay);

This transactor calls the b_transport method to send a transaction out through a port. So far, so good. Now let’s look at the parent transactor:

class producer_parent extends vmm_xactor;

vmm_tlm_b_transport_port #(producer_parent, vmm_tlm_generic_payload) m_port;

producer  m_producer;

virtual function void build_ph;
m_producer = new( “m_producer”, this );
endfunction: build_ph

The producer’s parent also has a port, through which it wishes to send the transaction out into its environment. The port on the producer must be bound to the port on the parent. This is done in the connect phase:

virtual function void connect_ph;
m_producer.m_port.tlm_import( this.m_port );
endfunction: connect_ph

Note the use of the method tlm_import in place of tlm_bind to perform the child-to-parent port binding. Why is this particular method named tlm_import? I am tempted to say “Don’t ask!” Whatever name had been selected, somebody would have found it confusing. Of course, the idea is that something is being imported. In this case it is actually the address of the b_transport method that is effectively being imported from the parent (this.m_port) to the child (m_producer.m_port). tlm_import is being called in the sense CHILD.tlm_import( PARENT), which makes sense to me, anyway.

So much for the producer. On the consumer side the situation is very similar so I will cut to the chase:

class consumer_parent extends vmm_xactor;

vmm_tlm_b_transport_export #(consumer_parent, vmm_tlm_generic_payload) m_export;

consumer  m_consumer;

virtual function void connect_ph;
m_consumer.m_export.tlm_import( this.m_export );
endfunction: connect_ph

In this case, the address of the b_transport method is effectively being passed up from the child (m_consumer.m_export) to the parent (this.m_export). In other words, b_transport is being exported rather than imported, but note that it is still the tlm_import method that is being used to perform the binding in the direction CHILD.tlm_import( PARENT ).

Now for the top-level environment, where we instantiate the parent transactors:

class tb_env extends vmm_group;

producer_parent  m_producer_1;
producer_parent  m_producer_2;
consumer_parent  m_consumer;

virtual function void build_ph;
m_producer_1 = new( “m_producer_1″, this );
m_producer_2 = new( “m_producer_2″, this );
m_consumer   = new( “m_consumer”,   this );
endfunction: build_ph

virtual function void connect_ph;
m_producer_1.m_port.tlm_bind( m_consumer.m_export, 0 );
m_producer_2.m_port.tlm_bind( m_consumer.m_export, 1 );
endfunction: connect_ph

endclass: tb_env

This is straightforward. We just use the tlm_bind method to perform peer-to-peer binding between a port and an export at the top level. Note that we are binding two distinct ports to a single export; as explained in a previous blog post, a VMM transactor can accept incoming transactions from multiple sources, distinguished using the value of the second argument to the tlm_bind method.

So, in summary, it is possible to bind TL- ports and exports up, down, and across the transactor hierarchy. Use tlm_bind for peer-to-peer bindings, and tlm_import for child-to-parent bindings.

Posted in Communication, Reuse, Transaction Level Modeling (TLM), VMM 1.2 | 1 Comment »