Verification Martial Arts: A Verification Methodology Blog

Archive for the 'Transaction Level Modeling (TLM)' Category

The Curious World of Ports and Exports in VMM 1.2

Posted by John Aynsley on 4th February 2010

JohnAynsley

John Aynsley, CTO, Doulos

In a previous post I discussed the new blocking transport interface of VMM 1.2, and described how a producer can call the b_transport method implemented by a consumer. In this post, I will describe how to connect the producer to the consumer using the new features of VMM 1.2.

The new features discussed here were inspired by the SystemC TLM-2.0 standard. In SystemC, two modules wishing to communicate get connected using so-called “ports” and “exports”. Although the underlying concept is both elegant and powerful, the terminology “port” and “export” often seems to cause confusion. Since this is now part of VMM 1.2, I will explain. Let us consider a simple example of a producer calling the b_transport method implemented in a consumer.

class my_tx extends vmm_data; // User-defined transaction class

class producer extends vmm_xactor;
vmm_tlm_b_transport_port #(producer, my_tx) m_port;
my_tx tx;

m_port.b_transport(tx, delay);

class consumer extends vmm_xactor;
vmm_tlm_b_transport_export #(consumer, my_tx) m_export;
task b_transport(int id = -1, my_tx trans, ref int delay);

class my_env extends vmm_group;
producer m_producer;
consumer m_consumer;

virtual function void connect_ph;
m_producer.m_port.tlm_bind( m_consumer.m_export );
endfunction

What is happening here is that the producer is calling b_transport through a port, the consumer is providing an implementation of b_transport using an export, and the top-level environment is connecting (or “binding”) the port to the export. The tlm_bind method is creating the link between the port and the export such that when the producer calls b_transport, it is the implementation of b_transport within the consumer that actually gets called.

Both the port and the export declarations are parameterized with the type of the transactor (producer/consumer) and the type of the transaction (my_tx). You may notice that the implementation of b_transport has an extra int id argument. This can be used to distinguish between transactions arriving from different producers. I will discuss this in my next blog post.

The purpose of ports and exports is to provide a structured way of making method calls between VMM transactors (or SystemC modules) such that the dependencies between each transactor and its environment can be minimized. To call b_transport the code within the producer only need refer to the port and has no direct dependencies on any code outside that transactor. Similarly, to call the b_transport method implemented within the consumer, the environment only need refer to the export. It is only when the port and export are connected within the connect_ph method of the environment that a specific dependency is established between the producer and consumer transactors.

What about those terms “port” and “export”? The term port was originally borrowed from VHDL and Verilog. In SystemC, a port allows an interface method call to be made up-and-out-of a module. When SystemC was enhanced to add the mirror image construct that allows an interface method call to be made down-and-into a module the term “export” was chosen because an export provides or “exports” an interface, whereas a port “imports” an interface.

If we could re-write history, I guess we might have chosen the term “import” instead of “port”. Perhaps that would have caused less confusion. Or maybe not!

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

Should you use VMM Callbacks or TLM Analysis ports?

Posted by S. Prashanth on 27th January 2010

With the addition of OSCI TLM2.0 features in VMM1.2, it is now becoming possible to use analysis ports for broadcasting transaction information from a transactor to any components such as scoreboard, functional coverage models, etc…

But, does it mean that VMM callbacks which are traditionally used for this purpose are not required anymore?

In short, the answer is no: both analysis port and callback have their own advantages. Before getting into more details, let me show you two simple examples I’ve created to encompass the analysis port and callback usage.

Communication through analysis port

Step1: In my transactor, I’ve simply instantiate a vmm_tlm_analysis_port instance [line 2]and invoke the analysis_port.write() method [line 8] to post the tr object to multiple subscribers.

1. class cpu_driver extends vmm_xactor;

2. vmm_tlm_analysis_port#(cpu_driver, cpu_trans) analysis_port;

3.    virtual function void build_ph();

analysis_port = new(this, “cpu_analysys_port”);

4.    endfunction

5.    virtual task main();

6.       cpu_trans tr;

7.       …

8. analysis_port.write(tr);

9.     endtask

10. endclass

Step2: Let’s now see how to model a subscriber such as a coverage model. In this model, I’ve simply instantiated a vmm_tlm_analysis_export instance [Line 3] and provided the implementation of the write method() [Line 4]. Once the transactor posts a transaction to the write method, the coverage model write_CPU gets called as well and receives this transaction, which can be sampled and covered.

