Sie sind auf Seite 1von 26

4/23/2014

.: SystemVerilog | Resources | Methodology:.

Konnect. Innovate. Deliver

Methodology

Introduction to Methodologies

What is a Methodology?

FAQ

SEARCH

SEARCH

APR 23
APR
23

WEDNESDAY

Methodology is a systematic way of doing things with a rich set of standard rules and guidelines. Methodology provides the necessary infrastructure to build a robust, reliable and complete Verification environment.

Why do we go for Verification Methodology?

Methodology shrinks verification efforts with its predefined libraries. It will make your life easier down the road by preventing you from making mistakes or poor decisions whose outcome may not be obvious at the time you made them. It also helps make sure that whatever you do will mesh nicely with what others do (re- usability)

Methodology is basically set of base class library which we can use to build our testbenches.

Let's take a 'simple' example. Suppose you asked to develop 3 VIP/testbench for different blocks. First thing is you will develop all three VIP's using similar structure/architecture (every company follows this). Now think of common classes/functions you will require.

Just for an example consider transaction class. Common functions you will require here is display, compare, copy transactions, isn't it? Now what you will do is, you will keep these common functions in some common area and you will access it in all 3 VIP’s. So this common area is nothing but your 'methodology'.

So the verification giants have already defined such common classes and functions which we will mostly require to build testbenches and have formed one library. That's it; they call this base class library a methodology. Now why 'base' class library? Well you can extend these classes to function it as per your requirement.

Building the testbench environment using Methodologies have following advantages

» Common test bench structure and run flow.

» Reusability.

» Time required to build any testbench is very less.

» Avoids poor coding practices

» Debugging simplicity

» Layered Testbench Architecture

» Debugging simplicity » Layered Testbench Architecture Figure 1 : Advantages of Methodology Figure 2 :

Figure 1 : Advantages of Methodology

Testbench Architecture Figure 1 : Advantages of Methodology Figure 2 : Methodology Based verification

Figure 2 : Methodology Based verification

4/23/2014

.: SystemVerilog | Resources | Methodology:.

These Methodologies include Transaction-based verification (TBV), coverage-driven verification (CDV), Constrained Random Testing (CRT), and Assertion Based Verification (ABV).

Verification Methodology Types

List of verification Methodologies are given below

» AVM Advanced Verification Methodology (System C & Systemverilog) by Mentor Graphics

» RVM Reference Verification Methodology (open Vera) by Synopsys

» OVM Open verification Methodology (systemverilog) by Mentor Graphics

» VMM Verification Methodology Manual (systemverilog) by Synopsys

VMM Using SystemVerilog

To get most of Hardware Verification languages like system Verilog a Methodology is must.

VMM is Verification Methodology Manual using System Verilog defined by Synopsys and ARM

The VMM for SystemVerilog enables its users to build a scalable, predictable and reusable environment enabling users to take full advantage of assertions, reusability, testbench automation, coverage, formal analysis, and other advanced technologies to help solve their RTL and system-level verification problems. Using VMM one can quickly build a layered test bench and each component of VMM can reused. It also gives a consistent look and feel throghout the project .

The VMM for SystemVerilog enables all SoC and IP projects to establish an effective, efficient and predictable verification process that is based upon the experience of leading industry experts from ARM, Synopsys, and their customers.

The broad scope of the VMM for SystemVerilog allows it to cover many verification techniques and show how they can be most effectively used together. The right combination of advanced techniques can improve verification thoroughness, increase verification productivity, accelerate the development process and, over the course of a project, consume fewer resources than brute-force approaches. The VMM for SystemVerilog can both enhance existing approaches and form the basis for a comprehensive verification environment that takes full advantage of constrained random generation, functional coverage and assertions.

Let us start with VMM base classes

The following 8 base classes are available in VMM

vmm_notify : Base class for VMM notification vmm_log : Base class for VMM messaging vmm_data : Base class for VMM data and transactions vmm_channel : Base class for VMM channels and completion models vmm_xactor : Base class for VMM Transactors vmm_env : Base class for VMM verification Environment vmm_atomic_gen : Base class for VMM Atomic Generator vmm_scenario_gen : Base class for VMM Scenario Generator

The VMM components used inside the Test bench

Generator: Generates the transactions either individually or in steams Transactor: Takes High level transactions such as single Ethernet Packet transaction in to multiple Ethernet Packet transaction. Driver : Controls the signals to the DUT it6 executes a single command such as bus read or write or driving Ethernet packet into the DUT Monitor: Bundles the signals from the DUT into transactions. Checker: Compares the output of the DUT, as seen by the Monitor, to the Scoreboard, using a predictor or reference model. Assertions: Constantly check the DUT for correctness. Scoreboard : Stores the transactions from transactors for later comparison

Layered VMM Testbench

from transactors for later comparison Layered VMM Testbench VMM Messaging – overview A testbench produces messages

VMM Messaging – overview

A testbench produces messages of many types and severities

The vmm_log class allows to control

4/23/2014

.: SystemVerilog | Resources | Methodology:.

» which messages are displayed,

» what their format is, and

» Even promote and demote them (useful for error testing).

All messages are sent to standard output, i.e. displayed on the screen and sent to the simulation log file, just like $display.

Message Type

In VMM, every message has a type and a severity. One may want to print a message to

» Debug a piece of code

» Tell the user that simulation reached a notable state, or

» Encountered a problem.

The message type tells which of these is happening

» Failure: Error has been detected

» Note: Simulation progress

» Debug: Optional simulation diagnostics

» Timing: Timing check or error

Severity – describes message importance

Severity levels and the type in parenthesis

Fatal: Functional correctness definitely compromised (Failure) Example: Testbench failure Error: Functional correctness may be compromised (Failure) Example: Actual model results don’t match expected results Warning: Functional correctness not compromised (Failure or Timing). Normal: Regular, expected message. Trace: High-level simulation execution trace message (Debug) Example: "Executing transaction" Debug: Detailed simulation execution trace message (Debug) Verbose: Very detailed simulation execution trace message (Debug) Example: "Sending byte #5 (0x5A)"

vmm_log class

» Each part of the testbench (test ,generator ,checkers ,etc ) uses its own instance of the vmm_log class to generate messages

» Each instance is a separate massage source with a descriptive name and an instance name.

» Use regular expressions to select and control sources.

» Descriptive name – name of the class instantiating vmm_log.

» Instance name –The name of the object or class if there is only single instance

Declaration and instantiations

The vmm_log usually instantiated inside a testbench object such as generator, checker or in a data object.

Vmm_log log = new (“Name”, “instance”)

The name string is the name of the class that contains the log, such as “USB Host”, or “MAC Frame”.

The instance string is the name of this instance of the object such as “Generator 1”, or “Left side”. If there is only a single instance, just use the string “class”.

Log Object Macros

The easiest way to use a vmm_log object is with the macros

`vmm_fatal(vmm_log log, string msg) `vmm_error(vmm_log log, string msg) `vmm_warning(vmm_log log, string msg) `vmm_note(vmm_log log, string msg) `vmm_trace(vmm_log log, string msg) `vmm_debug(vmm_log log, string msg) `vmm_verbose(vmm_log log, string msg)

Examples using Macros

Two examples of using the above message macros.

The first displays a simple string.

The second needs to print variable arguments, so it uses $psprintf, which returns a formatted string.

4/23/2014

.: SystemVerilog | Resources | Methodology:.

`vmm_error (log, $psprintf("Bad data: 0x%h vs. 0x%h",got, expect));

End

Note that these macros expand to several lines, so surround them with begin-end when used in an if-statement.

Message Handling

The messaging class handles each message according to its severity level.

The default is that

» fatal messages cause the simulation to exit,

» error messages increment a global error count, and cause the simulation to exit after 10 errors,

» While all others just print to standard out.

Use the method vmm_log::modify () to change how messages are handled.

Controlling Verbosity

