Verification Martial Arts: A Verification Methodology Blog

Archive for June, 2010

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 »

The Generic Payload in VMM 1.2

Posted by John Aynsley on 16th June 2010

John Aynsley, CTO, Doulos

In this post we turn to the generic payload, another feature from the SystemC TLM-2.0 standard that has been incorporated into VMM 1.2. The generic payload is a transaction data structure that contains common attributes found in current memory mapped bus protocols, as shown in the table below:

clip_image002

You will immediately recognize attributes such as command, address and data, and can probably have a good guess at the meaning of most, if not all, the remaining attributes. The Modifiable column indicates whether the value of the attribute may be modified by a component other than the initiator that first generates the transaction.

In TLM-2.0 the generic payload serves two purposes: firstly, to provide an off-the-shelf way of representing memory mapped bus protocols at an abstract level, and secondly, to provide the basis for modeling specific protocols. As an abstraction, the generic payload provides interoperability between components where the precise details of the bus protocol are unimportant, thus allowing the construction of a set of generic components for simple peripherals and memory that can be plugged into any transaction-level platform model. On the other hand, for modeling specific protocols the generic payload offers an extension mechanism that can be used to add protocol-specific attributes. This extension mechanism has been tuned to provide very fast, efficient conversion in C++ between generic payloads that represent different protocols, where each payload has a different set of extensions.

So much for TLM-2.0 in the context of virtual platform modeling, but what about VMM? A native VMM test bench that drives transactions into an HDL model is unlikely to benefit from using the generic payload. The real benefit will come when driving transactions into a TLM-2.0-compliant SystemC model that already uses the generic payload. The VMM code to generate a generic payload transaction might look like this:


vmm_tlm_generic_payload  randomized_tx;

forever
begin: loop
  vmm_tlm_generic_payload  tx;
  int  delay;
  assert( randomized_tx.randomize() with {
      m_address >= 0 && m_address < 256;
      m_length == 4 || m_length == 8;
      m_data.size == m_length;          // Trick to randomize dynamic array
      m_byte_enable_length <= m_length;
      (m_byte_enable_length % 4) == 0;
      m_byte_enable.size == m_byte_enable_length;
      m_streaming_width == m_length;
    } )
  else `vmm_error(log, "tx.randomize() failed");

  $cast(tx, randomized_tx.copy());
  m_port.b_transport(tx, delay);
  assert( tx.m_response_status == vmm_tlm_generic_payload::TLM_OK_RESPONSE );
end


The initiator is obliged to set each of the attributes of the generic payload to a legal value before sending the transaction through the port, and to check the value of the m_response_status attribute on return. The m_command attribute may be READ, WRITE, or IGNORE. The m_length attribute gives the number of bytes in the m_data array and the m_byte_enable_length attribute the number of bytes in the m_byte_enable array, which could be 0. The m_address attribute gives the address of the first byte in the array.

In summary, a generic payload transaction has the effect of transferring a block of bytes between an initiator and a target. Because the generic payload is intended as an abstraction for a memory-mapped bus, that block of bytes has a single start address in a memory map, and may be either written to or read from the target. As a refinement, individual bytes may be enabled or disabled and successive blocks of bytes may be sent to the same address range by setting the m_streaming_width attribute accordingly. The generic payload can be used as an abstraction for any communication mechanism that transfers a block of bytes, and the extension mechanism is available when it becomes necessary to add new protocol-specific attributes to the transaction.

Look out for my next post on this blog, when I will explain the extension mechanism in more detail.

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

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 »

TLM vs. Channels

Posted by JL Gray on 9th June 2010

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


Confused about the difference between using channels and TLM to connect your testbench components? Check out this short video for a simple explanation of the mechanics of the two approaches.

Posted in Transaction Level Modeling (TLM), Tutorial | 2 Comments »

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 »