1. class cntrlr_cov extends vmm_object;

2.    vmm_tlm_analysis_export #(cntrlr_cov, cpu_trans)

3.    cpu_export = new(this, “CpuAnExPort”);

4.    virtual function void write(int id=-1, cpu_trans tr);

5.        this.cpu_tr = tr;

6.        CG_CPU.sample();

7.   endfunction

8. endclass

Step3: The last important part is to bind my transactor and my subscribers. This is simply done by using the transactor tlm_bind() method. Of course we should be invoked for all subscribers.

1. class tb_env extends vmm_group;

2.    cpu_driver drv;

3.    cntrlr_cov cov;

4.    function void connect_ph();

5.       drv.analysis_port.tlm_bind(cov.cpu_export);

6.    endfunction

7. endclass

As you can see in these examples, analysis ports are easy to use. But they are not meant to allow subscribers to modify the transaction and are very much restricted to only one method with only one argument, i.e. write().

Communication through callback

Step1: I’ve created a generic callback that is nothing but a container that extends the vmm_xactor_callbacks base class with empty virtual methods [Line 1-3]. I have deliberately left these methods empty so that they can overridden for any particular usage such as a coverage model, scoreboard, etc.Next step is have my transactor calling this callback once the transaction is available [Line 10]

1. class cpu_driver_callbacks extends vmm_xactor_callbacks;

2.    virtual function void write(cpu_trans tr); endtask

3. endclass

4.

5. class cpu_driver extends vmm_xactor;

6.

7.    virtual task main();

8.       cpu_trans tr;

9.       …

10.      `vmm_callback(cpu_driver_callbacks, write(tr));

11.   endtask

12. endclass

Step2: Now, I can extend the previous class and provide the implementation the coverage model directly in the callback

1. cpu2cov_callback extends cpu_driver_callbacks;

2.    cntrlr_cov cov;

3.    virtual function void write(cpu_trans tr);

4.       cov.cpu_tr = tr;

5.       cov.CG_CPU.sample()

6.    endfunction

7. endclass

Step3: Once both transactor and subscribers are implemented, I can simply instantiate them in my implicitly phased environment [Line2-3]. Then, I can register the extended callback instance to the transactor by using append_callback() method Line[6]. Note that this registration happens in the connect phase.

1. class tb_env extends vmm_group;

2.    cpu_driver drv;

3.    cntrlr_cov cov;

4.    function void connect_ph();

5.       cpu2cov_callback cbk = new(cov);

6.       drv.append_callback(cbk);

7.    endfunction

8. endclass

As you can see in above examples, callbacks are also easy to use. As opposed to analysis port, their subscribers can possibly modify the transaction and can contain multiple methods with any kind of arguments.

Comparison

1. Analysis ports follow OSCI TLM2.0 standard.

2. Unlike callbacks, user do not need to create class with empty virtual methods, instead pre-defined method write() is used

3. Analysis ports can only broadcast one transaction as opposed to callbacks where you can define the method arguments.

4. Analysis port method write() is a function whereas callback class can model its empty virtual methods as tasks or void functions which gives you flexibility to control the transactor as well (like inserting delays, injecting error mechanism, etc)

5. The `vmm_tlm_analysis_export() macro must be used to create a new analysis façade when a class need to have more than one analysis export

6. Analysis ports can only be used by classes based on vmm_object. Callbacks can be used by any class.

In summary

- If a transactor needs to broadcast only one transaction, then analysis port can be used. If a transactor needs to send different kinds of information at different points, and provide some hooks for modeling variant functionality (like inserting delays, error injections, etc), then callbacks is the way to go. Both analysis port and callback can also be provided, publishing analysis port after callbacks.

Posted in Callbacks, Communication, Reuse, Transaction Level Modeling (TLM) | 2 Comments »

Transactor Interfaces [VMM 1.2 style]

Posted by Vidyashankar Ramaswamy on 18th January 2010

In my earlier blog post I have shown how to write a configurable physical interface. This time I shall look into the slave transactor and its interfaces. A slave transactor can have all or some of the interfaces shown in the following Figure. It solely depends on the nature of the protocol and its surrounding environment. If you are developing verification IP which is used across multiple projects or groups , then you must consider the entire interface requirement and develop the VIP accordingly. Please note that I will be discussing only the analysis port [No 5] and the transport port [No 6] interfaces which are developed using VMM 1.2 features.