By default, only messages with a severity of NORMAL (vmm_fatal, vmm_error, vmm_warning, vmm_note) or higher are displayed.

This can be controlled in two ways

Using +vmm_log_default

The command line switch +vmm_log_default=DEBUG will enable printing of all messages with

The severity level DEBUG and higher.

Using set_verbosity()

The method vmm_log::set_verbosity() allows to set the level of printing on the fly.

The following code sets the level to DEBUG for any vmm_log object with “Drv” in its name:

log.set_verbosity(log::DEBUG_SEV, "/Drv/", "/./", );

This call overrides the +vmm_log_default switch, and only applies to current vmm_log objects, not any created afterwards.

Create complex, multi-line messages using the vmm_log methods start_msg(), text (), and end_msg().

Change the formatting of vmm_log by extending the vmm_log_format class and register an instance with the vmm_log::set_format method.

VERIFICATION ENVIRONMENT

vmm_env:

Overview:

Testbench goes through many phases of execution, from initialization, simulation, and cleanup.

The class vmm_env helps to manage these steps and ensures that all execute in the proper order.

The new() method should only initialize values, and should never have any side effects such as spawning threads or consuming time.

If a testbench object starts running as soon as new () is called, one will not be able to delay its start, or synchronize it with other testbench operations.

The vmm_env class divides a simulation into the following nine steps, with corresponding methods:

gen_cfg() – Randomize test configuration descriptor build() – Allocate and connect test environment components. reset_dut() – Reset the DUT cfg_dut() – Download test configuration into the DUT start() – Start components wait_for_end() – End of test detection stop() – Stop data generators and wait for DUT to drain cleanup() – Check recorded statistics and sweep for lost data report() – Print final report

Execution Sequence in vmm_env class

Base class run () Dut specific extension

4/23/2014

.: SystemVerilog | Resources | Methodology:.

4/23/2014 .: SystemVerilog | Resources | Methodology:. Simplest Example The top method run () keeps track

Simplest Example

The top method run () keeps track of which steps have executed When run () is called, it runs the remaining ones.

For example, the following program runs all nine steps automatically

program test;

initial begin

verif_env env;

env = new( env.run();

);

end

endprogram

The class verif_env extends vmm_env. When run() is called and it will call all the steps which have not yet been run.

Basic Example

The next example runs the first step, makes a modification to the configuration, and then completes the test.

program test;

initial begin

verif_env env;

env = new(

);

env.gen_cfg(); // Create rand config env.rand_cfg.n_frames = 1; // Only run for 1 frame env.run(); // Run the other steps

end

endprogram

Automatic Sequencing

The run() task is not the only method that executes the steps. As shown in the following example, if build() is called without calling gen_cfg(), the build() method will automatically execute the previous step

program test; initial begin verif_env env; env = new(); env.build(); // Config and build begin my_eth_fr my_fr; my_fr = new(); // Use my own frame env.src[0].rand_fr = my_fr; // Use to build more

end

env.run();

end

endprogram

4/23/2014

.: SystemVerilog | Resources | Methodology:.

Using Vmm_env

»The virtual methods gen_cfg() and build() etc must call their super method as the first step.

» These calls to the base methods contain the sequencing code that ensures all previous steps have been called.

» If calls are left out, the vmm_env class will generate a fatal error at run time.

`include “vmm.sv” class verif_env extends vmm_env; my_cfg cfg; my_gen gen[4]; my_drv drv[4]; my_mon mon[4]; virtual function void gen_cfg(); super.gen_cfg(); // rest of gen_cfg method Endfunction virtual function void build(); super.build(); // rest of build method Endfunction Endclass

DATA AND TRANSACTIONS

Traditional Approach Vs OOP Approach

In traditional testbench the transactions are implemented using procedures one per transaction.

This caused the following problems:

» Code is not self-contained

» Code is not protected properly

» Cannot extend data types

» Cannot add constraints to an existing data type

Instead, model transactions as objects.

Their data values exist in a transaction class that can be randomized, copied, packed, and unpacked.

The code that actually executes the transactions resides in the Driver.

Transaction Coding Guidelines

» Properties in a transaction class should be public so they can be modified or constrained by other classes, such as the testbench.

» Do not hide data values using set () & get () methods.

» In hardware verification, one need access to all parts of the testbench for maximum control.

» Properties should be random by default so that they can be randomized by other classes.

» Can always go back and use rand_mode () to turn this off.

Transactions Vs Transactors

The transaction class contains both physical values that are sent to the DUT (address, data, etc.) and meta-data that has extra information about the transaction, such as a “kind” field.

Even though this might be encoded in the physical values, put it into a separate field that can be easily accessed and can be randomized.

class alu_xactn extends vmm_data; rand reg [7:0] data_in1 ; rand reg [7:0] data_in2 ; rand reg [2:0] select ; rand bit reset_N ; endclass

The Transactor contains the code to send the transaction to the next testbench level.

ID fields

Every transaction has three integer ID fields uniquely identifying it.

» The stream_id tells which stream created this object – useful when there are multiple generators.

» The sequence_id is used when a stream generator creates groups of related transactions, and identifies the group.

» The object_id identifies individual transactions in a sequence.

class vmm_data;

integer stream_id;

integer scenario_id;

integer object_id;

4/23/2014

.: SystemVerilog | Resources | Methodology:.

endclass

In the following example, a constraint block uses the stream_id.

Constraints - Guidelines

Every transaction should have one or more constraint blocks for the “must-obey” constraints that are never turned off or overridden.

For example, they would make sure an integer field is never negative or that a length field is never 0.

» Name these constraints “class_name_valid”,

» Have separate constraints for “should-obey”.

» One can turn these off later for injecting errors.

» Name these constraints “class_name_rule”.

Methods used in VMM transaction class

The vmm_data class defines a set of virtual methods for manipulating its properties.

Make own methods when extending vmm_data.

display() & psdisplay()

These methods display the contents of the class, either to the screen or to string.

Virtual task display (string prefix);

Virtual function string psdisplay (string prefix) ;

allocate()

This method allocates a vmm_data object and initializes required fields.

This is a virtual method, unlike new() so the correct method is called regardless of the handle Type.

Virtual function vmm_data allocate()

copy()

This method makes a copy of an existing transaction. It has an optional “to” field so one can copy to a previously allocated object.

Note that this method returns a vmm_data type, so use $cast () with it.

virtual function vmm_data my_data::copy(vmm_data to = null); my_data cpy; // Copying to a new instance? if (to == null) cpy = new(); else if (! $cast(cpy, to, CHECK)) begin `vmm_fatal(this.log, "Attempting to copy to a non my_data instance"); return; end // Copy ID’s and any other properties cpy.stream_id = this.stream_id; cpy.scenario_id = this.scenario_id; cpy.object_id = this.object_id; // Assign the copy to the return handle copy = cpy; endfunction

compare()

This method compares two objects and reports the difference.

Virtual function bit compare (to, diff, kind);

The current object is compared with “to” using type “kind”.

The method returns 1 if the two objects are the same, 0 if not.

The diff string gives a description of the difference.

The following three methods are used for converting between the physical fields of an object and an array of bytes

byte_size()

virtual function integer byte_size (kind);

The method byte_size tells how many bytes are needed to pack an object of this kind.

4/23/2014

.: SystemVerilog | Resources | Methodology:.

byte_pack();

virtual function integer byte_pack (bytes,offset,kind);

The method byte_pack packs the object of type kind into a dynamic array of bytes.

byte_unpack();

Virtual function integer byte_unpack (bytes,offset,kind);

The method byte_unpack unpacks the data from the dynamic array of bytes.

The offset tells the methods where to start in the byte array.

Notification - Overview

VMM provides an event notification class that allows notifying when an event notification is indicated, and includes data.

These notifiers are based on integer identifiers that hold a symbolic value.

The following code creates three notification identifiers associated with the alu_driver class:

class alu_driver extends vmm_xactor; static integer TR_STARTED; static integer TR_ABORTED; static integer TR_SUCCESS; endclass

Configuring a Notifier

Configure a notifier before using it.

A notifier can be ON_OFF, ONE_SHOT, or BLAST.

The following example calls the configure () method in the notify object (preinstantiated in vmm_xactor), which returns an integer value.

class alu_driver extends vmm_xactor;

function new(

);

this.TR_STARTED = this.notify.configure(*, vmm_notify::ON_OFF);

endtask

endclass

Channels and completion models:

Channels

» Testbench environment needs to exchange transactions between its components.

» For example, transactions flow from the Generator -> Transactor ->Driver, or from the Monitor -> Checker -> Scoreboard.

» Transactions are modeled as objects that are then created and modified by the different testbench components.

» The connection between these components is the VMM channel.

» One side is the producer (such as the Generator) putting transactions into the channel.

» The consumer side (Transactor) gets the transactions out of the channel and executes them.

Channels Vs Mailboxes

» Unlike mailboxes, channels are strongly typed which helps prevent coding errors.

» Channels allow flow control, so the put () method will block if the channel is full.

» A channel can have both high-water and low water marks to fine tune the interactions between the producer and consumer.

» get() method removes the transaction from the end of the channel

» peek () gives a handle to it without removal.

» Both block if the channel is empty.

» The output of a channel can be replicated using the tee() method.

Definition and Creation of Channel

class alu_xactn extends vmm_data;

Endclass // macro automatically creates new data type by // appending "_channel" to data_type_name `vmm_channel(alu_xactn); // alu_xactn_channel declaration program test; initial begin alu_xactn_channel ch; ch = new(“ALU channel”, “class”);

end

endprogram

4/23/2014

.: SystemVerilog | Resources | Methodology:.

Communication using Channel

// Producer forever begin alu_xactn tr = new(); ch.put(tr); end and:

// Consumer forever begin alu_xactn tr = ch.get();

end

Allocate object every time

Just like a SystemVerilog mailbox, the channel contains handles to objects, not the object themselves.

One can modify an object after it has been put in the channel, leading to a common mistake.

// Producer Alu_xactn_channel ch = new(“ ALU channel”, “class”); Alu_xactn tr; tr = new();

while (

void = tr.randomize(); ch.put(tr); end

)

begin

This code only allocates a single cell. It then repeatedly randomizes this cell and puts it in the channel.

The result is that the channel will contain many references to the same object.

The solution is to allocate a new cell every time through the loop.

while (

tr = new(); void = tr.randomize(); ch.put(tr); end

)

begin

Using channels to connect blocks

Just like a SystemVerilog mailbox, the channel contains handles to objects, not the object themselves.

One can modify an object after it has been put in the channel, leading to a common mistake.

// Producer alu_xactn_channel ch = new(“ALU channel”, “class”); alu_xactn tr; tr = new();

while (

void = tr.randomize();

ch.put(tr);

end

)

begin

Transaction Completion

» Synchronize two testbench blocks using a channel.

» Configure the channel with full=1 (the default) so it works like a procedural interface.

» The producer thread blocks when it calls put().

» When the consumer calls get() to remove the transaction from the channel, the producer unblocks so it can create a new transaction.

» In the following example, the consumer first calls peek() to read the transaction, but does not call get() until it is done, thus waking the producer.

// Consumer forever begin tr = ch.peek(); // Read the cell case (tr.kind) { // Process the cell

}

void = ch.get(); // Done, wake up producer

end

Atomic Generator

VMM approach to testbench

» Traditional test benches create stimulus with generators that grow more and more complex as the project progresses, accommodating

4/23/2014

.: SystemVerilog | Resources | Methodology:.

» every variant of stimulus,

» error generation,

» Synchronization, etc.

» This “mother of all generators” can be unstable because of the constant changes, as well as difficult to enhance and maintain.

» In VMM, Tests should tune random generators, not completely rewrite them.

These results in

less code (each test is smaller),

more randomness (all unspecified behavior is random) and

More checking (extra randomness broadens the stimulus).

Typical Generator

class alu_gen extends vmm_xactor;

main();

forever begin alu_xactn tr = new(); void = tr.randomize(); this.ch.put(tr); end endtask endclass

task

With this generator, there is no easy way to randomize cells with different constraints.

Solutions

» One could use the randomize with {} construct, but this would require a separate generator for each test, just what we were trying to avoid.

» One could modify the transaction class, alu_xactn, adding constraints for each test, but this moves the problem to a different file.

» Each of these requires every test writer to edit a common file, with the results applied to every generator / ALU transaction.

» Some test benches have knobs to control the different distributions and cases, but once again, the generator or transaction becomes the bottleneck, growing in

complexity.

» In addition, the testcase is the testbench plus knob files, adding another file to the flow.

Factory Patterns

Factories – Correct Solution

» Create a “factory” that stamps out transactions, then have individual tests feed it different blueprints.

» All the test-specific code is located in the test file, not the generators.

» In fact, one can have multiple factories running in a test, each generating a unique set of stimulus

class factory; alu_xactn blueprint = new(); task run(); while (run) begim alu_xactn tr; void = blueprint.randomize(); $cast(tr, blueprint.copy()); process(tr);

end

endtask

endclass

Changing the blueprint