image

Analysis Port

Analysis ports are used to share the received transaction among the other testbench components. These components can also be referred to as listeners, subscribers, observers, target or sometimes passive component. As the name says , this port is used to distribute the transaction to a single or multiple listeners for analysis. The important feature of the analysis port is that a single port can be connected to multiple subscribers. The component which is broadcasting the transaction uses “analysis port” and the observers implement the analysis export port. Each subscriber must implement the “write”  method of the vmm_tlm_analysis_export class. Here the listeners can’t modify the transaction and can only copy it’s content for analysis. Most common testbench components which can use this port are scoreboard, functional coverage, debug and reference model.

Analysis port in the producer (Initiator) model

The analysis port is implemented as follows. The port object is constructed in the transactors’s build phase. As this is a slave model, the write method is called after responding to the observed request on the bus.

File: vip_slave.sv

. . .
//////////// SLAVE MODEL ///////////////

class vip_slave extends vmm_xactor;
`vmm_typename(vip_slave)
// Variables declaration
. . .
// Analysis port
vmm_tlm_analysis_port#(vip_slave, vip_trans) analysis_port;
// TLM Blocking port
vmm_tlm_b_transport_port#(vip_slave, vip_trans) b_trans_resp_port;

// Component Phases
. . .
extern virtual function void build_ph();
extern virtual protected task main();
. . .
endclass: vip_slave
. . .
/////////////// Build Phase /////////////////
function void vip_slave::build_ph();
. . .
// Construct the analysis port for Observers
analysis_port = new(this, “analysis_port”);
// Construct the transport port for response modification
b_trans_resp_port = new(this, “b_trans_resp_port”);
. . .
endfunction: build_ph
. . .

////////////// Main Method////////////////
task vip_slave::main();
super.main();
forever begin
vip_trans tr;
int dly = 0;
. . .
if (tr.kind == vip_trans::READ) begin
// Retrieve the data
. . .
// Provide the handle to the modifying transactor
b_trans_resp_port.b_transport(tr, dly);
. . .
// Finally drive the data onto the bus
. . .
end
else begin
// WRITE
// Assemble the trans properties
. . .
// Provide the handle to the modifying transactor
b_trans_resp_port.b_transport(tr, dly);
. . .
// Store the data
. . .
end
. . .
// notify the observers about this transaction
this.analysis_port.write(tr);
. . .
end
endtask:
main

Analysis export port in the target (consumer) model

Following is a very simple implementation of an observer. This observer class has an instance of the tlm analysis export class and overrides the virtual function  “write”  to operate on the received transaction. Here the write method displays the received transaction from the initiator.

File: observer.sv

class observer extends vmm_object;
`vmm_typename(observer)
vmm_tlm_analysis_export#(observer, vip_trans) obsrv ;
vmm_log log = new(“log”, this.get_object_hiername());

virtual function void write (int id = -1, vip_trans tr);
`vmm_note(log, ” … From Observer: Rcvd Transaction … “);
tr.display(“”);
endfunction: write

function new(vmm_object parent = null, string inst=””);
super.new(parent, get_typename());
endfunction

/////////////// Build Phase /////////////////
function void build_ph();
. . .
// Construct the analysis export port

obsrv = new(this, “obsrv”);
. . .
endfunction

endclass: observer

Transport Interface

The transactions received by a slave can be processed by a higher layer transactor before responding to the request. In these situations TLM transport ports are used for passing transactions in a blocking/non-blocking way. This slave model uses a blocking transport port to pass the transaction to another transactor for further processing. Blocking transport, completes the transaction within a single method call and uses the forward path from initiator to target. To use this interface, the slave model should implement vmm_tlm_b_transport_port for issuing transactions and the higher layer transactor implements vmm_tlm_b_transport_export for receiving transactions. Please refer to the code shown above (vip_slave.sv).  Also note that the transaction data modification (call to b_transport method) happens before storing the WRITE data  or responding to a READ request.

In a transactor implementation, It is ok to construct and call the analysis port’s “write” method without binding it in the environment. This is not true with the transport port’s “b_transport” method and should be bound in the environment. So it is a good practice to make this port configurable (enable/disable) using vmm options.

Response modifier Transactor

This transactor shows how to instantiate the tlm export class object and the implementation of the b_transport method. Following is a very simple implementation of the transport method, where the received transaction is displayed.

File: resp_modifier.sv
class resp_modifier extends vmm_xactor;
`vmm_typename(resp_modifier)
vmm_tlm_b_transport_export#(resp_modifier, vip_trans) b_trans_resp_export ;

virtual task b_transport (int id = -1, vip_trans tr, ref int dly);
`vmm_note(log, ” …. Resp Trans Modifier …. “);
tr.display(“”);
endtask: b_transport

function new(vmm_unit parent = null, string inst=””);
super.new(get_typename(), inst, 0, parent);
endfunction

/////////////// Build Phase /////////////////
function void build_ph();
. . .
// Construct the transport export port

b_trans_resp_export = new(this, “b_trans_resp_export”);
. . .
endfunction

endclass: resp_modifier

Connecting it all together

The last step is to create the environment. The required components are constructed in the build phase. Connect phase is used to bind the ports appropriately as shown in the code below.  Please refer to the VMM user guide for more information on TLM 2.0 interfaces.

File: tb_env.sv
. . .
`include “vip_slave.sv”
`include “observer.sv”
`include “resp_modifier.sv”
. . .
////////// TB ENVIRONMENT ////////////////
class tb_env extends vmm_group;
`vmm_typename(tb_env)

// VIP Instantiation
vip_slave slv;
. . .

// TLM Port Declaration
observer        obsrv_vip_trans;
resp_modifier trans_mod_xactor;
. . .

// Component Phases
extern virtual function void build_ph();
extern virtual function void connect_ph();
. . .
endclass: tb_env
. . .

////////// Build Phase ////////////////
function void tb_env::build_ph();
. . .
this.slv = vip_slave::create_instance(this, “slv”, `__FILE__, `__LINE__);

//Create observer component
obsrv_vip_trans = new(this, “TRANS_OBSVR”);
// Create the response modifier transactor
trans_mod_xactor = new(this, “RESP_MODIFIER”);
. . .
endfunction: build_ph

/////////// Connect Phase ////////////
function void tb_env::connect_ph();
. . .
// Bind the analysis Port
this.slv.analysis_port.tlm_bind(obsrv_vip_trans.obsrv);
// Bind the transport port
this.slv.b_trans_resp_port.tlm_bind

(trans_mod_xactor.b_trans_resp_export);
. . .
endfunction: connect_ph
. . .

I hope you find this article useful. Please feel free to send me your opinion on this.

Posted in Communication, Structural Components, Transaction Level Modeling (TLM), VMM infrastructure | No Comments »

VMM 1.2 – The Movie

Posted by John Aynsley on 14th January 2010

JohnAynsley

John Aynsley, CTO, Doulos

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

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

Just in time for the holidays: VMM 1.2!

Posted by Janick Bergeron on 15th December 2009

Janick Bergeron
Synopsys Fellow

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

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

A new User’s Guide

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

Implicit Hierarchical Phasing

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

TLM 2.0

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

Object Hierarchy

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

Factory API

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

And many more!

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

Learning more

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

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

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

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

Transaction Level Modeling – Value add in different languages.

Posted by Nasib Naser on 14th December 2009

Nasib_NaserNasib Naser, PhD

Sr. Staff Corporate Applications Engineer – Synopsys

One of the driving factors of creating SystemVerilog is to raise the design verification abstraction level. The reason for such a move is described in the SV LRM Abstract. It says: “A set of extensions to the IEEE 1364-2001 Verilog Hardware Description Language to aid in the creation and verification of abstract architectural level models.” So why and how? The “Why” is obvious. A number of reasons come to mind:

  1. Faster development and simulation to enable reaching design and verification goals sooner than later.
  2. Achieve early closure on architectural decisions without early commitment to implementation details.
  3. Enable running “some” software within the complete system context.
  4. Create an environment in which verification methodologies could be developed that creates true verification IP re-usability and models interoperability.

This blog will discuss the methodology behind the “How.” The technology will be explained in subsequent blogs. Up until vmm 1.2 was released Transaction based models were created by utilizing VMM constructs such as vmm_channel(), vmm_xactor(), and vmm_data() . With all VMM strengths this use model succeeded only on in-house designs and didn’t gain wide modeling adoption. The TLM methodology built into VMM lacked common practices to enable interoperability – emphasis on common practice.

Meanwhile, driven by users, the Open SystemC Initiative aka OSCI TLM community managed to create a standard on which models could be developed for re-use and interoperability. Without dwelling in the past I’d like to give a brief history on the evolution that led to the TLM standard. In the beginning there was C, then C++. For obvious reasons these widely known software languages were used to develop in-house system level models for doing high level performance and architectural analysis. The use model was very limited as the simulation behavior was very far from the actual hardware. It lacks concurrency and timing. C++ extensions augmented with a “proof of concept” simulator was created and called SystemC that enable modeling these hardware behaviors in C++, and more. That worked very well. Failing to replace Verilog and vhdl for design and verification SystemC found its niche use model in the architectural modeling domain. At that point architects using SystemC started to demand a standard that enables interoperability for fast platform composition, ease of use, and re-usability. Hence, the OSCI SystemC Transaction Level Modeling 1.0 and later 2.0 standards were created.

So why re-invent the wheel when it comes to SystemVerilog TLM? And why not adopt a powerful and robust verification methodology such as VMM standard to enable seamless integration between SystemC and SystemVerilog? That’s why features described in the OSCI TLM standard found its way into the SystemVerilog/VMM world. These features are available in the newly released VMM 1.2. Subsequent blogs I will explain these features and the value add they bring into a true IP re-use and interoperable verification methodologies.

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

Blocking Transport Communication in VMM 1.2

Posted by John Aynsley on 10th December 2009

image John Aynsley, CTO, Doulos

One of the new features in VMM 1.2 is the blocking transport interface, borrowed from the SystemC TLM-2.0 standard. This interface provides an alternative to the using the put and get methods of the vmm_channel class when communicating between a producer and consumer. There are a couple of reasons why you might consider using the blocking transport interface in VMM: perhaps you are trying to interface to a SystemC reference model, or perhaps you want to write a transactor that has very clean semantics when it comes to determining the start and end of a transaction. In either case, the new blocking transport interface can help.

A blocking transport call is a method call that carries with it a transaction object and is expected not to return until the transaction is complete. The status of the transaction, that is, whether the transaction succeeded or failed, is expected to be carried within the transaction object itself. You call blocking transport as follows:

class my_tx extends vmm_data; // A user-defined transaction class

enum {OKAY, FAIL} status; // Status flag embedded in the transaction itself
endclass

my_tx tx;
int delay;

$cast(tx, randomized_tx.copy()); // Create and randomize a transaction object

m_port.b_transport(tx, delay);

if( tx.m_status != OKAY ) // Check the response status
`vmm_warning(log, “Transaction failed”);