class my_transaction extends alu_xactn; constraint select_valid {select == 3'b100;} endclass program test; verif_env env; initial begin env = new(); env.build(); begin my_transaction my_tr = new(); env.select.blueprint = my_tr;

end

env.run();

end

endprogram

Benefits

4/23/2014

.: SystemVerilog | Resources | Methodology:.

Tests can modify constraints by

» Making variables non-random

» Turning constraint blocks off

» Add new constraint block

» Re-define constraint blocks

» Add random variables

» Supersede random results with directed data

Transactors

VMM Transactors

» A VMM transactor is just a while loop that reads in transactions from a previous testbench layer, does some processing, and sends out transactions to the next

layer.

» The key is properly starting and stopping the transactors.

» The VMM has several transactor types:

» Active Xactor – Master

» Drives pins, blocks on channel get()

» Reactive Xactor – Slave

» Monitors and drives pins, blocks on signal edges

» Passive Xactor – Monitor

» Monitors pins, blocks on signal edges

» Also – Generator or other Xactors as needed

» Creates transactions, blocks using notification or channel put()

A Basic Transactor

Add code to method main() to process transactions.

The other methods all start with a call to the base method to start and stop this method. For example, vmm_xactor::start_xactor() starts the virtual method main() – Don’t need to do this.

class alu_driver extends vmm_xactor; //start_xactor starts the execution threads virtual task start_xactor; super.start_xactor();

endtask //stops execution threads after currently executing //transaction had completed. Takes effect at next call //to vmm_xactor::wait_if_stopped() virtual task stop_xactor(); super.stop_xactor();

endtask

// resets the xactor’s state and execution threads

virtual task reset_xactor(

);

super.reset_xactor(

);

endtask virtual task main();

endtask

endclass

Stopping an Xactor

The main() method periodically checks to see if the transactor has been stopped by calling wait_if_stopped() as shown below

virtual task main(); forever begin this.wait_if_stopped(); alu_xactn tr = to_driver.get(); this.wait_if_stopped();

end

endtask

The wait_if_stopped() method will block if stop_xactor() has been called.

Different blocks in testbench will define when to stop and what it means.

Should check if the transactor needs to stop after every time-consuming action, such as the call to get () above.

Physical and Virtual Interfaces

4/23/2014

.: SystemVerilog | Resources | Methodology:.

» The SystemVerilog interface groups all relevant physical signals (ports) together,

» A virtual interface is just a pointer to a physical interface.

» One can pass a virtual interface into drivers and monitors.

» Now the testbench can replicate a driver, with each instance using a separate virtual interface so as to drive multiple physical ports.

» If need to synchronize on a clock edge in an interface, use the clocking block in the interface.

» Note that this form does not contain the active edge of the clock signal.

» If the designer changes the edge, just change the interface definition, not every usage of the signal.

OVM VERIFICATION ENVIRONMENT

This Example gives you detailed explanation about OVM verification environment including a Design Under Test (DUT), a Verification Environment and a Test. The Design

is

written in Verilog or VHDL and Verification Environment is developed using SystemVerilog and OVM methodology.

In

traditional Verilog code, modules are the basic building blocks to structure designs and test benches. The recent trend is to use classes to build flexible and

reusable Verification Environment.

The OVM Verification environment consist of OVM components like

» OVM Transactor

» OVM Sequencer

» OVM sequence

» OVM Driver

» OVM Monitor

» OVM Scoreboard

OVM TRANSACTOR

The transactor contains the code to send the transaction to the next test bench level. Here we are creating the basic transaction class alu_item which is extended from OVM base class ovm_sequence_item.

A

transaction is just a collection of related data items that get passed around the verification environment as a single unit.

In

OVM all transactions including sequence item all are derived from the class ovm_transaction. This Example uses the sequencer hence the transaction class must be

derived from ovm_sequence_item class, which is child class of ovm_transaction. The constructor new is passed a string used to build a unique instance name of transaction.

The code snippet for transaction class is as show below.

class alu_item extends ovm_sequence_item; rand reg [ 7:0] data_in1 ; rand reg [ 7:0] data_in2 ; rand reg [ 2:0] select; rand bit reset_N; constraint rest_c1{reset_N == 1'b1;} `ovm_object_utils_begin (alu_item) `ovm_field_int(data_in1 , OVM_ALL_ON) `ovm_field_int(data_in2 , OVM_ALL_ON) `ovm_field_int(select , OVM_ALL_ON) `ovm_field_int(reset_N , OVM_ALL_ON) `ovm_object_utils_end // new constructor function new (string name = "alu transaction instant") ; super.new(name); endfunction endclass

As transactions are created we need to copy, compare, print, pack, and unpack those transactions is done automatically by inbuilt ovm macros as shown below.

`ovm_object_utils_begin (alu_item) `ovm_field_int(data_in1 , OVM_ALL_ON) `ovm_field_int(data_in2 , OVM_ALL_ON) `ovm_field_int(select , OVM_ALL_ON) `ovm_field_int(reset_N , OVM_ALL_ON) `ovm_object_utils_end

The flag OVM_ALL_ON indicates that the given field should be copied printed, included in any comparison for equality between two transactions, and so on.

OVM_SEQUENCER

A sequencer is an advanced stimulus generator that controls the items that are provided to the driver for execution. By default, a sequencer behaves similarly to a

simple stimulus generator and returns a random data item upon request from the driver. This default behavior allows you to add constraints to the data item class in order to control the distribution of randomized values.

4/23/2014

.: SystemVerilog | Resources | Methodology:.

» The alu_sequencer is derived from base class ovm_sequencer parameterizes it to use the alu_item type.

»`ovm_sequencer_utils and `ovm_update_sequence_lib_and_item are used to indicate the generated data item type and field desired automation.

» Call `ovm_update_sequence_lib_and_item macro from the constructor of your sequencer class. This macro registers all the sequence types that are associated

with the current sequencer and indicates the sequencer's generated transaction type as a parameter

class alu_sequencer extends ovm_sequencer #(alu_item) ; //constructor function new(string name , ovm_component parent) ; super.new(name , parent) ; `ovm_update_sequence_lib_and_item(alu_item) endfunction // Provide implementations of virtual methods such as get_type_name and // create `ovm_sequencer_utils(alu_sequencer) endclass

OVM_SEQUENCE

The class alu_seq_do in the following example defines a simple sequence. It is derived from ovm_sequence and uses the `ovm_sequence_utils macro to associate this sequence with alu_sequencer, and to declare the various utilities `ovm_object_utils would provide.

Once you define a sequence, it is registered inside its sequencer and may be generated by the sequencer’s default generation loop. The `ovm_sequence_utils macro creates the necessary infrastructure to associate this sequence with the relevant sequencer type, and declares the various automation utilities. This macro is similar to the `ovm_object_utils macro (and its variations) except that it takes a second argument, which is the sequencer type name, this sequence is associated with.

class alu_seq_do extends ovm_sequence #(alu_item), ; function new(string name = "alu_seq_do") ; super.new(name) ; endfunction `ovm_sequence_utils(alu_seq_do,alu_sequencer) virtual task body() ; `ovm_info(get_name(), $psprintf("In body() of %s",get_name()), 1000) `ovm_do(req) endtask endclass : alu_seq_do

Sequence and Sequence Item Macros

This section describes the sequence and sequence item macros, `ovm_do and `ovm_do_with.

The `ovm_do macro takes as an argument either a variable of type ovm_sequence or of type ovm_sequence_item. An object is created using the factory settings and assigned to the specified variable. Based on the processing when the driver requests an item from the sequencer, the item is randomized and provided to the driver. The body of the sequence invokes an item of type alu_item, using the `ovm_do macro.

OVM_DRIVER

A driver is an active entity that emulates logic that drives the DUT. A typical driver repeatedly receives a data item and drives it to the DUT by sampling and driving the DUT signals.

To create a driver

» Derive a driver from the ovm_driver base class.

» If desired, add OVM infrastructure macros for class properties to implement utilities for printing, copying, comparing, and so on.

» Obtain the next data item from the sequencer and execute it as outlined above.

» Declare a virtual interface in the driver to connect the driver to the DUT.

The class alu_driver in the example below defines a driver class. The example derives alu_driver from ovm_driver (parameterized to use the alu_item transaction type) and uses the methods in the seq_item_port object to communicate with the sequencer. As always, include a constructor and the `ovm_component_utils macro to register the driver type with the common factory.

class alu_driver extends ovm_driver #(alu_item) ; // Provide implementations of virtual methods such as get_type_name and // create `ovm_component_utils(alu_driver) // constructor function new(string name , ovm_component parent ) ; super.new(name,parent) ; endfunction task run (); while(1) begin

#10

seq_item_port.get_next_item(req); `ovm_info("Driver", "printing Recieved item:" , OVM_MEDIUM) req.print(); seq_item_port.item_done() ;

end endtask : run

4/23/2014

.: SystemVerilog | Resources | Methodology:.

endclass : alu_driver

OVM_TEST

This is top level of ovm verification environment which include all instance of transactor, sequencer, driver.

The following Elaboration and simulation steps are followed inside ovm environment

» new() : In this Phase constructor is called.

» build() : In this Phase Create components using new or the factory.

» connect() : In this Phase Make port, export and implementation connections.

» end_of_elaboration() : In This Phase make sure that after all connections have been hardened

» start_of_simulation() : This phase start Just before simulation starts

» run() : This Phase starts the simulation

» extract() , check() , report() : All these are post processing used to extract ,check , give the detail report .

In our Example As shown inside initial block

set_config_string("sequencer" ,"default_sequence", "alu_seq_do") ; will indicate that sequencer has to run alu_seq_do sequence as default sequence.

The build () function is used to Create components using new or the factory.

In connect phase we need to connect driver sequence item port to sequencer item export as show below.

The test is actually started by calling the run_test method.

The simulation can be stopped by calling global_stop_request()

module test ; `include "ovm.svh" `include "alu_xactn.sv" `include "alu_sequencer.sv" `include "alu_driver.sv" `include "alu_seq_lib.sv" alu_sequencer sequencer ; alu_driver driver ; initial begin set_config_string("sequencer" ,"default_sequence", "alu_seq_do") ; sequencer = new("sequencer" , null) ; sequencer.build() ; driver = new("driver", null) ; driver.build(); driver.seq_item_port.connect(sequencer.seq_item_export); ovm_default_printer = ovm_default_tree_printer ; sequencer.print(); driver.print(); fork run_test() ; #2000 global_stop_request(); join end endmodule

UVM article

Introduction

The UVM( Universal Verification Methodology) is started in December 2009, a technical subcommittee of Accellera- a standard organization in the electronic design automation(EDA) industry—voted to establish the UVM and decided to build this new standard using the Open Verification Methodology (OVM-2.1.1) as its foundation. Accellera released version UVM 1.0 EA on May 17, 2010. UVM Class Library provides the building blocks needed to quickly develop well-constructed and reusable verification components and test environments in systemverilog. All three of the simulation vendors (Synopsys, Cadence and Mentor)support UVM today.

UVM library contents are same as that OVM library as mentioned below

1.Component classes for building testbench components like generator/driver/monitor etc.

2. Reporting classes for logging,

3. Factory for object substitution.

4. Synchronization classes for managing concurrent process.

5. Policy classes for printing, copying, recording, packing, and unpacking of uvm_object based classes.

6. TLM Classes for transaction level interface.

7. Sequencer and Sequence classes for generating realistic stimulus.

8. And Macros which can be used for shorthand notation of complex implement

Like in OVM how all above mentioned classes are derived from OVM_object base class in UVM also above mentioned classes are derived from UVM_object base class.

4/23/2014

.: SystemVerilog | Resources | Methodology:.

A more detailed overview of each category and the classes comprising them:

Components

Components form the foundation of the UVM. They encapsulate behavior of drivers, scoreboards, and other objects in a testbench. The UVM library provides a set of predefined component types, all derived directly or indirectly from ovm_component.

Following are some of the UVM component classes.

1. Agent

2. Monitor

3. Scoreboard

4. Driver

5. Sequencer

Reporting

The uvm_report_object provides an interface to the UVM reporting facility. The reporting classes provide a facility for issuing reports (messages) with consistent formatting and configurable side effects, such as logging to a file or exiting simulation. Users can also filter out reports based on their verbosity , unique ID, or severity. If the verbosity level of a report is greater than the configured maximum verbosity level of its report object, it is ignored.

Argument Description

1. unique ID or severity = its an unique id to form a group of messages.

2. verbosity = it mainly indicates the relative importance of particular message.

3. filename/line = we need to include macros like '

FILE

and

LINE

'

if we require filename and line number from where the massage is issued.

Factory

As the name implies, the UVM factory is used to manufacture (create) UVM objects and components. The factory pattern is an well known object-oriented design pattern. Users can configure the factory to produce an object of a given type on a global or instance basis. The factory method design pattern defining a separate method for creating the objects. whose subclasses can then override to specify the derived type of object that will be created. Use of the factory allows dynamically configurable component hierarchies and object substitutions without having to modify their code and without breaking encapsulation.

There are three basic steps to be followed for using uvm factory.

1. Registration = class type has to be registered while defining a class.

2. Construction = here create() should be used to construct uvm based objects.

3. Overriding = user can override the registered classes or objects accroding to the requirement.

Synchronization

The UVM provides event and barrier synchronization classes for process synchronization.

Policies

Each of UVM’s policy classes perform a specific task for ovm_object based objects: printing, comparing, recording, packing, and unpacking. They are implemented separately from uvm_object so that users can plug in different ways to print, compare, etc. without modifying the object class being operated on. The user can simply apply a different printer or compare “policy” to change how an object is printed or compared.

TLM

The UVM TLM library defines several abstract, transaction-level interfaces and the ports and exports that facilitate their use. Each TLM interface consists of one or more methods used to transport data, typically whole transactions (objects) at a time. Component designs that use TLM ports and exports to communicate are inherently more reusable, inter operable, and modular.

Core Base Classes of UVM

The UVM library defines a set of base classes and utilities that facilitate the design of modular, scalable, reusable verification environments. The basic building blocks for all environments are components and the transactions they use to communicate. The UVM provides base classes for these, as shown below.

The UVM provides base classes for these, as shown below. uvm_object http://www.systemverilog.in/method.php#fragment-3

uvm_object

4/23/2014

.: SystemVerilog | Resources | Methodology:.

All components and transactions derive from uvm_object,which defines an interface of core class-based operations: create, copy, compare, print,sprint, record, etc. It also defines interfaces for instance identification (name, type name, unique id, etc.) and random seeding.

uvm_component

The uvm_component class is the root base class for all UVM components. Components are quasi-static objects that exist throughout simulation. This allows them to establish structural hierarchy much like modules and program blocks . Every component is uniquely addressable via a hierarchical path name, e.g.

“env1.pci1.master3.driver”.

The uvm_component also defines a phased test flow that components follow during the course of simulation. Each phase-- build , connect , run , etc.-- is defined by a callback that is executed in precise order. Finally, the uvm_component also defines configuration, reporting, transaction recording, and factory interfaces.

Following example depicts the usage of uvm_component:

class consumer extends uvm_component; uvm_blocking_put_imp #(simple_trans, consumer) put_export; // 2 parameters

task put(simple_trans t); case(t.kind) READ: // Do read. WRITE: // Do write. endcase endtask endclass

uvm_transaction:

The uvm_transaction is the root base class for UVM transactions, which, unlike uvm_components , are transient in nature. It extends uvm_object to include a timing and recording interface. Simple transactions can derive directly from uvm_transaction , while sequence-enabled transactions derive from uvm_sequence_item .

class simple_trans extends uvm_transaction; rand data_t data; rand addr_t addr; rand enum {WRITE,READ} kind; constraint c1 { addr < 16’h2000; }

endclass

uvm_root

The uvm_root class is special uvm_component that serves as the top level component for all UVM components, provides phasing control for all UVM components, and other global services.

uvm_void

The uvm_void class is the base class for all UVM classes. It is an abstract class with no data members or functions. It allows for generic containers of objects to be created, similar to a void pointer in the C programming language. User classes derived directly from uvm_void inherit none of the UVM functionality, but such classes may be placed in uvm_void -typed containers along with other UVM objects.

As all base classes of UVM are from OVM there we do not find much difference between OVM and UVM. Only some new features are added to UVM such as callbacks, report catcher and heartbeat. Features like byte packing,unpacking,transaction id,transaction recording and time of transaction created all these VMM features are now available in UVM. This UVM methodology efficiently uses both OVM and VMM features.

The main differences between OVM and UVM are as mentioned below:

UVM is based on OVM

The deprecated features from OVM were removed in UVM .

The URM and AVM compatibility layers were removed from UVM.

Added a uvm_heartbeat class which allows environments to set up heartbeat criteria to monitor the liveness of the components in the hierarchy.

Callbacks were updated with the following additional functionality:

- A callback iterator class

- Type wide callback support (instead of just instance specific)

- Callback type registration for type checking (added type checking to the add functions to warn if added to a type that doesn't support a specific callback).

- Added add/delete callback by name.

- More callback tracing was added.

Objections were updated with the following additional functionality:

- Added a string description for raise/drop

4/23/2014

.: SystemVerilog | Resources | Methodology:.

- Added ability to add external callbacks to objections.

uvm_report_catcher callback mechanism for reports. Allows messages to be processed and potentially changed. Catcher callbacks can be added globally or to specific report objects using the uvm_callbacks add methods.

uvm_callbacks added support for type wide callbacks by using a null object identifier.

Added better runtime type checking for callbacks to ensure that callbacks are only registered with objects that can use them.

* added type-callback registration macro, `uvm_register_cb.

* added ability to specify inheritance hierarchy of objects using callbacks via the `uvm_set_super_type macro.

Added the ability to configure the global timeout using the configuration mechanism. ovm_top.set_config("","timeout",<value>) will set the timeout value for the task based phases.

Added tracing to the objection mechanism. The tracing can be enabled procedurally with uvm_objection::trace_mode() or can be set via the command line with + UVM_OBJECTION_TRACE.

Added raised, dropped, and all_dropped callbacks to the uvm_objection class. This allows external callbacks to be attached to objections

Detailed explanation of differences :

uvm_heartbeat

Heartbeats provide a way for environments to easily ensure that their descendants are alive. A uvm_heartbeat is associated with a specific objection object. A component that is being tracked by the heartbeat object must raise (or drop) the synchronizing objection during the heartbeat window.

The uvm_heartbeat object has a list of participating objects. The heartbeat can be configured so that all components (UVM_ALL_ACTIVE), exactly one(UVM_ONE_ACTIVE), or any component (UVM_ANY_ACTIVE) must trigger the objection in order to satisfy the heartbeat condition.

Heartbeats provide a way for environments to easily ensure that their descendants are alive.

Methods

new: Creates a new heartbeat instance associated with cntxt.

hb_mode: Sets or retrieves the heartbeat mode.

set_heartbeat: Sets up the heartbeat event and assigns a list of objects to watch.

add: Add a single component to the set of components to be monitored.

remove: Remove a single component to the set of components being monitored.

start: Starts the heartbeat monitor.

stop: Stops the heartbeat monitor.

Explanation of uvm_heartbeat methods :

new:

This will creates a new heartbeat instance associated with context . The context is the hierarchical location that the heartbeat objections will flow through and be monitored at. The objection associated with the heartbeat is optional, if it is left null then the uvm_test_done objection is used.

Syntax

function new(string name , uvm_component cntxt, uvm_objection = null)

hb_mode:

Sets or retrieves the heartbeat mode. The current value for the heartbeat mode is returned. If an argument is specified to change the mode then the mode is changed to the new value.

Syntax

function uvm_heartbeat_modes hb_mode (uvm_heartbeat_modes mode = UVM_NO_HB_MO)

Set_heartbeat

Sets up the heartbeat event and assigns a list of objects to watch. The monitoring is started as soon as this method is called. Once the monitoring has been started with a specific event, providing a new monitor event results in an error. To change trigger events, you must first stop the monitor and then start with a event trigger.

If the trigger event e is null and there was no previously set trigger event, then the monitoring is not started. Monitoring can be started by start.

Syntax:

4/23/2014

.: SystemVerilog | Resources | Methodology:.

Add a single component to the set of components to be monitored. This does not cause monitoring to be started. If monitoring is currently active then this component will be immediately added to the list of components and will be expected to participate in the currently active event window.

syntax

function void add ( uvm_component comp )

remove

Remove a single component to the set of components being monitored. Monitoring is not stopped, even if the last component has been removed (an explicit stop is required).

syntax

function void remove ( uvm_component comp )

start:

Starts the heartbeat monitor. If e is null then whatever event was previously set is used. If no event was previously set then a warning is issued. It is an error if the monitor is currently running and e is specifying a different trigger event from the current event.

syntax:

function void start ( uvm_event e = null )

stop:

Stops the heartbeat monitor. Current state information is reset so that if start is called again the process will wait for the first event trigger to start the monitoring.

syntax:

function void stop ()

uvm_callback

The uvm_callback class is the base class for user-defined callback classes. Typically, the component developer defines an application-specific callback class that extends from this class. In it, he defines one or more virtual methods, called a callback interface, that represent the hooks available for user override.

Methods intended for optional override should not be declared pure.Usually, all the callback methods are defined with empty implementations so users have the option of overriding any or all of them. As mentioned earlier ovm library provide extra features in callback they are explained below:

example: mainly taken out from user guide

virtual class bus_bfm_cb extends uvm_callback; virtual function bit trans_received(bus_bfm driver, bus_tr tr); return 0; endfunction virtual task trans_executed(bus_bfm driver, bus_tr tr); endtask function new(string name="bus_bfm_cb_inst"); super.new(name); endfunction endclass

uvm_callback_iter

The uvm_callback_iter class is an iterator class for iterating over callback queues of a specific callback type. The typical usage of the class is

uvm_callback_iter#(mycomp,mycb) iter = new(this);

for(mycb cb = iter.first(); cb != null; cb = iter.next())

cb.dosomething();

The callback iteration macros, uvm_do_callbacks and uvm_do_callbacks_exit_on provide a simple method for iterating callbacks and executing the callback methods.

The uvm_callback_iter class is an iterator class for iterating over callback queues of a specific callback type.

Class Declaration

class uvm_callback_iter#(type T = uvm_object,type CB = uvm_callback)

Methods:

new:

4/23/2014

first

.: SystemVerilog | Resources | Methodology:.

function CB first()

Returns the first valid (enabled) callback of the callback type (or a derivative) that is in the queue of the context object. If the queue is empty then null is returned.

next

function CB next()

Returns the next valid (enabled) callback of the callback type (or a derivative) that is in the queue of the context object. If there are no more valid callbacks in the queue, then null is returned.

get_cb:

function CB get_cb()

Returns the last callback accessed via a first() or next() call.

Iterator interface:

This set of functions provide an iterator interface for callback queues. A facade class, uvm_callback_iter is also available, and is the generally preferred way to iterate over callback queues.

get_first:

static function CB get_first (ref int itr, input T obj)

returns the first enabled callback of type CB which resides in the queue for obj. If obj is null then the type wide queue for T is searched. itr is the iterator; it will be updated with a value that can be supplied to get_next to get the next callback object. If the queue is empty then null is returned.

The iterator class uvm_callback_iter may be used as an alternative, simplified, iterator interface.

get_next

static function CB get_next (ref int itr, input T obj) returns the next enabled callback of type CB which resides in the queue for obj, using itr as the starting point. If obj is null then the type wide queue for T is searched. itr is the iterator; it will be updated with a value that can be supplied to get_next to get the next callback object. If no more callbacks exist in the queue, then null is returned. get_next will continue to return null in this case until get_first has been used to reset the iterator.

The iterator class uvm_callback_iter may be used as an alternative, simplified, iterator interface.

uvm_callbacks(T,CB):

To enable compile-time type-safety, the class is parameterized on both the user-defined callback interface implementation as well as the object type associated with the callback. The object type-callback type pair are associated together using the uvm_register_cb macro to define a valid pairing; valid pairings are checked when a user attempts to add a callback to an object.

To provide the most flexibility for end-user customization and reuse, it is recommended that the component developer also define a corresponding set of virtual method hooks in the component itself. This affords users the ability to customize via inheritance/factory overrides as well as callback object registration. The implementation of each virtual method would provide the default traversal algorithm for the particular callback being called. Being virtual, users can define subtypes that override the default algorithm, perform tasks before and/or after calling super. to execute any registered callbacks, or to not call the base implementation, effectively disabling that particular hook.

T

This type parameter specifies the base object type with which the CB callback objects will be registered. This object must be a derivative of uvm_object.

CB

This type parameter specifies the base callback type that will be managed by this callback class. The callback type is typically a interface class, which defines one or more virtual method prototypes that users can override in subtypes. This type must be a derivative of uvm_callback.

Add/delete interface

add

static function void add_by_name(string name, uvm_callback cb,uvm_apprepend ordering = UVM_APPEND)

Registers the given callback object, cb, with the given obj handle. The obj handle can be null, which allows registration of callbacks without an object context. If ordering is UVM_APPEND (default), the callback will be executed after previously added callbacks, else the callback will be executed ahead of previously added callbacks. The cb is the callback handle; it must be non-null, and if the callback has already been added to the object instance then a warning is issued. Note that the CB parameter is optional. For example, the following are equivalent:

uvm_callbacks#(my_comp)::add(comp_a, cb);

uvm_callbacks#(my_comp, my_callback)::add(comp_a,cb);

Use of this add is described in the following example:

4/23/2014

.: SystemVerilog | Resources | Methodology:.

initial begin bd_cb::add(driver,cb); cbs.display_cbs(); for (int i=1; i<=5; i++) begin

tr.addr = i; tr.data = 6-i; driver.in.put(tr);

end

end

endmodule

add_by_name

static function void add_by_name(string name, uvm_callback cb, uvm_component root,uvm_apprepend ordering= UVM_APPEND)

Registers the given callback object, cb, with one or more uvm_components. The components must already exist and must be type T or a derivative. As with add the CB parameter is optional. root specifies the location in the component hierarchy to start the search for name. See uvm_root::find_all for more details on searching by name.

delete:

static function void delete(T obj,uvm_callback cb)

Deletes the given callback object, cb, from the queue associated with the given obj handle. The obj handle can be null, which allows de-registration of callbacks without an object context. The cb is the callback handle; it must be non-null, and if the callback has already been removed to the object instance then a warning is issued. Note that the CB parameter is optional. For example, the following are equivalent

uvm_callbacks#(my_comp)::delete(comp_a, cb);

uvm_callbacks#(my_comp, my_callback)::delete(comp_a,cb);

Use of these option are described in following examples: mainly taken out from user guide

virtual task run(); cbs = new;

#1000;

bd_cb::add_by_name(cb, “top.bfm”);

#100;

bd_cb::delete(cb);

endfunction

endclass

uvm_report_catcher

The uvm_report_catcher is used to catch messages issued by the uvm report server. Catchers are uvm_callbacks(uvm_report_object,uvm_report_catcher) object, so all facilities in the uvm_callback and uvm_callback#(T,CB) classes are available for registering catchers and controlling catcher state. The uvm_callbacks# (uvm_report_object,uvm_report_catcher) class is aliased to uvm_report_cb to make it easier to use. Multiple report catchers can be registered with a report object. The catchers can be registered as default catchers which catch all reports on all uvm_report_object reporters, or catchers can be attached to specific report objects (i.e. components).

User extensions of uvm_report_catcher must implement the catcher method in which the action to be taken on catching the report is specified. The catch method can return CAUGHT, in which case further processing of the report is immediately stopped, or return THROW in which case the (possibly modified) report is passed on to other registered catchers. The catchers are processed in the order in which they are registered.

On catching a report, the catch method can modify the severity, id, action, verbosity or the report string itself before the report is finally issued by the report server. The report can be immediately issued from within the catcher class by calling the issue method.

The catcher maintains a count of all reports with FATAL,ERROR or WARNING severity and a count of all reports with FATAL, ERROR or WARNING severity whose severity was lowered. These statistics are reported in the summary of the uvm_report_server.

This example shows the basic concept of creating a report catching callback and attaching it to all messages that get emitted

mainly taken out from user guide

class my_error_demoter extends uvm_report_catcher; function new(string name="my_error_demoter"); super.new(name); endfunction //This example demotes "MY_ID" errors to an info message function action_e catch(); if(get_severity() == UVM_ERROR && get_id() == "MY_ID") set_severity(UVM_INFO); return THROW; endfunction endclass

4/23/2014

.: SystemVerilog | Resources | Methodology:.

initial begin // Catchers are callbacks on report objects (components are report // objects, so catchers can be attached to components). // To affect all reporters, use null for the object uvm_report_cb::add(null, demoter); // To affect some specific object use the specific reporter uvm_report_cb::add(mytest.myenv.myagent.mydriver, demoter); // To affect some set of components using the component name uvm_report_cb::add_by_name("*.*driver", demoter);

end

type-callback registration macro:

`uvm_register_cb:

Registers the given CB callback type with the given T object type. If a type-callback pair is not registered then a warning is issued if an attempt is made to use the pair (add,delete, etc.).

The registration will typically occur in the component that executes the given type of callback. For instance:

virtual class mycb; virtual function void doit(); endclass class my_comp extends uvm_component; `uvm_register_cb(my_comp,mycb)

task run;

`uvm_do_callbacks(my_comp, mycb, doit()) endtask endclass

`uvm_set_super_type macro

Defines the super type of T to be ST. This allows for derived class objects to inherit type wide callbacks that are registered with the base class. The registration will typically occur in the component that executes the given type of callback. For instance:

virtual class mycb; virtual function void doit(); endclass class my_comp extends uvm_component; `uvm_register_cb(my_comp,mycb)

task run;

`uvm_do_callbacks(my_comp, mycb, doit()) endtask endclass class my_derived_comp extends my_comp; `uvm_set_super_type(my_derived_comp,my_comp)

task run;

`uvm_do_callbacks(my_comp, mycb, doit()) endtask endclass

Tracing objection

Tracing of objection activity can be turned on to follow the activity of the objection mechanism. It may be turned on for a specific objection instance with uvm_objection::trace_mode, or it can be set for all objections from the command line using the option +UVM_OBJECTION_TRACE.

trace_mode

function bit trace_mode (int mode = -1 )

Set or get the trace mode for the objection object. If no argument is specified (or an argument other than 0 or 1) the current trace mode is unaffected. A trace_mode of 0 turns tracing off. A trace mode of 1 turns tracing on. The return value is the mode prior to being reset.

Callback Hooks

raised

The raised callback is called when a descendant of the component instance raises the specified objection . The source_obj is the object which originally raised the object. count is an optional count that was used to indicate a number of objections which were raised.

virtual function void raised (uvm_objection objection,uvm_object source_obj,string description,int count )

dropped

4/23/2014

.: SystemVerilog | Resources | Methodology:.

The dropped callback is called when a descendant of the component instance raises the specified objection . The source_obj is the object which originally dropped the object. count is an optional count that was used to indicate a number of objections which were dropped.

virtual function void dropped (uvm_objection objection,uvm_object source_obj,string description,int count )

A typical use model of objections is for a sequence from an active agent to raise an uvm_test_done objection when it is started as a root sequence (a sequence which has no parent sequence), and to drop the objection when it is finished as a root sequence. This would look like the following:

mainly taken out from user guide

class interesting_sequence extends uvm_sequence#(data_item); task pre_body(); // raise objection if started as a root sequence uvm_test_done.raise_objection(this); endtask task body(); /do interesting activity

endtask task post_body(); // drop objection if started as a root sequence uvm_test_done.drop_objection(this); endtask endclass

all_dropped:

The all_dropped callback is called when a descendant of the component instance raises the specified objection . The source_obj is the object which originally all_dropped the object. count is an optional count that was used to indicate a number of objections which were dropped. This callback is time-consuming and the all_dropped conditional will not be propagated up to the object’s parent until the callback returns.

virtual task all_dropped (uvm_objection objection,uvm_object source_obj,string description,int count )

UVM EXAMPLE

UVM, a new verification methodology has more features in developing a verification environment than previous methodologies like OVM and VMM. A verification environment, which is reusable is composed of bus-functional modules called verification components. Each verification component follows consistent architecture and encapsulates a complete set of elements for stimulating, checking, and collecting coverage information for a specific design.

Following example projects a detailed information on building of a UVM based environment for specified design. The design is written in verilog and the verification environment for that design is created using the UVM methodology.

UVM Components

A UVM environment basically has the following components.

1. UVM Transactor

2. UVM Sequencer

3. UVM Sequence

4. UVM Driver

5. UVM Monitor

All these components instantiated in environment, named as UVM environment are connected through interface.

1. UVM Transactor

This is a component which sends stimulus to rest of the testbench. Here, all properties which are very much necessary in developing further environment will be specified.

All UVM related transaction methods are derived form uvm_transaction. This class(uvm_transaction) extends from the base class uvm_object to include a timing and recording interface. Here sequence enabled transactions are derived mainly from uvm_sequence_item while simple transactions are derived from uvm_transaction.

The example below illustrates the use of uvm_sequence_item for transaction of a simple vending machine.

class ven_seq_do extends uvm_sequence #(xctor) ; rand intrst; rand int data; function new(string name="ven_seq_do") ; super.new(name) ; endfunction `uvm_sequence_utils_begin(ven_seq_do,sequencer) `uvm_field_int(rst,UVM_ALL_ON) `uvm_field_int(data,UVM_ALL_ON) `uvm_sequence_utils_end virtual task body() ; `uvm_info(get_type_name(),"Starting simple sequence", UVM_LOG); for(int i=0; i<=5; i++)

4/23/2014

.: SystemVerilog | Resources | Methodology:.

begin

$display("%0t :///////////////////// simple seq started ///////////////////////",$time); `uvm_do(req) $display("%0t :///////////////////// simple seq item done ///////////////////////",$time);

end endtask endclass : ven_seq_do

We have inbuilt macros in UVM to perform some transaction level operations like copy, compare, print, pack, unpack. In this example, the field macros used within uvm_*_utils_begin and uvm_*_utils_end are shown.

2. UVM Sequencer

The sequencer generates stimulus data and passes it to a bus functional module for execution. The UVM class library provides the uvm_sequencer, a base class, which is parameterized by the request and response item types.

Creating a sequencer:

1. Derive a sequencer from uvm_sequencer base class by specifying the request and response type parameters.

2. Use `uvm_updates_sequence_lib_and_item to indicate generated data type.

Example below shows a sequencer

Following points are important for sequencer:

1. Should not use uvm_component_utils for this sequencer since all the methods related to sequencer are embedded in uvm_sequencer_utils. So use of

uvm_sequencer_utils is efficient.

2. `uvm_updates_sequence_lib_and_item should be used within a constructor of sequencer. This macro register all the sequence types that are associated with

current sequencer.

Each `uvm_field_* macro has two arguments like ARG and FLAG

ARG is the instance name of the variable. The variables rst and data are an example.

FLAG as shown is UVM_ALL_ON signifies that ARG will undergo all kinds of methods. Use of UVM_DEFAULT is also allowed.

UVM sequence

This class defines a simple sequence. The sequence-specific macros perform the same function as the set of `uvm_object_*_utils macros, except they set the default sequencer type and the sequence will run on.

This class is derived from uvm_sequence base class. This class must use the `uvm_sequence_utils. This `uvm_sequence_utils provides necessary environment for sequence to get associated with relevant sequencer type and declares various automation utilities.

Example for uvm_sequence

Methods of uvm_sequence:

`uvm_do: This method takes uvm_sequence_item as an argument and does the randomization.

body() : This function specifies the randomization of the uvm_sequence_item transactions.

UVM Driver

The driver's role is to request a data from sequencer and drive the same to interface. The UVM class library provides uvm_driver base class from which all driver classes will be inherited.

Creating a driver:

1. Derive a driver from the uvm_driver base class

2. Implement utilities in driver if required

3. Declare a virtual interface in the driver to connect the driver to the DUT.

Methods

run() : This task does the actual work of driver. In the following example , seq_item_port, a command through which the driver sends a request to sequencer to obtain a transaction. On the contrary, get_next_item(req) gets an actual transaction from a sequence.

Example for driver

class driver extends uvm_driver #(xctor) ; protected virtual intf i_f; xctor req; `uvm_component_utils(driver) function void assign_vi (virtual interface intf if1); this.i_f = if1; endfunction virtual task run (); $display("INSIDE RUN : DRIVER CLK = %x\n",i_f.clk); fork

4/23/2014

.: SystemVerilog | Resources | Methodology:.

drive_signal(); join endtask : run task drive_signal(); forever begin @(posedge i_f.clk) seq_item_port.get_next_item(req); print(); req.print(); i_f.rst = req.rst; i_f.coin = req.data; if(i_f.coke == 1) begin

disp();

end

seq_item_port.item_done();

end endtask : drive_signal task disp(); $display("-------------------------------------------------------------------------------------------"); $display("\n"); $display("the time at which the coke is available is = %0gs",$time); $display(" AVAILABLE=%d $display("\n"); $display("-------------------------------------------------------------------------------------------"); endtask endclass : driver

COKE

IS

",i_f.coke);

UVM Monitor

The monitor is responsible for extracting signal information from the bus and translating it into events and status information. The monitor functionality should be limited to basic monitoring which is always required.

The following example shows a simple monitor which has the functions that collects the bus information through the virtual interface.

class monitor extends uvm_monitor; virtual interface intf m_if; function new(string name,uvm_component parent); super.new(name,parent); endfunction `uvm_component_utils(monitor) function void assign_vi(virtual interface intf m_if); this.m_if = m_if; endfunction virtual task run(); forever begin

@(posedge m_if.clk)

print();

begin

$display("@ time %0gs the rst is = %b",$time,m_if.rst); $display("@ time %0gs the data is = %b",$time,m_if.coin); $display("============================================\n"); $display(" Time \t output \t value \n"); $display("@ %0gs\t coke \t %b \n",$time,m_if.coke); $display("============================================\n");

end

end endtask endclass : monitor

The collection is done in a task run() phase. It runs in an endless loop and collects the data as soon as the signals indicate that the data is available on the bus.

UVM Environment:

After creating the transaction level verification component, this section describes how to assemble these components into environment. Environment class is the container of reusable components. It configures and connects all components.

Example for the environment:

Below example shows the phase build() where all components are constructed.

It connects the all the components through interface in a function assign_if.

4/23/2014

.: SystemVerilog | Resources | Methodology:.

sequencer seq; driver dri; `uvm_component_utils_begin(env) `uvm_component_utils_end function new(string name , uvm_component parent); super.new(name,parent); endfunction : new function void build(); $display("INSIDE BUILD CREATE AN OBJECT"); mon = monitor :: type_id :: create("mon",this); $display("INSIDE BUILD CREATE AN OBJECT"); dri = driver :: type_id :: create("dri",this); $display("INSIDE BUILD CREATE AN OBJECT"); seq = sequencer :: type_id :: create("seq",this); endfunction : build function void assign_vi(virtual interface intf vif); this.i_f = vif; mon.assign_vi(vif); seq.assign_vi(vif); dri.assign_vi(vif); endfunction endclass : env

UVM Testcase

The uvm_test class defines the test scenario for the testbench specified in the test. The test class enables configuration of the testbench and environment class as well as utilities for command-line test selection. Tests in UVM are classes that are derived from an uvm_test class. Using classes allows inheritance and reuse of tests.

Instantiating the reusable environment directly inside the tests has several drawbacks:

1. The test writer must know how to configure the environment.

2. Changes to the topology require updating multiple test files, which can turn into a big task.

3. The tests are not reusable because they rely on a specific environment structure.

Example for a testcase is shown below:

class ven_test extends uvm_env; env env1; `uvm_component_utils(ven_test) function new(string name, uvm_component parent); super.new(name,parent); endfunction virtual function void build(); env1 = env :: type_id :: create("env1",this); endfunction : build function void connect();

env1.dri.seq_item_port.connect(env1.seq.seq_item_export);

env1.assign_vi(ven_top.i_if);

endfunction : connect task run();

#10000

global_stop_request();

endtask

endclass

Methods

It has phases like

build() :Creation of environment .

connect() :Connection of driver and sequencer .

run() :To exercise stimulus and a global request is issued to stop the further transaction.

Top module

It is the top module of an entire verification environment. It is where the actual DUT and interface are instantiated.

4/23/2014

.: SystemVerilog | Resources | Methodology:.

clk(i_if.clk), coin(i_if.coin), coke(i_if.coke) ); initial begin uvm_report_info("TB", "/////////////////////Starting out testbench/////////////////// \n", , "uday.txt", 2); run_test();

end initial begin

i_if.clk=1;

end always #5 i_if.clk = ~i_if.clk; endmodule : ven_top

Number of Visits:

here to download the UVM example FEEDBACK Number of Visits: © 2013 Systemverilog.in, AllRights Reserved, Emailus:

© 2013 Systemverilog.in, AllRights Reserved, Emailus: sv@kacpertech.com

Site best viewed in 1024 * 768px or more

Powered by