Since this is SystemVerilog, the transaction object itself is passed by reference. The delay argument instructs the recipient of the transaction to process the transaction after the given delay has elapsed, and can be set by both the caller of and the implementation of the b_transport method.

The blocking transport method needs to be implemented by the transactor that will receive or consume the transaction:

task b_transport(int id = -1, my_tx tx, ref int delay);

// Process transaction

// Pause for given delay and then reset the delay argument
#(delay);
delay = 0;

// Set the response status in the transaction object
tx.m_status = OKAY;
endtask : b_transport

By definition, blocking transport “blocks” until the transaction has been fully processed. It is coded as a SystemVerilog task so that it is allowed to execute timing controls such as the #(delay) in this example. The task is not obliged to suspend for the given delay in this manner; it could have simply returned leaving the delay without modification, or even have increased the value of the delay, leaving it for the caller to realize the delay later. The task is obliged to set the response status flag within the transaction object before returning, and the caller must check the response status on return.

One significant thing that is happening here is that communication between a producer and a consumer (or in TLM-2.0 jargon, an initiator and a target) is being accomplished without having any intervening channel to buffer the transactions. The b_transport method is called by the producer, provided by the consumer, and only returns when the transaction is complete. The advantage of not having an intervening channel is that it can help increase execution speed in the context of a very fast simulation model. The disadvantage is that it is not possible to have multiple transactions in progress given only a single execution thread in the initiator; therefore, it is a good idea to add a semaphore in the implementation of the b_transport method in the target transactor

class target_xactor extends vmm_xactor;

local semaphore m_sem = new(1);

task b_transport(int id = -1, my_tx tx, ref int delay);
m_sem.get(1);
// Process transaction

m_sem.put(1);
endtask : b_transport

This is not the whole story, because we also need to explain how to connect the producer to the consumer. Look out for future blog posts.

Posted in Communication, Reuse, SystemC/C/C++, Transaction Level Modeling (TLM) | 2 Comments »

Developing transactors using VMM 1.2

Posted by Vidyashankar Ramaswamy on 8th December 2009

There are many ways to design and develop a transcator. The following is the way I visualize it. Typical transactor components are shown in the following figure. Based on the functionality, transactor can be grouped into up-stream, down-stream, pass through or a passive monitor types. I shall explain in brief what I mean by these. Up-stream can be a stimulus generator and down-stream can be a bus function master/slave model. A pass through can exists in the test bench to connect a master and the bus function model. A passive monitor simply monitors the bus interface on to which it is connected and broadcasts the packet information whenever it is available. The dotted line in the figure partitions the transactor based on functionality and shows different port connections.

The right side of the dotted line in the above figure represents the upstream. This can be a producer (master or stimulus generator), in which case it can have only output port. This output port is designed as a TLM transport port.

The left side of the dotted line represents the downstream: this can be a slave transactor in which case the receiving port will be a VMM channel. If the downstream transactor is connected to the DUT, then you need to declare a virtual interface and bind it through a port object to the physical interface. This is done from the enclosing environment. This makes the BFM component reusable across test benches. In my next article I shall show you an example about the port object.

If you are designing a pass through transactor, then you need to have both VMM channel for receiving the transaction from the producer and the TLM transport port for sending the transaction to the consumer. Analysis port can be used if any observers are hooked up to this transactor. Also note that you need not have any virtual port connection for a pass through transactor.

A monitor component will have only analysis port along with the physical interface connection.

You might be wondering why the analysis port and the callback interface are centered between up-stream and the down-stream. If you have guessed it, yes you’re right. Both master and slave need to broadcast the information/packet which is passing through them to the observers. The observer can be a scoreboard, coverage collector or a simple file write for debug purposes.

To make the master/slave transactor re-usable, callback methods are used. A callback method allows the user to extend the behavior of a transactor without having to modify the transactor itself. VMM 1.2 supports factory service to replace a transactor. I favor callbacks for transactor extensions. So which one should you use ? I shall leave that up to you to decide and this could be a topic on its own.

Please feel free to comment and share your opinion. For more information please refer to the VMM 1.2 user guide.

Posted in Communication, Structural Components, Transaction Level Modeling (TLM), VMM infrastructure | No Comments »

What Has TLM-2.0 Got To Do With It?

Posted by John Aynsley on 17th November 2009

JohnAynsley

John Aynsley, CTO, Doulos

You may have noticed that the public release of VMM 1.2 is just around the corner, and with this new version of VMM comes the introduction of features inspired by the SystemC TLM-2.0 standard.

Excuse me! TLM-2.0? What? Why do we need features from SystemC in VMM?

I will set out to answer that question fully in a series of blog posts over the coming months. But first off I will remark that the idea is not so strange. After all, VMM has always been transaction-level (with a small ‘t’ and ‘I’). Communication within a VMM verification environment exploits transaction-level modeling for speed and productivity, because “TLM” is about abstracting the model of communication used in a simulation. If we can adopt a common standard for transaction-level modeling across both SystemC and SystemVerilog, that has to be a good thing for everyone. It is evident that the design and verification community demands more than one language standard (witness VHDL, SystemVerilog, C/C++, and SystemC). Each individual language standards has progressed over time by borrowing the best features from the others. Having VMM borrow features from SystemC makes it easier to learn and work with both standards.

The other natural link between VMM and SystemC is that mixed-language simulation environments and C/C++ reference models are not unusual. Virtual platform models, as used for software development and architectural exploration, are growing in importance, and the SystemC TLM-2.0 standard is used to achieve interoperability between the components of a virtual platform model. If a constrained random VMM environment is to be used with a reference model that consists of a virtual platform adhering to the SystemC TLM-2.0 standard, then having TLM-2.0 support within VMM promises to make life easier for the VMM programmer.

Besides interoperability, the other main objective of the SystemC TLM-2.0 standard is simulation speed. The combination of speed and interoperability is achieved by the technical details of the ways in which transactions are passed between components. Fortunately, those technical details are a good fit with the way communication has always worked in VMM. In particular, both VMM and TLM-2.0 support the idea that each transaction has a finite lifetime with a well-defined time-of-birth and time-of-death.

The SystemC TLM-2.0 standard is based on C++. Unfortunately, not all C++ coding idioms translate naturally into SystemVerilog, so the transaction-level communication in VMM 1.2 is “inspired by” the TLM-2.0 standard rather than being a literal rendition of it.

So what are these new features? If you are already a SystemC user you may recognize ports and exports, borrowed directly from the SystemC standard, and analysis ports, transport interfaces, sockets and the generic payload, borrowed from the TLM-2.0 standard. I will explain how VMM is able to exploit each of these features in future blog posts, so watch this space…

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

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

Posted by Shankar Hemmady on 11th November 2009

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

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

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

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

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

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

Feature

Description

vmm_object

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

vmm_unit

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

vmm_timeline

Allows users to coordinate and even define custom phases

vmm_test

Adds support for multi-test management

`vmm_unit_config_xxx

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

vmm_opts

Flexible options handling, command-line or otherwise

vmm_rtl_config

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

vmm_tlm

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

regular expressions

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

`vmm_class_factory

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


Table 1. VMM 1.2 Features

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

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

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

Exclusive Access of VMM Channel

Posted by Shankar Hemmady on 4th September 2009

rahul_shah1 Rahul V. Shah (bio)
Director of Customer Solutions, eInfochips


It is always challenging when it comes to controlled randomization. Constraints may be an easier way to think about it, but at chip level we are often interested in generating a few scenarios which are controlled in specific sequences. However, we still don’t want to develop scenarios that are very directed.

Let’s consider an example: we have an AHB bus interface with different master. We have a DMA controller on the bus along with few other masters. The chip level stress scenario might include multiple master performing data transfer to the memory interface on the bus. The transactions can be completely random. To make the scenario more interesting, we may want to add random reads from the status register, random read of some read only registers along with other data xfer.

One of the scenarios can include handling an error/exception scenario where we want read the status register, followed by the interrupt register followed by a write transfer to clear the interrupt. In the normal scenario, we can generate such scenario in directed fashion. But that will take away the random behavior.

Earlier, such scenarios were implemented in a lot more complex fashion as it was difficult to create a random scenario while getting exclusive access to randomness whenever required. Here I describe a mechanism to get exclusive access to a channel when required, while utilizing the benefits of randomness.

Scenario generators are used to generate a sequence of transactions. Multiple scenario generators may be connected to the same output channel but such a connection does not prevent other generators to concurrently inject transactions to that channel. A scenario is thus not guaranteed the exclusive access to an output channel. Multiple threads in the same multi-stream scenario, or multiple single stream scenarios, or any transactor may inject transactions in the same channel.

If the requirement is to generate a sequence of transactions without any interruption from other generator or from any transactor, an exclusive access of channel can be obtained and later released when exclusive access is no longer required. Let’s consider the scenario below:

01. class my_scenario extends vmm_ms_scenario;
02. rand atm_cell atm_cell_inst ;
03. atm_cell_channel atm_out_chan;
04. int MSC = this.define_scenario(“MY SCENARIO”, 0);
05. local bit [7:0] id;
06.
07. function new();
08. super.new(null);
09. atm_cell_inst = new;
10. endfunction: new
11.
12. task execute(ref int n);
13. $cast(atm_out_chan, this.get_channel(“ATM_SCENARIO_CHANNEL”));
14. atm_out_chan.grab(this);
15. repeat (10) begin
16. atm_out_chan.put(atm_scenario,.grabber(this));
17. repeat (10) @ (posedge clk) ;
18. end
19. atm_out_chan.ungrab(this);
20. endtask: execute
21. endclass: my_scenario

If a scenario requires exclusive access to a channel to ensure the uninterrupted execution of the sequence of transactions, it can grab the channel as shown in line 16, atm_out_chan.grab(this). This will grab the atm_out_chan channel and once grabbed, access of this channel will not be provided to any other scenario until it is explicitly ungrabbed. As shown in lines 15-18, the scenario sends 10 sequential transactions with a delay of 10 clock cycless after grabbing the channel. To inject transactions in the grabbed channel, a reference to the scenario currently injecting the transaction must be provided to the put method as shown in line 16 atm_out_chan.put(atm_scenario,.grabber(this)). After completion of the sequence of transactions, the channel is ungrabbed at line 19 atm_out_chan.ungrab(this).

When the channel is grabbed by one scenario and other scenarios try to put transactions in the same channel, the put method is blocked until the channel is ungrabbed by the scenario who has previously grabbed the channel. To prevent the blocking that would occur as a result of the grabbed channel, we can check the status of the channel using the vmm_channel::is_grabbed() function. This function will return “1”, if the channel is grabbed.

Posted in Communication, Stimulus Generation, Transaction Level Modeling (TLM), Tutorial | No Comments »

How to connect your SystemC Reference Models to your verification VMM based framework

Posted by Shankar Hemmady on 17th August 2009

Nasib_Naser

Nasib Naser, Phd, CAE, Synopsys

In this blog I will discuss the Use Model demonstrated in Figure 1 where a VMM layered testbench is used to verify an RTL DUT against a SystemC transaction level model. SystemVerilog allows for the creation of a reusable layered testbench architectures. The VMM methodology provides the basis for such a layered architecture. With a layered approach, transaction-level reference models can be easily integrated at the appropriate level to provide self-checking functions. In this Use Model the VMM Function layer is communicating with SystemC model using the TLI mechanism to perform read/write transactions, and using the same testbench scenarios the VMM command layer is driving the DUT at pin level.

clip_image002

Figure 1 – VMM driving TLM and RTL with checking

Synopsys’ VCS functional verification solution addresses the challenge of this use model with its SystemC-SystemVerilog Transaction-Level Interface (TLI). Using TLI SystemC interface methods can be invoked in SystemVerilog and vice versa. The **value add** for using TLI is that the SystemVerilog DPI based communication code that synchronizes both domains is automatically generated.

Let’s take a look at the various code components in SystemC and SystemVerilog based on the VMM methodology that enables such a verification use model. In the following example we define the read and write transactions as SC Interface methods.

class Buf_if: virtual public sc_interface {
public:

// do the pure virtual function read()/write() declarations here
virtual void read(unsigned int addr, unsigned int* data) = 0;

virtual void write(unsigned int addr, unsigned int data) = 0;
};

Following code shows VMM Transactor invoking SystemC transactions read and write at function layer. VMM transactor tb_mast is communicating to SystemC TLM using vmm channel tb_mast_out_ch1 and with the RTL model using the vmm channel tb_mast_out_ch2 channel, as shown in the following code:

class tb_master extends vmm_xactor;
virtual tb_if.master ifc;
tb_data_channel tb_master_in_ch;
tb_data_channel
tb_master_out_ch1;
tb_data_channel
tb_master_out_ch2;

extern virtual task main();
endclass: tb_master

task tb_master::main();
tb_data tr, tr_out;
super.main();
forever begin
.
..
// Send the Instruction to SC Reference Model
tb_master_out_ch2.put(tr_out);
// Send the Instruction to RTL
tb_mast_out_ch1.put(tr_out);
end
endtask: main

The following code shows VMM reference Transactors calling the SystemC transaction functions via the adaptor alu_tl_if_adpt_vlog which was automatically generated by VCS TLI.

class tb_ref extends vmm_xactor;

tb_data_channel     tb_ref_in_ch;

alu_tl_if_adpt_vlog alu_tl_if_adpt_vlog_inst0;


extern function new (string instance,
integer stream_id = -1,

tb_data_channel tb_ref_in_ch = null);

extern virtual task main();

endclass: tb_ref

task tb_ref::main();

super.main();

forever begin

case(tr_out.tb_data_type)

SA_SB_OP_GO : begin

alu_tl_if_adpt_vlog_inst0.write(addrA,a);

alu_tl_if_adpt_vlog_inst0.write(addrB,b);

alu_tl_if_adpt_vlog_inst0.write(addrOP,op);

alu_tl_if_adpt_vlog_inst0.read(addrOut,d);

tr_out.data_out = d;
end

endcase

end

endtask

This VCS TLI use model provides a complete and easy way to integrating blocking and non-blocking SystemC reference models into a VMM based multi-layer verification environment.

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