Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                

SystemVerilog FAQ

Download as docx, pdf, or txt
Download as docx, pdf, or txt
You are on page 1of 268
At a glance
Powered by AI
The key takeaways from the document are that randomize() is used to randomize variables in a class while std::randomize() is used to randomize variables without a class. Pre_randomize and post_randomize are not virtual methods but behave like virtual methods. Randcase is a case statement that randomly selects one of its branches based on weight assignments.

Variables in an object are randomized using the randomize() class method. However, std::randomize() is used to randomize data without a class. Ultimately, randomize() is a virtual method of a class while std::randomize() does not require a class.

No, pre_randomize and post_randomize are not virtual methods but behave like virtual methods because they are called by the virtual randomize() method.

Saturday, 16 April 2016

SystemVerilog FAQ1

What happens if I randomize variable var1 using constraint cn {0 < var1 < 100;}?
The solver considered the this constraint as (0 < var1) || (var1 < 100), so result will not be as
expected.
Ex1: value 500: It is not less than 100 but it is greater than 0,
Ex2: value -1: It is not greater than 0 but it is less than 100.
To solve this issue use one of the following way,
1. Use inside operator like, constraint cn {var1 inside {[1:99]};}
You cant use constraint cn {var1 inside {(0:100)};} -> Wrong Syntax
2. Constraint cn {var1 >0; var1 < 100}

What are bi-directional constraints?


Constraints by-default in SystemVerilog is bi-directional. That implies that the constraint solver
doesn't follow the sequence in which the constraints are specified. All the variables are looked
simultaneously. Even the procedural looking constrains like if ... else ... and -> constrains, both if
and else part are tried to solve concurrently.

So, all the variables are randomized simultaneously,


typedef enum {low, mid, high} AddrType;
class MyBus extends Bus;
rand bit [15:0] addr;
rand AddrType atype;
constraint addr_range {
(atype == low ) -> addr inside { [0 : 15] };
(atype == mid ) -> addr inside { [16 : 127]};
(atype == high) -> addr inside {[128 : 255]};
}
endclass
So as shown in above example, the value chosen for addr depends on atype and how it is
constrained, and the value chosen for atype depends on addr and how it is constrained.

What is circular dependency?


Too many explicit variable ordering in randomization may lead to circular dependency. The
LRM says that "Circular dependencies created by the implicit variable ordering shall result in an
error." and "circular dependency is not allowed". But it does not put restriction on what to do if
an explicit circular dependency exists.
...
int x, y, z;
constraint XYZ {
solve x before y;
solve y before z;
solve z before x;
....
}

What is solve...before constraint?


By default Constraint solver tried to randomize all variables simultaneously.
In the case where the user want to specify the order in which the constraints solver shall solve the
constraints, the user can specify the order via solve before construct.

What is the difference between randomize() and std::randomize() method?


Variables in an object are randomized using the randomize() class method. Every class has a
built-in randomize() virtual method. However, std::randomize() is a mechanism to randomize
data that do not belong to a class.
Ultimately, randomize() is a virtual method of class, so classs variables are randomized using
randomize() method while std::randomize() is used when you want to randomize variable
without writing class and creating its object.

Are pre_randomize/post_randomize methods virtual?


No. The pre_randomize() and post_randomize() methods are not virtual. However, because they
are automatically called by the randomize() method, which is virtual, so they appear to behave as
virtual methods.
Below example demonstrates that these functions are not virtual but simulation results show that,
it executed extended class definition functions. Extended class object is created and assigned to
base class object. Calls to pre_randomize and post_randomize calls in object B, executed the
extended class definitions.
-----------------------------------------------------------------------------------------------
class Base;
function void pre_randomize;
$display(" BASE PRE_RANDOMIZATION ");
endfunction
virtual function void post_randomize;
$display(" BASE POST_RANDOMIZATION ");
endfunction
endclass
class Extend extends Base;
function void pre_randomize;
$display(" EXTEND PRE_RANDOMIZATION ");
endfunction
function void post_randomize;
$display(" EXTEND POST_RANDOMIZATION ");
endfunction
endclass

program pre_post_17;
Base B ;
Extend E = new();
initial begin
B=E;
void'(B.randomize());
void'(E.randomize());
end
endprogram

//Output:
// Error-[SV-IBCMO] Illegal built-in class method override
// Built-in class method 'post_randomize' cannot be overridden as 'virtual'.
view raw pre_post_randomize_1.sv hosted with by GitHub
-----------------------------------------------------------------------------------------------
By removing the virtual keyword for the post_randomize() function, calling the randomize()
function by parent and child class, both will execute functions of child class only. This is virtual
function behaviour.
-----------------------------------------------------------------------------------------------
class Base;
function void pre_randomize;
$display(" BASE PRE_RANDOMIZATION ");
endfunction
function void post_randomize;
$display(" BASE POST_RANDOMIZATION ");
endfunction
endclass

class Extend extends Base;


function void pre_randomize;
$display(" EXTEND PRE_RANDOMIZATION ");
endfunction
function void post_randomize;
$display(" EXTEND POST_RANDOMIZATION ");
endfunction
endclass

program pre_post_17;
Base B ;
Extend E = new();
initial begin
B=E;
void'(B.randomize());
void'(E.randomize());
end
endprogram

//Output:
// EXTEND PRE_RANDOMIZATION
// EXTEND POST_RANDOMIZATION
// EXTEND PRE_RANDOMIZATION
// EXTEND POST_RANDOMIZATION
view raw pre_post_randomize_2.sv hosted with by GitHub
-----------------------------------------------------------------------------------------------

Does post_randomize() is called if randomize() method is failed?


No.

How to randomize string variable?


String variable cannot be randomized directly using randomize method.
-----------------------------------------------------------------------------------------------
class rand_str;
string str;
rand int unsigned str_lngth;
rand char c[];

constraint cn_l {
str_lngth inside {[6:8]};
}
constraint cn_c {
c.size == str_lngth;
}
constraint cn_c1 {
foreach (c[i]) {
c[i] inside {[65:122]};
}
}
constraint order {
solve str_lngth before c;
}

function void post_randomize();


foreach (c[i]) begin
this.str = {str, string'(c[i])};
end
endfunction
endclass
module top();
rand_str R;
initial begin
R = new();
if (R.randomize()) begin
$display ("R.str=%s", R.str);
end
else begin
$error ("Randomization Failed");
end
end
endmodule

//Output:
// R.str=zsyF_]D
view raw rand_string.sv hosted with by GitHub
-----------------------------------------------------------------------------------------------

How to randomize real variable?


Using randomize() method we can randomize only integral data-type variables only (bit, logic,
reg, wire, integer, enum, packed struct)
Here I show two ways to randomize variable of type real.
-----------------------------------------------------------------------------------------------
class rand_real_c;
rand bit [63:0] b;
real r;
function void post_randomize();
this.r = $bitstoreal(b);
endfunction
endclass

module top();
rand_real_c R;
initial begin
R = new();
if (R.randomize()) begin
$display ("R.b=%0d, R.r=%e", R.b, R.r);
end
else begin
$error ("Randomization Failed");
end
end
endmodule

//Output:
// R.b=9322325283763399790, R.r=-4.601070e-302
view raw bitstoreal_1.sv hosted with by GitHub
-----------------------------------------------------------------------------------------------
-----------------------------------------------------------------------------------------------
class rand_real_c;
rand integer i, j;
real r;
function void post_randomize();
this.r = $bitstoreal({i, j});
endfunction
endclass

module top();
rand_real_c R;
initial begin
R = new();
if (R.randomize()) begin
$display ("R.i=%0d,, R.j=%0d, R.r=%e", R.i, R.j, R.r);
end
else begin
$error ("Randomization Failed");
end
end
endmodule

//Output:
// R.i=727460974,, R.j=-2124444300, R.r=8.050506e-100
view raw bitstoreal_2.sv hosted with by GitHub
-----------------------------------------------------------------------------------------------

Without using randomize method or rand, generate an array of unique values?


...

int UniqVal[10];

foreach(UniqVal[i]) begin

UniqVal[i] = i;

end

UniqVal.shuffle();

Can I use randc variable inside solve...before constraint?


The following restrictions apply to solve...before:

1) Only random variables are allowed, that is, they shall be rand.
2) randc variables are not allowed. randc variables are always solved before any
other.

Write code to generate one-hot random variable having length of 5 bit.


-------------------------------------------------------------
// Randmly generate one_hot variable having length of 5 bit
class rand_onehot #(int unsigned L = 5);
rand int unsigned a;
logic [L-1:0] one_hot;

constraint cn_1 {
a >= 0; a < L;
}

function void post_randomize();


one_hot = (1 << a);
endfunction
endclass

module top();
rand_onehot OH;
initial begin
repeat (5) begin
OH = new();
if (OH.randomize()) begin
$display ("OH.a=%0d, OH.one_hot=%b", OH.a, OH.one_hot);
end
else begin
$error ("Randomization failed");
end
end
end
endmodule

//Output:
// OH.a=1, OH.one_hot=00010
// OH.a=3, OH.one_hot=01000
// OH.a=2, OH.one_hot=00100
// OH.a=2, OH.one_hot=00100
// OH.a=1, OH.one_hot=00010
view raw one_hot.sv hosted with by GitHub

-------------------------------------------------------------

Write code to generate two-hot random variable having length of 5 bit.


-------------------------------------------------------------
// Randmly generate Two-hot (Having 2 one) variable having length of 5 bit
class rand_twohot #(int unsigned L = 5);
rand int unsigned a;
rand int unsigned b;
logic [L-1:0] two_hot;

constraint cn_1 {
a != b;
a >= 0; a < L;
b >= 0; b < L;
}

function void post_randomize();


two_hot = (1 << a) | (1 << b);
endfunction
endclass

module top();
rand_twohot TH;
initial begin
repeat (5) begin
TH = new();
if (TH.randomize()) begin
$display ("Th.a=%0d, TH.b=%0d, TH.two_hot=%b", TH.a, TH.b, TH.two_hot);
end
else begin
$error ("Randomization failed");
end
end
end
endmodule

//Output:
// Th.a=3, TH.b=4, TH.two_hot=11000
// Th.a=1, TH.b=4, TH.two_hot=10010
// Th.a=3, TH.b=1, TH.two_hot=01010
// Th.a=2, TH.b=1, TH.two_hot=00110
// Th.a=3, TH.b=4, TH.two_hot=11000
view raw two_hot.sv hosted with by GitHub

-------------------------------------------------------------

How to randomize dynamic unpacked array?

1. Randomize size of dynamic array, its contents will be automatically randomized and
assigned.
2. Randomize size of dynamic array, then randomize content of dynamic array in
post_randomize method.

class ABC;

// Dynamic array

rand bit [7:0] data [];

// Constraints

constraint cc {

// constraining size

data.size inside {[1:10]};


// constraining individual entry

data[0] > 5;

// All elements

foreach(data[i])

if(i > 0)

data[i] > data[i-1];

endclass : ABC

What will be the output of following Code?


-------------------------------------------------------------
class base;
rand int a;
constraint c1 {
a > 0;
}
endclass : base

class child extends base;


constraint c2 {
a < 0;
}
endclass : child

class test;
base B;
child C;

function void abc();


C = new();
B = C;
if (!B.randomize()) begin
$error ("Randomization failed");
end
else begin
$display ("Randomization passed");
end
endfunction : abc
endclass : test

module top();
test T;
initial begin
T = new();
T.abc();
end
endmodule : top

//Output:
// Constraint failure
view raw constraint_with_polymorphism_ex1.sv hosted with by GitHub
-------------------------------------------------------------

How to resolve it?


Need to turn off constraint of Base class.

How to turn off that constraint?


-------------------------------------------------------------
class base;
rand int a;
constraint c1 {
a > 0;
}
endclass : base

class child extends base;


constraint c2 {
a < 0;
}
endclass : child

class test;
base B;
child C;

function void abc();


C = new();
B = C;
B.c1.constraint_mode(0); // Turn OFF constraint of Base class as handld is of Base class
//B.c2.constraint_mode(0); // Using handle of Base class, can't turn OFF constraint which
// is defined in Child class even though handle of Base class
// points to object of Child class
if (!B.randomize()) begin
$error ("Randomization failed");
end
else begin
$display ("Randomization passed");
end
endfunction : abc
endclass : test

module top();
test T;
initial begin
T = new();
T.abc();
end
endmodule : top

//Output:
// Randomization passed
view raw constraint_with_polymorphism_ex2.sv hosted with by GitHub

-------------------------------------------------------------

Saturday, 16 April 2016


SystemVerilog FAQ2

What is the difference between void and null pointer?


So, once again, null pointer is a value, while void pointer is a type.
Null pointer is a special reserved value of a pointer. A pointer of any type has such a reserved
value.
A null pointer is one which is not pointing to anything,
Void pointer is a specific pointer type - void * - a pointer that points to some data location in
storage, which doesn't have any specific type.

Do we need to call super.new() when extending class? What happens if we dont call?
A super.new call shall be the first statement executed in the constructor.
This is because the superclass shall be initialized before the current class and, if the user code
does not provide an initialization, the compiler shall insert a call to super.new automatically.

What is the difference between initial block and final block?


Initial block is getting executed at start of simulation while Final block is getting executed at
end of simulation.
Both of them gets executed only once during the simulation
You can schedule an event or have delay in initial block But you cant schedule an event or have
delay in final block.

What is the use of abstract class?


Using abstract class you can Not only define a template for child, but Abstract Classes offer the
added benefit of letting you define functionality that your child classes can utilize later.

A base class may be characterized as being abstract by identifying it with the keyword virtual:
virtual class BasePacket;
...
endclass
An object of an abstract class shall not be constructed directly. Its constructor may only be called
indirectly through the chaining of constructor calls originating in an extended non-abstract object
A virtual method in an abstract class may be declared as pure virtual.

Where to use abstract class and where to use interface class?


Abstract Class Interface Class

Abstract Classes are a good fit if you want to provide Interface classes are good if
implementation details to your child but don't want to allow an you want to provide only
instance of your class to be directly instantiated (which allows you templates to child class
to partially define a class).

You can only extend one abstract class. you can implement as many
interface classes as you
want.

methods of abstract can be virtual or pure virtual methods of interface class


shall be pure virtual

How you call task in derived class which is defined in parent class?

1. If derived class overrides the task then you can call parent classs task using super.
2. If derived class does not override the task then you can call parent classs task directly be
using name of task

How to check whether a handle is holding object or not?


Check it special string called null.

What is "this"?
"this" pointer refers to current instance.

How to avoid race condition between DUT and Test-bench?


In Verilog, VHDL,
1) Clock which is given to DUT and Test-bench should have phase difference (DUT should
work on posedge of clk and Test-bench should work on negedge of clk).
In SV,
2) Using Clocking block,
3) Using Program block,

What is the difference between bit [7:0] sig_1; and byte sign_2; ?
Byte is signed data type and bit [7:0] is unsigned data type.

Saturday, 16 April 2016


SystemVerilog FAQ3

Write a clock generator without using always block.

initial begin

clk <= '0;

forever #(CYCLE/2) clk = ~clk

end

What is the difference between program block and module?

1. Program blocks can't have always block inside them, modules can have.

2. Program blocks can't contain UDP, modules, or other instance of program block inside them. Modules
don't have any such restrictions.

3. Inside a program block, program variable can only be assigned using blocking assignment and non-
program variables can only be assigned using non-blocking assignments. No such restrictions on module.

4. Program blocks get executed in the re-active region of scheduling queue, module blocks get executed
in the active region
Why always block is not allowed in program block?
In a design, an always block might trigger on every positive edge of a clock from the start of simulation.
A test-bench, on the other hand, goes through initialization, drive and respond to design activity, and
then completes. When the last initial block completes, simulation implicitly ends just as if you had
executed $finish. If you had an always block, it would never stop, so you would have to explicitly call
$exit to signal that the program block completed.

How to implement always block logic in program block?


Using forever loop.

Convert below always blocks logic using forever loop.


-------------------------------------------------------------------------------------

// Logic with always

always @(posedge clk or negedge reset_) begin

if(!reset_) begin

data <= '0;

end else begin

data <= data_next;

end

end

// Logic with Forever


forever begin

fork

begin : reset_logic

@ (negedge reset_);

data <= '0;

end : reset_logic

begin : clk_logic

@ (posedge clk);

if(!reset_) data <= '0;

else data <= data_next;

end : clk_logic

join_any

disable fork

end

view raw always_forever.sv hosted with by GitHub

-------------------------------------------------------------------------------------

Saturday, 30 April 2016


Singleton class in System Verilog

Sometimes it is required to have only one object of some classes like configuration classes. For this
purpose we create singleton classes.
Only one object is created for a singleton class and whenever we try to create a new object, same object
is returned.
System verilog does not provide construct to create a singleton class. But we can create it with some
manipulation.

---------------------------------------------------------------------

class singleton;

int unsigned var1;

// Need to declare it as static,

// as it is accessed by static method 'create'

static singleton single;

// Declared as 'protected',

// so user can't directly create instance of this class

protected function new();

endfunction : new

// Make it static,

// so user can use it before class is constructed

// To create instance of this class first time when this it is not create

static function singleton create();

if (single == null) begin

$display("Object single is null, so creating new object");

single = new();
end

return single;

endfunction : create

endclass : singleton

module top();

singleton s1, s2;

initial begin

// create is static method so we can use it directly

// using <class_name :: method_name>

s1 = singleton :: create();

$display (" 1 : s1.var1 = %0d", s1.var1);

s1.var1 = 10;

$display (" 2 : s1.var1 = %0d", s1.var1);

s2 = singleton :: create();

$display (" 3 : s2.var1 = %0d", s2.var1);

s2.var1 = 20;

$display (" 4 : s2.var1 = %0d", s2.var1);

$display (" 5 : s1.var1 = %0d", s1.var1);


end

endmodule : top

//Output:

// Object single is null, so creating new object

// 1 : s1.var1 = 0

// 2 : s1.var1 = 10

// 3 : s2.var1 = 10

// 4 : s2.var1 = 20

// 5 : s1.var1 = 20

view raw singleton.sv hosted with by GitHub

---------------------------------------------------------------------

uvm_root class defined as a singleton class in UVM source code.


---------------------------------------------------------------------

// Snippet of UVM souce code for singleton

virtual class uvm_coreservice_t;

local static `UVM_CORESERVICE_TYPE inst;

static function uvm_coreservice_t get();

if(inst==null)

inst=new;
return inst;

endfunction // get

pure virtual function uvm_root get_root();

endclass

class uvm_default_coreservice_t extends uvm_coreservice_t;

pure virtual function uvm_root get_root();

virtual function uvm_root get_root();

return uvm_root::m_uvm_get_root();

endfunction

endclass

class uvm_root extends uvm_component;

// singleton handle

static local uvm_root m_inst;

extern protected function new ();

function uvm_root::new();

super.new("__top__", null);

m_rh.set_name("reporter");

clp = uvm_cmdline_processor::get_inst();
report_header();

// This sets up the global verbosity. Other command line args may

// change individual component verbosity.

m_check_verbosity();

endfunction

// internal function not to be used

// get the initialized singleton instance of uvm_root

static function uvm_root m_uvm_get_root();

if (m_inst == null) begin

m_inst = new();

void'(uvm_domain::get_common_domain());

m_inst.m_domain = uvm_domain::get_uvm_domain();

end

return m_inst;

endfunction

uvm_coreservice_t cs;

extern static function uvm_root get();

function uvm_root uvm_root::get();

uvm_coreservice_t cs = uvm_coreservice_t::get();
return cs.get_root();

endfunction

endclass

view raw singleton_uvm.sv hosted with by GitHub

---------------------------------------------------------------------

Sunday, 24 April 2016


Difference between m_sequencer and p_sequencer in UVM

To understand difference between m_sequencer and p_sequencer, let's first go through couple of
classes from UVM library.
-------------------------------------------------------------------------------------

// Snippet of uvm_sequence_item class

class uvm_sequence_item extends uvm_transaction;

protected uvm_sequencer_base m_sequencer;

protected uvm_sequence_base m_parent_sequence;

// Set the sequence and sequencer execution context for a sequence item

function void set_item_context(uvm_sequence_base parent_seq,

uvm_sequencer_base sequencer = null);

set_use_sequence_info(1);

if (parent_seq != null) set_parent_sequence(parent_seq);

if (sequencer == null && m_parent_sequence != null) sequencer = m_parent_sequence.get_sequencer();


set_sequencer(sequencer);

if (m_parent_sequence != null) set_depth(m_parent_sequence.get_depth() + 1);

reseed();

endfunction

// Sets the default sequencer for the sequence to sequencer. It will take

// effect immediately, so it should not be called while the sequence is

// actively communicating with the sequencer.

virtual function void set_sequencer(uvm_sequencer_base sequencer);

m_sequencer = sequencer;

m_set_p_sequencer();

endfunction

endclass

view raw m_sequencer_vs_p_sequencer_1.sv hosted with by GitHub

-------------------------------------------------------------------------------------

-------------------------------------------------------------------------------------

// Snippet of uvm_sequence_base class

class uvm_sequence_base extends uvm_sequence_item;

// Executes this sequence, returning when the sequence has completed.

//
// The ~sequencer~ argument specifies the sequencer on which to run this

// sequence. The sequencer must be compatible with the sequence.

virtual task start (uvm_sequencer_base sequencer,

uvm_sequence_base parent_sequence = null,

int this_priority = -1,

bit call_pre_post = 1);

set_item_context(parent_sequence, sequencer);

...

endtask

endclass

// `uvm_declare_p_sequencer macro definition

//

// This macro is used to declare a variable ~p_sequencer~ whose type is

// specified by ~SEQUENCER~.

`define uvm_declare_p_sequencer(SEQUENCER) \

SEQUENCER p_sequencer;\

virtual function void m_set_p_sequencer();\

super.m_set_p_sequencer(); \
if( !$cast(p_sequencer, m_sequencer)) \

`uvm_fatal("DCLPSQ", \

$sformatf("%m %s Error casting p_sequencer, please verify that this sequence/sequence item is
intended to execute on this type of sequencer", get_full_name())) \

endfunction

view raw m_sequencer_vs_p_sequencer_2.sv hosted with by GitHub

-------------------------------------------------------------------------------------

When you call `uvm_declare_p_sequencer from sequence, it overrides m_set_p_sequencer function.


When you call start method of sequence, it calls set_item_context method,
Then set_item_context method calls set_sequencer method,
Then set_sequencer method assign handle of sequencer (which you pass in start method of sequence)
to m_sequencer,
set_sequencer also calls m_set_p_sequencer method, but you have override the m_set_p_sequencer
method by declaring `uvm_declare_p_sequencer macro.
So m_set_p_sequencer defined in macro will be executed, and it casts m_sequencer into p_sequencer,
where p_sequencer's type is specified by the argument of `uvm_declare_p_sequencer macro.

Conclusion:
m_sequencer and p_sequencer both point to the same thing (the sequencer on which the sequence is
running). However, there are some important differences:
m_sequencer is a generic uvm sequencer pointer of type uvm_sequencer_base. It will always exist for
an uvm_sequence and is initialized when the sequence is started.

p_sequencer is a reference to uvm_sequencer#(REQ,RSP), the user derived parameterized sequencer


class.
Other way you can say that p_sequencer is a type specific sequencer pointer.
p_sequencer will not exist if the `uvm_declare_p_sequencer macros aren't used.

Advantage of p_sequencer over m_sequencer:


Being type specific, you will be able to access anything added to the sequencer (i.e. pointers to other
sequencers, handle of environment class (which is defined in user derived virtual sequencer class) etc.).
Drawback of p_sequencer over m_sequencer:
p_sequencer creates an additional dependency, means sequence which use p_sequencer may not be
executed on all the sequencers. Sequence requires resource in sequencer class which is declared as
p_sequencer (i.e. pointers to other sequencers, handle of environment class, etc.)

Saturday, 23 April 2016


Randomize Non-random (State) variable using randomize() method of Class

The randomize() method can be used to temporarily control the set of random and state variables
within a class instance or object.
When randomize is called with arguments, those arguments designate the complete set of random
variables within that object; all other variables in the object are considered state variables.

The randomize method accepts the special argument null to indicate no random variables for the
duration of the call. In other words, all class members behave as state variables.

Consider following Example:

----------------------------------------------------

class rand_mo;

rand integer Var1;

integer Var2;

endclass

program rand_mo_p_38;

rand_mo obj = new();

initial begin

// Random variable: Var1, State Variable: Var2


void'(obj.randomize());

$display(" 1 : Var1 : %0d, Var2 : %0d",obj.Var1, obj.Var2);

// Random variable: Var2, State Variable: Var1

void'(obj.randomize(Var2));

$display(" 2 : Var1 : %0d, Var2 : %0d",obj.Var1, obj.Var2);

// Random variable: Var1, Var2

void'(obj.randomize(Var1, Var2));

$display(" 3 : Var1 : %0d, Var2 : %0d",obj.Var1, obj.Var2);

// State variable: Var1, Var2

void'(obj.randomize(null));

$display(" 4 : Var1 : %0d, Var2 : %0d",obj.Var1, obj.Var2);

end

endprogram

// Output:

// 1 : Var1 : -902462825, Var2 : x

// 2 : Var1 : -902462825, Var2 : -1241023056

// 3 : Var1 : 69704603, Var2 : -1877783293

// 4 : Var1 : 69704603, Var2 : -1877783293

view raw randomize_with_arguments.sv hosted with by GitHub


----------------------------------------------------

Saturday, 23 April 2016


rand_mode and constraint_mode in System Verilog

rand_mode:

The random nature of variables declared as rand or randc can be turned on or off dynamically by using
in-built method called rand_mode(). rand_mode() can be called as function or task.

In below example, rand_mode of all variable of class is disabled and enabled.

---------------------------------------------------------------------

class rand_mo;

rand integer Var1;

randc integer Var2;

endclass

program rand_mo_p_23;

rand_mo obj = new();

initial begin

void'(obj.randomize());

$display(" 1 : Var1 : %d, Var2 : %d ",obj.Var1, obj.Var2);

// Var1 and Var2 will be treated as State variables.


obj.rand_mode(0);

void'(obj.randomize());

$display(" 2 : Var1 : %d, Var2 : %d ",obj.Var1, obj.Var2);

// Var1 and Var2 will be treated as random variables.

obj.rand_mode(1);

void'(obj.randomize());

$display(" 3 : Var1 : %d, Var2 : %d ",obj.Var1, obj.Var2);

end

endprogram

//Output:

// 1 : Var1 : -902462825, Var2 : 906460592

// 2 : Var1 : -902462825, Var2 : 906460592 //Remain same (not randomized)

// 3 : Var1 : 69704603, Var2 : 1917593266

view raw rand_mode_1.sv hosted with by GitHub

---------------------------------------------------------------------

We can also change rand_mode of specific variable. Consider below example,

---------------------------------------------------------------------

class rand_mo;

rand integer Var1;


rand integer Var2;

endclass

program rand_mo_p_24;

rand_mo obj = new();

initial begin

void'(obj.randomize());

$display(" 1 : Var1 : %d Var2 : %d ",obj.Var1,obj.Var2);

// Var1 will become State variable

obj.Var1.rand_mode(0);

void'(obj.randomize());

$display(" 2 : Var1 : %d Var2 : %d ",obj.Var1,obj.Var2);

// Var2 will also become State variable

obj.Var2.rand_mode(0);

$display(" 3 : Var1 : %d Var2 : %d ",obj.Var1,obj.Var2);

// Var1 will become random variable

obj.Var1.rand_mode(1);

void'(obj.randomize());

$display(" 4 : Var1 : %d Var2 : %d ",obj.Var1,obj.Var2);


end

endprogram

//Output:

// 1 : Var1 : -902462825 Var2 : -1241023056 // Botn Var1 and Var2 are randomized

// 2 : Var1 : -902462825 Var2 : 69704603 // Var1 remain unchanged (Not randomized)

// 3 : Var1 : -902462825 Var2 : 69704603 // Var1 and Var2 both remain unchanged (Not randomized)

// 4 : Var1 : -1877783293 Var2 : 69704603 // Var1 changed (randomized), Var2 reamin unchanged (Not
randomized)

view raw rand_mode_2.sv hosted with by GitHub

---------------------------------------------------------------------

When rand_mode method is called as function, it returns the active status of the specified random
variable.

When called as a function, rand_mode() returns the current active state of the specified random
variable. It returns 1 if the variable is active (ON) and 0 if the variable is inactive (OFF).

---------------------------------------------------------------------

class rand_mo;

rand integer Var1;

rand integer Var2;

endclass

program rand_mo_p_24;

rand_mo obj = new();


initial begin

void'(obj.randomize());

$display(" 1 : Var1 : %d Var2 : %d ",obj.Var1,obj.Var2);

obj.Var1.rand_mode(0);

void'(obj.randomize());

$display(" 2 : Var1 : %d Var2 : %d ",obj.Var1,obj.Var2);

if(obj.Var1.rand_mode()) begin

$display(" 3a : Var1 is random");

end

else begin

$display(" 3b : Var1 is nonrandom");

end

void'(obj.randomize());

$display(" 4 : Var1 : %d Var2 : %d ",obj.Var1,obj.Var2);

end

endprogram

//Output:

// 1 : Var1 : -902462825 Var2 : -1241023056


// 2 : Var1 : -902462825 Var2 : 69704603

// 3b : Var1 is nonrandom

// 4 : Var1 : -902462825 Var2 : -1877783293

view raw rand_mode_3.sv hosted with by GitHub

---------------------------------------------------------------------

A compiler error shall be issued if the specified variable does not exist within the class hierarchy or even
though it exists but not declared as rand or randc. The following example illustrates the second case.

rand_mode of rand static variable,

---------------------------------------------------------------------

class A;

rand static integer Var1;

rand integer Var2;

endclass

program A_p_27;

A obj_1 = new;

A obj_2 = new;

initial begin

obj_2.Var1.rand_mode(0);

obj_2.Var2.rand_mode(0);
repeat(2) begin

void'(obj_1.randomize());

$display(" 1 : obj_1.Var1 : %0d, obj_1.Var2 : %0d, obj_2.Var1 : %0d, obj_2.Var2 :


%0d",obj_1.Var1,obj_1.Var2,obj_2.Var1,obj_2.Var2);

void'(obj_2.randomize());

$display(" 2 : obj_1.Var1 : %0d, obj_1.Var2 : %0d, obj_2.Var1 : %0d, obj_2.Var2 :


%0d",obj_1.Var1,obj_1.Var2,obj_2.Var1,obj_2.Var2);

end

end

endprogram

//Output:

// 1 : obj_1.Var1 : x, obj_1.Var2 : -902462825, obj_2.Var1 : x, obj_2.Var2 : x

// 2 : obj_1.Var1 : x, obj_1.Var2 : -902462825, obj_2.Var1 : x, obj_2.Var2 : x

// 1 : obj_1.Var1 : x, obj_1.Var2 : -1241023056, obj_2.Var1 : x, obj_2.Var2 : x

// 2 : obj_1.Var1 : x, obj_1.Var2 : -1241023056, obj_2.Var1 : x, obj_2.Var2 : x

view raw rand_mode_4.sv hosted with by GitHub

---------------------------------------------------------------------

constraint_mode
SystemVerilog supports to change the status of constraint block dynamically.

The constraint_mode() method can be used to active/inactive constraint. By default all the constraint
blocks are active. When a constraint is inactive, it is not considered by the randomize() method.

It can be used as task or function.

When called as a task, the argument to the constraint_mode task method determines the operation to
be performed.

When called as a function, constraint_mode() returns the current active state of the specified constraint
block. It returns 1 if the constraint is active (ON) and 0 if the constraint is inactive (OFF).

---------------------------------------------------------------------

// object_name.constraint_mode

class rand_mo;

rand integer Var1;

rand integer Var2;

constraint Var_1 { Var1 == 20;}

constraint Var_2 { Var2 == 10;}

endclass

program rand_mo_p_38;

rand_mo obj = new();

initial begin

//By default all constraints are active.


void'(obj.randomize());

$display(" 1 : Var1 : %0d, Var2 : %0d ",obj.Var1, obj.Var2);

//Both constraints Var_1 and Var_2 are turned off.

obj.constraint_mode(0);

void'(obj.randomize());

$display(" 2 : Var1 : %0d, Var2 : %0d ",obj.Var1, obj.Var2);

//Both constraints Var_1 and Var_2 are turned on.

obj.constraint_mode(1);

void'(obj.randomize());

$display(" 3 : Var1 : %0d, Var2 : %0d ",obj.Var1, obj.Var2);

end

endprogram

//Output:

// 1 : Var1 : 20, Var2 : 10

// 2 : Var1 : -755415376, Var2 : -334455186

// 3 : Var1 : 20, Var2 : 10

view raw constraint_mode_1.sv hosted with by GitHub

---------------------------------------------------------------------

---------------------------------------------------------------------
// object_name.constraint_name.constraint_mode

class rand_mo;

rand integer Var1;

rand integer Var2;

constraint Var_1 { Var1 == 20;}

constraint Var_2 { Var2 == 10;}

endclass

program rand_mo_p_38;

rand_mo obj = new();

initial begin

void'(obj.randomize());

$display(" Var1 : %0d, Var2 : %0d ",obj.Var1, obj.Var2);

obj.Var_1.constraint_mode(0);

void'(obj.randomize());

$display(" Var1 : %0d, Var2 : %0d ",obj.Var1, obj.Var2);

obj.Var_1.constraint_mode(1);

void'(obj.randomize());

$display(" Var1 : %0d, Var2 : %0d ",obj.Var1, obj.Var2);

end
endprogram

//Output:

// Var1 : 20, Var2 : 10

// Var1 : -755415376, Var2 : 10

// Var1 : 20, Var2 : 10

view raw constraint_mode_2.sv hosted with by GitHub

---------------------------------------------------------------------

---------------------------------------------------------------------

// Used as Function

class rand_mo;

rand integer Var1;

rand integer Var2;

constraint Var_1 { Var1 == 20;}

constraint Var_2 { Var2 == 10;}

endclass

program rand_mo_p_38;

rand_mo obj = new();

initial begin

//By default all constraints are active.


void'(obj.randomize());

$display(" 1 : Var1 : %0d, Var2 : %0d",obj.Var1, obj.Var2);

//Both constraint Var_1 is are turned off.

obj.Var_1.constraint_mode(0);

void'(obj.randomize());

$display(" 2 : Var1 : %0d, Var2 : %0d",obj.Var1, obj.Var2);

if (obj.Var_1.constraint_mode())

$display(" 3a : Var_1 constraint si active");

else

$display(" 3b : Var_1 constraint si inactive");

if (obj.Var_2.constraint_mode())

$display(" 4a : Var_2 constraint si active");

else

$display(" 4b : Var_2 constraint si inactive");

void'(obj.randomize());

$display(" 5 : Var1 : %0d, Var2 : %0d ",obj.Var1, obj.Var2);

end

endprogram
//Output:

// 1 : Var1 : 20, Var2 : 10

// 2 : Var1 : -755415376, Var2 : 10

// 3b : Var_1 constraint si inactive

// 4a : Var_2 constraint si active

// 5 : Var1 : -334455186, Var2 : 10

view raw constraint_mode_3.sv hosted with by GitHub

---------------------------------------------------------------------

uesday, 26 September 2017


Array Manipulation Methods in SystemVerilog with example

SV provides build in methods to facilitate searching from array, array ordering and
reduction.

Array locator methods:


Array locator methods operate on any unpacked array, including queues, but their
return type is a queue.

Element locator methods (with clause is mandatory):


find() returns all the elements satisfying the given expression.
find_first() returns the first element satisfying the given expression.
find_last() returns the last element satisfying the given expression.

Index locator methods (with clause is mandatory):


find_index() returns the indices of all the elements satisfying the given expression.
find_first_index() returns the index of the first element satisfying the given expression.
find_last_index() returns the index of the last element satisfying the given expression.

Index locator methods return a queue of int for all arrays except associative arrays,
which return a queue of the same type as the associative index type.
arrays that specify a wildcard index type shall not be allowed.
If no elements satisfy the given expression or the array is empty (in the case of a queue
or dynamic array), then an empty queue is returned.

Index locator methods return a queue with the indices of all items that satisfy the
expression.

The optional expression specified by the with clause shall evaluate to a Boolean value.

Let's go through below example,


---------------------------------------------------------------------
module top();
int q[$];
int result[$];

initial begin
q = {9, 1, 8, 3, 4, 4};
$display("1. queue 'q' in decimal : %p", q);

// Find all the elements less than 5


$display("2. find with (item < 5) : %p", q.find with (item < 5) ); // These
$display("3. find() with (item < 5) : %p", q.find() with (item < 5) ); // All
$display("4. find(item) with (item < 5) : %p", q.find(item) with (item < 5) ); // Are
$display("5. find(x) with (x < 5) : %p", q.find(x) with (x < 5) ); // Equivalent

// Find all the elements greater than 3


result = q.find with (item > 3);
$display("6. find with (item > 3) : %p", result);

// Find indices of all items greater than 7


result = q.find_index with (item > 7);
$display("7. find_index with (item > 7) : %p", result);

// Find indices of all items equals to 4


$display("8. find_index with (item == 4) : %p", q.find_index with (item == 4) );

// Find first item grater than 8


result = q.find_first with (item > 8);
$display("9. find_first with (item > 8) : %p", result);

// Find first item grater than 10


$display("10. find_first with (item > 10) : %p", q.find_first with (item > 10) );

// Find index of first item equals to 4


result = q.find_first_index with (item == 4);
$display("11. find_first_index with (item == 4) : %p", result);

// Find last item less than 4


$display("12. find_last with (item < 4) : %p", q.find_last with (item < 4) );

// Find index of last item equals to 4


$display("13. find_last_index with (item == 4) : %p", q.find_last_index with (item == 4));

// find all items equal to their position (index)


//result = q.find with ( item == item.index );
//$display("14. find with ( item == item.index ) : %p", result);
end
endmodule : top

//Output:
// 1. queue 'q' in decimal : '{9, 1, 8, 3, 4, 4}
// 2. find with (item < 5) : '{1, 3, 4, 4}
// 3. find() with (item < 5) : '{1, 3, 4, 4}
// 4. find(item) with (item < 5) : '{1, 3, 4, 4}
// 5. find(x) with (x < 5) : '{1, 3, 4, 4}
// 6. find with (item > 3) : '{9, 8, 4, 4}
// 7. find_index with (item > 7) : '{0, 2}
// 8. find_index with (item == 4) : '{4, 5}
// 9. find_first with (item > 8) : '{9}
// 10. find_first with (item > 10) : '{}
// 11. find_first_index with (item == 4) : '{4}
// 12. find_last with (item < 4) : '{3}
// 13. find_last_index with (item == 4) : '{5}
view raw array_find_methods.sv hosted with by GitHub
---------------------------------------------------------------------

Element locator methods (with clause is optional):


min() returns the element with the minimum value or whose expression evaluates to a
minimum.
max() returns the element with the maximum value or whose expression evaluates to a
maximum.
unique() returns all elements with unique values or whose expression evaluates to a
unique value.
unique_index() returns the indices of all elements with unique values or whose
expression evaluates to a unique value.

Let's go through below example,


---------------------------------------------------------------------
module top();
int q[$];
int result[$];

initial begin
q = {2, 6, 7, 3, 2, 7, 10, 3, 16};
$display("1. queue 'q' in decimal : %p", q);

result = q.min();
$display("2. Minimum element of queue 'q' : %p", result);

//result.delete();
//result = q.min with (item > 5);
//$display("3. Minimum element of queue 'q' : %p", result);

result = q.max();
$display("4. Maximum element of queue 'q' : %p", result);

//result.delete();
//result = q.max(x) with (x <15);
//$display("5. Maximum element of queue 'q' : %p", result);

result = q.unique();
$display("6. Unique elements of queue 'q' : %p", result);

result = q.unique_index();
$display("7. Index of Unique elements of queue 'q' : %p", result);
end
endmodule : top

//Output:
// 1. queue 'q' in decimal : '{2, 6, 7, 3, 2, 7, 10, 3, 16}
// 2. Minimum element of queue 'q' : '{2}
// 4. Maximum element of queue 'q' : '{16}
// 6. Unique elements of queue 'q' : '{2, 6, 7, 3, 10, 16}
// 7. Index of Unique elements of queue 'q' : '{0, 1, 2, 3, 6, 8}
view raw other_locator_methods.sv hosted with by GitHub
---------------------------------------------------------------------

Array reduction methods:


Array reduction methods may be applied to any unpacked array of integral values to
reduce the array to a single value

sum() returns the sum of all the array elements or, if a with clause is specified, returns
the sum of the values yielded by evaluating the expression for each array element.

product() returns the product of all the array elements or, if a with clause is specified,
returns the product of the values yielded by evaluating the expression for each array
element.

and() returns the bitwise AND ( & ) of all the array elements or, if a with clause is
specified, returns the bitwise AND of the values yielded by evaluating the expression for
each array element.

or() returns the bitwise OR ( | ) of all the array elements or, if a with clause is specified,
returns the bitwise OR of the values yielded by evaluating the expression for each array
element.

xor() returns the bitwise XOR ( ^ ) of all the array elements or, if a with clause is
specified, returns the bitwise XOR of the values yielded by evaluating the expression for
each array element.
Let's go through below example,
---------------------------------------------------------------------
module top();
int unsigned q[$];
int unsigned result;

initial begin
q = {1, 2, 3, 4};
$display("1. queue 'q' in decimal : %p", q);

result = q.sum(); // 1 + 2 + 3 + 4 = 10
$display("2. sum of all elements of queue 'q' : %0d", result);

result = q.product(); // 1 * 2 * 3 * 4 = 24
$display("3. product of all elements of queue 'q' : %0d", result);

$display("");
q = {4, 5, 'hC, 'hF};
$display("4. queue 'q' in decimal : %p", q);
result = q.and(); // 0b0100 & 0b0101 & 0b1100 & 0b1111 = 0b0100 = 4
$display("5. AND of all elements of queue 'q' : %0d", result);

$display("");
q = {4, 5, 8, 0};
$display("6. queue 'q' in decimal : %p", q);
result = q.or(); // 0b0100 | 0b0101 | 0b1000 | 0b0000 = 0b1101 = 13
$display("7. OR of all elements of queue 'q' : %0d", result);

$display("");
q = {1, 2, 3, 4};
$display("8. queue 'q' in decimal : %p", q);
result = q.xor(); // 0b0001 ^ 0b0010 ^ 0b0011 ^ 0b0100 = 0b0100 = 4
$display("9. XOR of all elements of queue 'q' : %0d", result);

result = q.xor() with (item + 4); // 0b0101 ^ 0b0100 ^ 0b0111 ^ 0b1000 = 0b1100 = 12
$display("10. XOR (with clause) of all elements of queue 'q' : %0d", result);

end
endmodule : top

//Output:
// 1. queue 'q' in decimal : '{1, 2, 3, 4}
// 2. sum of all elements of queue 'q' : 10
// 3. product of all elements of queue 'q' : 24
//
// 4. queue 'q' in decimal : '{4, 5, 12, 15}
// 5. AND of all elements of queue 'q' : 4
//
// 6. queue 'q' in decimal : '{4, 5, 8, 0}
// 7. OR of all elements of queue 'q' : 13
//
// 8. queue 'q' in decimal : '{1, 2, 3, 4}
// 9. XOR of all elements of queue 'q' : 4
// 10. XOR (with clause) of all elements of queue 'q' : 12
view raw array_reduction_methods.sv hosted with by GitHub
---------------------------------------------------------------------

Array ordering methods:


Array ordering methods reorder the elements of any unpacked array (fixed or
dynamically sized) except for associative arrays.

reverse() reverses the order of the elements in the array. Specifying a with clause shall
be a compiler error.

sort() sorts the array in ascending order, optionally using the expression in the with
clause.

rsort() sorts the array in descending order, optionally using the expression in the with
clause.

shuffle() randomizes the order of the elements in the array. Specifying a with clause
shall be a compiler error.
Let's go through below example,
---------------------------------------------------------------------
module top();
int unsigned q[$];

initial begin
q = {9, 1, 8, 3, 4, 4};
$display("1. queue 'q' in decimal : %p", q);

q.reverse();
$display("2. After calling reverse() function, queue 'q' in decimal : %p", q);

q.sort();
$display("3. After calling sort() function, queue 'q' in decimal : %p", q);

// First ODD and then EVEN in assending order


q.sort with (item % 2 == 0);
$display("4. After calling sort() function, queue 'q' in decimal : %p", q);

// First EVEN and then ODD in assending order


q.sort with (item % 2 != 0);
$display("5. After calling sort() function, queue 'q' in decimal : %p", q);

q.rsort();
$display("6. After calling rsort() function, queue 'q' in decimal : %p", q);

q.shuffle();
$display("7. After calling shuffle() function, queue 'q' in decimal : %p", q);
end
endmodule : top

//Output:
// 1. queue 'q' in decimal : '{9, 1, 8, 3, 4, 4}
// 2. After calling reverse() function, queue 'q' in decimal : '{4, 4, 3, 8, 1, 9}
// 3. After calling sort() function, queue 'q' in decimal : '{1, 3, 4, 4, 8, 9}
// 4. After calling sort() function, queue 'q' in decimal : '{1, 3, 9, 4, 4, 8}
// 5. After calling sort() function, queue 'q' in decimal : '{4, 4, 8, 1, 3, 9}
// 6. After calling rsort() function, queue 'q' in decimal : '{9, 8, 4, 4, 3, 1}
// 7. After calling shuffle() function, queue 'q' in decimal : '{4, 4, 8, 1, 9, 3}
view raw array_ordering_methods.sv hosted with by GitHub
---------------------------------------------------------------------

Now let's see couple of practical examples, let's say we want to find number of 1s from
bit array or bit queue or we want to find out number of non-zero elements in any array or
queue.
---------------------------------------------------------------------
module top();
int unsigned q[$];
int unsigned r[$];
bit bitq[$];
int unsigned result;

initial begin
q = {1, 0, 2, 3, 0, 4};
bitq = {0 ,1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1};
$display("1. queue 'q' in decimal : %p", q);
$display("2. queue 'bitq' : %p", bitq);

result = bitq.sum(item) with (int'(item));


$display("3. Number of 1's in 'bitq' : %0d", result);

r = q.find(x) with (x != 0);


$display("4. Number of non-zero elements in queue 'q' :%0d", r.size());
end
endmodule : top

//Output:
// 1. queue 'q' in decimal : '{1, 0, 2, 3, 0, 4}
// 2. queue 'bitq' : '{'h0, 'h1, 'h1, 'h1, 'h0, 'h0, 'h1, 'h0, 'h0, 'h0, 'h1, 'h0, 'h1, 'h1}
// 3. Number of 1's in 'bitq' : 7
// 4. Number of non-zero elements in queue 'q' :4
view raw array_methods_examples.sv hosted with by GitHub
---------------------------------------------------------------------
Posted by Sagar Shah No comments:
Email ThisBlogThis!Share to TwitterShare to FacebookShare to Pinterest
Labels: ASIC, find, find_first, find_first_index, find_index, find_last, find_last_index, product,
reverse, rsort, sort, sum, systemverilog, unique, unique_index, verification

Sunday, 23 July 2017


Advantage of uvm_event over SV event and how to disable uvm_event using
callback

The uvm_event#(type T = uvm_object) class is an extension of the abstract


uvm_event_base class. The optional parameter T allows the user to define a data type
which can be passed during an event trigger. uvm_event class is an abstract wrapper
class around SystemVerilog event construct.

It provides additional services such as over traditional SystemVerilog event like,


1) pass data when event is triggered,
A traditional Systemverilog event does not have functionality to pass data when event is
triggered. While uvm_event adds this functionality. So, you can pass the transaction
class handle when some event is triggered.
By calling trigger task we can trigger the event and optionally give the data which we
want to pass using uvm_event.
By calling wait_trigger()/wait_ptrigger() task of uvm_event we can wait for event to be
trigger and then by calling get_trigger_data() function we can get data.
or we can directly use only one task wait_trigger_data()/wait_ptrigger_data() of
uvm_event to wait for event to be triggered and to get the data.

2) setting callbacks,
We can also add callbacks whenever an event is triggered. This is done by registering a
callback class with particular event.

3) maintaining the number of waiters,


We can get the number of processes waiting on the event (using get_num_waiters()
function).

4) maintaining the time when event was triggered,


We can get the time that this event was last triggered (using get_trigger_time() function)

Like SystemVerilog event has trigger (@event) and persistent trigger


(wait(event.triggered)) mode, uvm_event also has trigger (wait_trigger task) and
persistent trigger (wait_ptrigger task).
Let's go through below example and see how we can transfer data using uvm_event and how we
can disable uvm_event from triggering using callbacks of uvm_event.

-------------------------------------------------------------------
`include "uvm_macros.svh"
import uvm_pkg::*;

//-----------------------------------------------------------------------------
// Interface
//-----------------------------------------------------------------------------
interface my_interface(input logic clk);
bit valid;
logic [7 : 0] addr;
reg data_reg;
wire data;

assign data = data_reg;


endinterface : my_interface
typedef virtual my_interface my_vif;

//-----------------------------------------------------------------------------
// Sequence Item Class
//-----------------------------------------------------------------------------
class my_seq_item extends uvm_sequence_item;
rand logic [7:0] addr;
rand logic [7:0] data;
int unsigned pkt_id;

constraint addr_range_cn {
addr inside {[10:20]};
}
constraint data_range_cn {
data inside {[100:200]};
}
`uvm_object_utils_begin(my_seq_item)
`uvm_field_int(pkt_id, UVM_ALL_ON| UVM_DEC)
`uvm_field_int(addr, UVM_ALL_ON| UVM_HEX)
`uvm_field_int(data, UVM_ALL_ON| UVM_HEX)
`uvm_object_utils_end

function new(string name="my_seq_item");


super.new(name);
endfunction : new

virtual function string convert2string();


convert2string =
$sformatf("pkt_id:%0d, addr=0x%0h, data=0x%0h", pkt_id, addr, data);
endfunction : convert2string
endclass : my_seq_item

//-----------------------------------------------------------------------
// Sequencer Class
//-----------------------------------------------------------------------
typedef class my_agent;
class my_sequencer extends uvm_sequencer #(my_seq_item);
my_agent parent;
`uvm_component_utils (my_sequencer)

function new (string name="my_sequencer", uvm_component parent=null);


super.new(name, parent);
if(!$cast(this.parent, parent)) begin
`uvm_fatal(get_name(), $sformatf("Casting failed from"))
end
endfunction : new
endclass : my_sequencer
view raw uvm_event_1.sv hosted with by GitHub
-------------------------------------------------------------------

-------------------------------------------------------------------
//-----------------------------------------------------------------------
// Driver Class
//-----------------------------------------------------------------------
class my_driver extends uvm_driver #(my_seq_item);
my_agent parent;
uvm_event PKT_TX_CMPLT_EV;
uvm_event_pool my_event_pool;
`uvm_component_utils (my_driver)

function new (string name="my_driver", uvm_component parent=null);


super.new(name, parent);
if(!$cast(this.parent, parent)) begin
`uvm_fatal(get_name(), $sformatf("Casting failed from"))
end
endfunction : new

function void build_phase (uvm_phase phase);


super.build_phase(phase);
my_event_pool = uvm_event_pool::get_global_pool();
// Returns the item with the given key.
// If no item exists by that key, a new item is created with that key and returned.
if (!$cast(PKT_TX_CMPLT_EV, my_event_pool.get($sformatf("DRV_EVENT")))) begin
// OR, you can directly use add method
// PKT_TX_CMPLT_EV = my_event_pool.add($sformatf("DRV_EVENT"));
`uvm_fatal(get_name(), $sformatf("casting failed from uvm_object to uvm_event"))
end
endfunction : build_phase

task run_phase(uvm_phase phase);


forever begin
seq_item_port.get_next_item(req);
`uvm_info(get_name(),
$sformatf("After get_next_item, my_seq_item : %s", req.convert2string()), UVM_LOW)
// Item done is non-blocking
seq_item_port.item_done();
for (int unsigned i=0; i<8; i ++) begin
@(posedge parent.vif.clk);
if (i == 0) begin
parent.vif.valid <= 1'b1;
parent.vif.addr[7:0] <= req.addr[7:0];
end
parent.vif.data_reg <= req.data[i];
end
@(posedge parent.vif.clk);
parent.vif.valid <= 1'b0;
PKT_TX_CMPLT_EV.trigger(req);
end
endtask : run_phase
endclass : my_driver

//-----------------------------------------------------------------------
// Agent Class
//-----------------------------------------------------------------------
class my_agent extends uvm_agent;
my_sequencer sqr;
my_driver drv;
my_vif vif;
`uvm_component_utils_begin (my_agent)
`uvm_field_object(sqr, UVM_DEFAULT)
`uvm_field_object(drv, UVM_DEFAULT)
`uvm_component_utils_end
function new (string name="my_agent", uvm_component parent=null);
super.new(name, parent);
endfunction : new

function void build_phase (uvm_phase phase);


super.build_phase(phase);
if(!uvm_config_db#(my_vif) :: get(this, "", $sformatf("vif"), this.vif)) begin
`uvm_fatal(get_name(), $sformatf("Failed to get virtual interface"))
end
sqr = my_sequencer :: type_id :: create("sqr", this);
drv = my_driver :: type_id :: create("drv", this);
endfunction : build_phase

function void connect_phase (uvm_phase phase);


super.connect_phase(phase);
drv.seq_item_port.connect(sqr.seq_item_export);
endfunction : connect_phase
endclass : my_agent

//-----------------------------------------------------------------------
// UVM event callback class
//-----------------------------------------------------------------------
class my_event_callback extends uvm_event_callback;
`uvm_object_utils(my_event_callback)
function new(string name="my_event_callback");
super.new(name);
endfunction : new

// Called just before triggering the associated event.


// If this function returns 1, then the event will not trigger
// and the post-trigger callback is not called.
// This provides a way for a callback to prevent the event from triggering.
// e - is the uvm_event#(T=uvm_object) that is being triggered.
// data - is the optional data associated with the event trigger.
virtual function bit pre_trigger (uvm_event e, uvm_object data);
my_seq_item obj;
if(!$cast(obj, data)) begin
`uvm_fatal(get_name(), $sformatf("Casting failed"))
end
else begin
if(obj.pkt_id == 3) begin
`uvm_info(get_name(),
$sformatf("pre_trigger: discarding packet from event:%s, pkt:%s",
e.get_name(), obj.convert2string()), UVM_LOW)
return 1;
end
else begin
`uvm_info(get_name(),
$sformatf("pre_trigger: pkt:%s", obj.convert2string()), UVM_LOW)
return 0;
end
end
endfunction : pre_trigger

// Called after triggering the associated event.


// e - is the uvm_event#(T=uvm_object) that is being triggered.
// data - is the optional data associated with the event trigger.
virtual function void post_trigger (uvm_event e, uvm_object data);
my_seq_item obj;
if(!$cast(obj, data)) begin
`uvm_fatal(get_name(), $sformatf("Casting failed"))
end
else begin
`uvm_info(get_name(),
$sformatf("post_trigger: pkt:%s", obj.convert2string()), UVM_LOW)
end
endfunction : post_trigger

endclass : my_event_callback
view raw uvm_event_2.sv hosted with by GitHub
-------------------------------------------------------------------
As shown in above code, one uvm_event named PKT_TX_CMPLT_EV is taken in driver.
In build phase of driver we get global handle of event pool using static method get_event_pool of
uvm_event_pool class.
Then PKT_TX_CMPLT_EV is added into associative array of uvm_event_pool using get/add
method of uvm_event_pool. Note that here PKT_TX_CMPLT_EV event is added in associative
array of uvm_event_pool using key (in string format) DRV_EVENT.
In run phase of driver when stimulus is driven, trigger method of uvm_event is called and
transaction class is passed in argument of trigger method.

uvm_event also provides facility of callback when event is triggered.


In code my_event_callback (callback for uvm_event) class which extended from
uvm_event_callback.
uvm_event_callback provides two hookups, 1) pre_trigger, 2) post_trigger.

pre_trigger:
Called just before triggering the associated event. If this function returns 1, then the event will
not trigger and the post-trigger callback is not called.

post_trigger:
Called after triggering the associated event.

-------------------------------------------------------------------
//-----------------------------------------------------------------------
// Sequence Class
//-----------------------------------------------------------------------
class my_seq extends uvm_sequence #(my_seq_item);
uvm_event my_event;
int unsigned pkt_id;
my_event_callback my_event_cb;

`uvm_object_utils (my_seq)
`uvm_declare_p_sequencer(my_sequencer)
function new(string name="my_seq");
super.new(name);
endfunction : new

task get_event(input string event_key,


output uvm_event e);
uvm_event_pool my_event_pool;
my_event_pool = uvm_event_pool::get_global_pool();
e = my_event_pool.get(event_key);
endtask : get_event

task get_event_data(ref uvm_event e, ref my_seq_item my_item);


uvm_object item;

// This method calls wait_ptrigger followed by get_trigger_data (Recommanded)


`uvm_info(get_name(), $sformatf("before wait_ptrigger_data"), UVM_LOW)
e.wait_ptrigger_data(item);
`uvm_info(get_name(), $sformatf("after wait_ptrigger_data"), UVM_LOW)

if (item == null) begin


`uvm_error(get_name(),
$sformatf("Got NULL item from event"))
end
else begin
if ($cast(my_item, item)) begin
`uvm_info(get_name(),
$sformatf("Got the item from event %s", my_item.convert2string()), UVM_LOW)
end
else begin
`uvm_error(get_name(),
$sformatf("Casting failed from %s to %s", item.get_type_name(), my_item.get_type_name()))
end
end
endtask : get_event_data

task send_tr(input int unsigned pkt_id = 0);


my_seq_item req;
`uvm_create_on(req, p_sequencer)
if(!req.randomize()) begin
`uvm_fatal(get_name(), $sformatf("Randomization failed"))
end
req.pkt_id = pkt_id;
`uvm_info (get_name(),
$sformatf("After randomizating, my_seq_item : %s",
req.convert2string()), UVM_LOW)
// Sequence will comout from `uvm_send as item_done in driver is non blocking
`uvm_send(req)
endtask : send_tr

task body ();


my_seq_item my_data;

pkt_id ++;
send_tr(pkt_id);
get_event("DRV_EVENT", my_event);
get_event_data(my_event, my_data);
// do manipulation on my_data
my_data = null;

my_event_cb = my_event_callback :: type_id :: create ("my_event_cb");


my_event.add_callback(my_event_cb);
`uvm_info(get_name(),
$sformatf("%s event_callback is added for %s event",
my_event_cb.get_name(), my_event.get_name()), UVM_LOW)

#200;
pkt_id ++;
send_tr(pkt_id);
get_event("DRV_EVENT", my_event);
get_event_data(my_event, my_data);
// do manipulation on my_data
my_data = null;

#200;
pkt_id ++;
send_tr(pkt_id);
begin
fork
begin
get_event("DRV_EVENT", my_event);
get_event_data(my_event, my_data);
my_data = null;
end
begin
repeat (50) begin
@(posedge p_sequencer.parent.vif.clk);
end
`uvm_info(get_name(), $sformatf("event is not triggered"), UVM_LOW)
end
join_any
disable fork;
end

my_event.delete_callback(my_event_cb);
`uvm_info(get_name(),
$sformatf("%s event_callback is deleted for %s event",
my_event_cb.get_name(), my_event.get_name()), UVM_LOW)
#200;
pkt_id ++;
send_tr(pkt_id);
get_event("DRV_EVENT", my_event);
get_event_data(my_event, my_data);

endtask : body
endclass : my_seq

//-----------------------------------------------------------------------
// Test Class
//-----------------------------------------------------------------------
class my_test extends uvm_test;
my_agent agent;
my_vif vif;
`uvm_component_utils_begin (my_test)
`uvm_field_object(agent, UVM_DEFAULT)
`uvm_component_utils_end

function new (string name="my_test", uvm_component parent=null);


super.new(name, parent);
endfunction : new

function void build_phase (uvm_phase phase);


super.build_phase(phase);
if(!uvm_config_db#(my_vif) :: get(this, "", $sformatf("vif"), this.vif)) begin
`uvm_fatal(get_name(), $sformatf("Failed to get virtual interface"))
end
agent = my_agent::type_id::create("agent", this);
uvm_config_db#(my_vif) :: set(this, "agent", $sformatf("vif"), this.vif);
endfunction : build_phase

task run_phase(uvm_phase phase);


my_seq seq;
phase.raise_objection(this);
seq = my_seq::type_id::create ("seq");
//seq.set_starting_phase(phase);
#150;
seq.start(agent.sqr);
#150;
phase.drop_objection(this);
endtask : run_phase
endclass : my_test

// Top module
module top();
bit clk;

my_interface intf(clk);

initial begin
uvm_config_db#(my_vif) :: set(uvm_root::get(), "uvm_test_top", "vif", intf);
forever begin
#5 clk = ~clk;
end
end

initial begin
run_test("my_test");
end
endmodule : top
view raw uvm_event_3.sv hosted with by GitHub
-------------------------------------------------------------------
As shown in above code, in sequence, event callback is registered with associated event using
add_callback method of uvm_event and also deleted using delete_callback method of
uvm_event

-------------------------------------------------------------------
Output:
UVM_INFO @ 0: reporter [RNTST] Running test my_test...
UVM_INFO uvm_event_3.sv(55) @ 150: uvm_test_top.agent.sqr@@seq [seq] After
randomizating, my_seq_item : pkt_id:1, addr=0x13, data=0x8c
UVM_INFO uvm_event_2.sv(33) @ 150: uvm_test_top.agent.drv [drv] After get_next_item,
my_seq_item : pkt_id:1, addr=0x13, data=0x8c
UVM_INFO uvm_event_3.sv(26) @ 150: uvm_test_top.agent.sqr@@seq [seq] before
wait_ptrigger_data
UVM_INFO uvm_event_3.sv(28) @ 235: uvm_test_top.agent.sqr@@seq [seq] after
wait_ptrigger_data
UVM_INFO uvm_event_3.sv(37) @ 235: uvm_test_top.agent.sqr@@seq [seq] Got the item
from event pkt_id:1, addr=0x13, data=0x8c
UVM_INFO uvm_event_3.sv(74) @ 235: uvm_test_top.agent.sqr@@seq [seq] my_event_cb
event_callback is added for DRV_EVENT event
UVM_INFO uvm_event_3.sv(55) @ 435: uvm_test_top.agent.sqr@@seq [seq] After
randomizating, my_seq_item : pkt_id:2, addr=0xd, data=0x6e
UVM_INFO uvm_event_2.sv(33) @ 435: uvm_test_top.agent.drv [drv] After get_next_item,
my_seq_item : pkt_id:2, addr=0xd, data=0x6e
UVM_INFO uvm_event_3.sv(26) @ 435: uvm_test_top.agent.sqr@@seq [seq] before
wait_ptrigger_data
UVM_INFO uvm_event_2.sv(111) @ 525: reporter [my_event_cb] pre_trigger: pkt:pkt_id:2,
addr=0xd, data=0x6e
UVM_INFO uvm_event_2.sv(127) @ 525: reporter [my_event_cb] post_trigger: pkt:pkt_id:2,
addr=0xd, data=0x6e
UVM_INFO uvm_event_3.sv(28) @ 525: uvm_test_top.agent.sqr@@seq [seq] after
wait_ptrigger_data
UVM_INFO uvm_event_3.sv(37) @ 525: uvm_test_top.agent.sqr@@seq [seq] Got the item
from event pkt_id:2, addr=0xd, data=0x6e
UVM_INFO uvm_event_3.sv(55) @ 725: uvm_test_top.agent.sqr@@seq [seq] After
randomizating, my_seq_item : pkt_id:3, addr=0x12, data=0xa3
UVM_INFO uvm_event_2.sv(33) @ 725: uvm_test_top.agent.drv [drv] After get_next_item,
my_seq_item : pkt_id:3, addr=0x12, data=0xa3
UVM_INFO uvm_event_3.sv(26) @ 725: uvm_test_top.agent.sqr@@seq [seq] before
wait_ptrigger_data
UVM_INFO uvm_event_2.sv(106) @ 815: reporter [my_event_cb] pre_trigger: discarding
packet from event:DRV_EVENT, pkt:pkt_id:3, addr=0x12, data=0xa3
UVM_INFO uvm_event_3.sv(98) @ 1225: uvm_test_top.agent.sqr@@seq [seq] event is not
triggered
UVM_INFO uvm_event_3.sv(107) @ 1225: uvm_test_top.agent.sqr@@seq [seq] my_event_cb
event_callback is deleted for DRV_EVENT event
UVM_INFO uvm_event_3.sv(55) @ 1425: uvm_test_top.agent.sqr@@seq [seq] After
randomizating, my_seq_item : pkt_id:4, addr=0x14, data=0xa5
UVM_INFO uvm_event_2.sv(33) @ 1425: uvm_test_top.agent.drv [drv] After get_next_item,
my_seq_item : pkt_id:4, addr=0x14, data=0xa5
UVM_INFO uvm_event_3.sv(26) @ 1425: uvm_test_top.agent.sqr@@seq [seq] before
wait_ptrigger_data
UVM_INFO uvm_event_3.sv(28) @ 1515: uvm_test_top.agent.sqr@@seq [seq] after
wait_ptrigger_data
UVM_INFO uvm_event_3.sv(37) @ 1515: uvm_test_top.agent.sqr@@seq [seq] Got the item
from event pkt_id:4, addr=0x14, data=0xa5
UVM_INFO uvm_objection.svh(1271) @ 1665: reporter [TEST_DONE] 'run' phase is ready to
proceed to the 'extract' phase
UVM_INFO uvm_report_server.svh(847) @ 1665: reporter [UVM/REPORT/SERVER]
view raw uvm_event_output.sv hosted with by GitHub
-------------------------------------------------------------------

FAQ:
Through uvm_event we can pass data(transaction class) when event is triggered, then why do we
need TLM/Analysis ports in UVM?
Ans:
If event is triggered again before receiver gets the data then data will be overwritten.
Posted by Sagar Shah No comments:
Email ThisBlogThis!Share to TwitterShare to FacebookShare to Pinterest
Labels: post_trigger, pre_trigger, uvm_event, uvm_event_callback, uvm_event_pool,
wait_ptrigger, wait_ptrigger_data, wait_trigger, wait_trigger_data

Reset Testing using Phase Jump in UVM

Reset testing is a crucial element of functional sign-off for any chip. The architectural
components of the entire verification environment need to be correctly synchronized to be made
aware of the reset condition. Scoreboards, drivers and monitors need to be tidied up, and the
complex stimulus generation needs to be killed gracefully.

As we know, in UVM, there are twelve phases parallel to run_phase:

1. pre_reset_phase(), reset_phase(), post_reset_phase(): Phases involved in reset activity.


2. pre_configure_phase(), configure_phase(), post_configure_phase(): Phases involved in
configuring DUT.
3. pre_main_phase(), main_phase(), post_main_phase(): Phases involved in driving main
stimulus to the DUT.
4. pre_shutdown_phase(), shutdown_phase and post_shutdown_phase(): Phases involved in
settling down the DUT after driving main stimulus.

Using these phases instead of using only run_phase, we can achieve synchronization between all
components of verification environment also easily test reset functionality.

In reset testing, user drives random sequence to the DUT and in between data transmission, reset
is applied followed by driving restart sequence. We will see how the reset functionality could be
easily tested using phases parallel to run_phase and phase jump feature of UVM.

Lets go through complete example to understand how it is achieved using UVM phases and
Phase jump feature.
----------------------------------------------------------------------
`timescale 1ns/1ps
`include "uvm_macros.svh"
import uvm_pkg :: *;

`define ADDR_WIDTH_IN_BITS 8
`define DATA_WIDTH_IN_BITS 8

//-----------------------------------------------------------------------------
// Interface
//-----------------------------------------------------------------------------
interface my_interface(input logic clk,
input logic rstn /* Active Low Reset */);
bit valid;
logic [`ADDR_WIDTH_IN_BITS - 1 : 0] start_addr;
reg [`DATA_WIDTH_IN_BITS - 1 : 0] data_reg;
wire [`DATA_WIDTH_IN_BITS - 1 : 0] data;
int unsigned length_in_bytes;

assign data = data_reg;


endinterface : my_interface
typedef virtual my_interface my_vif;
typedef class my_agent;

//-----------------------------------------------------------------------------
// Agent Configuration Class
//-----------------------------------------------------------------------------
class my_agent_cfg extends uvm_object;
// virtual interface
my_vif vif;
// The length of time, in ps, that reset will stay active
int unsigned reset_time_ps = 10;
// Minimum length of payload data
int unsigned min_payload_length = 5;
// Maximum length of payload data
int unsigned max_payload_length = 100;
uvm_active_passive_enum is_active = UVM_ACTIVE;

`uvm_object_utils_begin(my_agent_cfg)
`uvm_field_enum(uvm_active_passive_enum, is_active, UVM_DEFAULT)
`uvm_field_int(reset_time_ps, UVM_DEFAULT | UVM_DEC)
`uvm_field_int(min_payload_length, UVM_DEFAULT | UVM_DEC)
`uvm_field_int(max_payload_length, UVM_DEFAULT | UVM_DEC)
`uvm_object_utils_end

function new(string name="my_agent_cfg");


super.new(name);
endfunction : new

function void is_valid();


if (max_payload_length < min_payload_length) begin
`uvm_error(get_name(),
$sformatf("Value of max_payload_length is shall be greater or equal to value of
min_payload_length, configured values of max_payload_length:%0d,
min_payload_length:%0d",
max_payload_length, min_payload_length))
end
if (reset_time_ps <= 0) begin
`uvm_error(get_name(), $sformatf("reset_time_ps shall be greater than 0"))
end
endfunction : is_valid
endclass : my_agent_cfg

//-----------------------------------------------------------------------------
// Sequence Item Class
//-----------------------------------------------------------------------------
class my_seq_item extends uvm_sequence_item;
// Random varialbes
rand logic [`ADDR_WIDTH_IN_BITS - 1 : 0] start_addr;
rand logic [`DATA_WIDTH_IN_BITS - 1 : 0] data[];
rand int unsigned payload_length;
// Non random variables
my_agent_cfg cfg;

`uvm_object_utils_begin(my_seq_item)
`uvm_field_int (start_addr, UVM_DEFAULT | UVM_HEX)
`uvm_field_int (payload_length, UVM_DEFAULT | UVM_DEC)
`uvm_field_array_int (data, UVM_DEFAULT | UVM_HEX)
`uvm_object_utils_end

constraint length_cn {
payload_length inside {[cfg.min_payload_length : cfg.max_payload_length]};
data.size == payload_length;
}
constraint order_cn {
solve payload_length before data;
}

function new(string name="my_seq_item");


super.new(name);
endfunction : new

function string convert2string();


convert2string = $sformatf("start_addr:%0h, payload_length:%0d, data[0]:%0h,
data[%0d]:%0h",
start_addr, payload_length, data[0], payload_length-1, data[payload_length-1]);
endfunction : convert2string
endclass : my_seq_item
view raw phase_jump_1.sv hosted with by GitHub
----------------------------------------------------------------------
----------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Sequencer Class
//-----------------------------------------------------------------------------
class my_sequencer extends uvm_sequencer#(my_seq_item);
my_agent parent;
`uvm_component_utils(my_sequencer)

function new(string name="my_sequencer", uvm_component parent=null);


super.new(name, parent);
if (parent == null) begin
`uvm_fatal(get_name(),
$sformatf("NULL handle is provided in parent argument of constructor"))
end
else begin
if (!$cast(this.parent, parent)) begin
`uvm_fatal(get_name(),
$sformatf("Casting Failed, provide parent of valid type"))
end
end
endfunction : new
endclass : my_sequencer

//-----------------------------------------------------------------------------
// Driver Class
//-----------------------------------------------------------------------------
class my_driver extends uvm_driver#(my_seq_item);
my_agent parent;
event reset_driver;
`uvm_component_utils_begin(my_driver)
`uvm_component_utils_end

function new(string name="my_driver", uvm_component parent=null);


super.new(name, parent);
if (parent == null) begin
`uvm_fatal(get_name(),
$sformatf("NULL handle is provided in parent argument of constructor"))
end
else begin
if (!$cast(this.parent, parent)) begin
`uvm_fatal(get_name(),
$sformatf("Casting Failed, provide parent of valid type"))
end
end
endfunction : new

function void build_phase (uvm_phase phase);


super.build_phase(phase);
endfunction : build_phase

task pre_reset_phase(uvm_phase phase);


// De-assert valid signal after enterring into pre_reset_phase
parent.cfg.vif.valid <= 1'b0;
endtask : pre_reset_phase

// Wait for Reset to assert and


// Do something you want to do after reset is asserted
task reset_phase(uvm_phase phase);
phase.raise_objection(this);
wait (parent.cfg.vif.rstn == 1'b0);
`uvm_info(get_name(),
$sformatf("after waiting for rstn to be asserted"), UVM_LOW)
phase.drop_objection(this);
endtask : reset_phase

// Wait for Reset to de-assert


task post_reset_phase(uvm_phase phase);
phase.raise_objection(this);
wait (parent.cfg.vif.rstn == 1'b1);
`uvm_info(get_name(),
$sformatf("after waiting for rstn to be deasserted"), UVM_LOW)
phase.drop_objection(this);
endtask : post_reset_phase

// Drive stimulus on interface and in parallel


// wait for reset to be asserted
task main_phase(uvm_phase phase);
`uvm_info(get_name(), $sformatf("enter in main_phase"), UVM_LOW)
forever begin
fork
begin
drive();
end
begin
wait (reset_driver.triggered);
`uvm_info(get_name(),
$sformatf("after wait for reset_driver event to be triggered"), UVM_LOW)
end
join_any
disable fork;
end
endtask : main_phase

task drive();
my_seq_item tr;
`uvm_info(get_name(), $sformatf("Before get_next_item"), UVM_LOW)
seq_item_port.get_next_item(tr);
`uvm_info(get_name(),
$sformatf("After get_next_item tr:\n%s", tr.convert2string()), UVM_LOW)
@(posedge parent.cfg.vif.clk);
parent.cfg.vif.valid <= 1'b1;
parent.cfg.vif.length_in_bytes <= tr.payload_length;
parent.cfg.vif.start_addr <= tr.start_addr;
for (int unsigned i=0; i<tr.payload_length; i ++) begin
parent.cfg.vif.data_reg <= tr.data[i];
@(posedge parent.cfg.vif.clk);
if (i == tr.payload_length - 1) begin
parent.cfg.vif.valid <= 1'b0;
end
end
seq_item_port.item_done(tr);
`uvm_info(get_name(), $sformatf("item_done is called"), UVM_LOW)
endtask : drive
endclass : my_driver
//-----------------------------------------------------------------------------
// Monitor Class
//-----------------------------------------------------------------------------
class my_monitor extends uvm_monitor;
my_agent parent;
`uvm_component_utils_begin(my_monitor)
`uvm_component_utils_end

function new(string name="my_monitor", uvm_component parent=null);


super.new(name, parent);
if (parent == null) begin
`uvm_fatal(get_name(), $sformatf("NULL handle is provided in parent argument of
constructor"))
end
else begin
if (!$cast(this.parent, parent)) begin
`uvm_fatal(get_name(), $sformatf("Casting Failed, provide parent of valid type"))
end
end
endfunction : new

function void build_phase (uvm_phase phase);


super.build_phase(phase);
endfunction : build_phase

task pre_reset_phase(uvm_phase phase);


endtask : pre_reset_phase

// Wait for reset to de-assert


task reset_phase(uvm_phase phase);
@(posedge parent.cfg.vif.rstn);
`uvm_info(get_name(), $sformatf("rstn deassertion detected"), UVM_LOW)
endtask : reset_phase
// Sample interface signals and form packet and
// in parallel wait for reset to be asserted
task main_phase(uvm_phase phase);
my_seq_item tr;
forever begin
fork
begin
receive(tr);
end
begin
@(negedge parent.cfg.vif.rstn);
`uvm_info(get_name(), $sformatf("rstn is asserted during reception of data"), UVM_LOW)
`uvm_info(get_name(), $sformatf(" tr:\n%s", tr.convert2string()), UVM_LOW)
end
join_any
disable fork;
// put tr into analysis port
tr = null;
end
endtask : main_phase

task receive(ref my_seq_item tr);


@(negedge parent.cfg.vif.clk);
if (parent.cfg.vif.valid == 1'b1) begin
`uvm_info(get_name(), $sformatf("valid is detected"), UVM_LOW)
tr = new("tr");
tr.payload_length = parent.cfg.vif.length_in_bytes;
tr.start_addr = parent.cfg.vif.start_addr;
tr.data = new[tr.payload_length];
for (int unsigned i=0; i<tr.payload_length; i ++) begin
tr.data[i] = parent.cfg.vif.data;
if (i != tr.payload_length - 1) begin
@(negedge parent.cfg.vif.clk);
end
end
`uvm_info(get_name(), $sformatf("Complete tr:\n%s", tr.convert2string()), UVM_LOW)
end
endtask : receive
endclass : my_monitor

//-----------------------------------------------------------------------------
// Agent Class
//-----------------------------------------------------------------------------
class my_agent extends uvm_agent;
my_agent_cfg cfg;
my_sequencer sqr;
my_driver drv;
my_monitor mon;

`uvm_component_utils_begin(my_agent)
`uvm_field_object(cfg, UVM_DEFAULT)
`uvm_field_object(sqr, UVM_DEFAULT)
`uvm_field_object(drv, UVM_DEFAULT)
`uvm_field_object(mon, UVM_DEFAULT)
`uvm_component_utils_end

function new(string name="my_agent", uvm_component parent=null);


super.new(name, parent);
endfunction : new

function void build_phase (uvm_phase phase);


super.build_phase(phase);
if (!uvm_config_db#(my_agent_cfg) :: get(this, "", "cfg", this.cfg) &&
this.cfg != null) begin
`uvm_fatal(get_name(), $sformatf("configuration object of type:%s is not set for this instance",
this.cfg.get_type()))
end
if (!uvm_config_db#(my_vif) :: get(this, "", "vif", this.cfg.vif)) begin
`uvm_fatal(get_name(), $sformatf("Interface is not passed to agent"))
end

cfg.is_valid();

if (cfg.is_active == UVM_ACTIVE) begin


sqr = my_sequencer :: type_id :: create ("sqr", this);
drv = my_driver :: type_id :: create ("drv", this);
end
mon = my_monitor :: type_id :: create ("mon", this);
endfunction : build_phase

function void connect_phase (uvm_phase phase);


super.connect_phase(phase);
if (cfg.is_active == UVM_ACTIVE) begin
drv.seq_item_port.connect(sqr.seq_item_export);
end
endfunction : connect_phase

task pre_reset_phase(uvm_phase phase);


if(cfg.is_active == UVM_ACTIVE) begin
// Tells the sequencer to kill all sequences and child sequences currently
// operating on the sequencer, and remove all requests, locks and responses
// that are currently queued.
// This essentially resets the sequencer to an idle state.
sqr.stop_sequences();
// Indicates Driver that reset is asserted
->drv.reset_driver;
`uvm_info(get_name(), $sformatf("reset_driver event is triggered"), UVM_LOW)
end
endtask : pre_reset_phase
endclass : my_agent
view raw phase_jump_2.sv hosted with by GitHub
----------------------------------------------------------------------
As shown in above code,
Driver is waiting for Reset to be asserted (in reset_phase) by raising objection and then perform
action which user want on assertion of Reset signal and at last drop the objection and move to
post_reset_phase. In post_reset_phase driver is waiting for Reset to de-assert and then move to
main_phase. In main_phase driver drives stimulus on interface and in parallel to that wait for
indication from agent about assertion of reset.

Components such as monitors that attach to signaling interfaces should be designed to be phase
independent because they are intended to mimic other real devices in the system. These
components should watch the reset signal associated with their interface and reset themselves
accordingly.

You may find that the driver, the sequencer, and their currently running sequences will squawk
with errors if they are not synchronized properly. UVM requires that the sequencer first stop its
sequences and then the driver must be certain to not call item_done on any outstanding
sequences. However, the order that a simulator executes threads in the various components is
indeterminate. To synchronize these operations, the containing agent has a pre_reset_phase such
as the above.

----------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Sequence Class
//-----------------------------------------------------------------------------
class my_base_sequence extends uvm_sequence#(my_seq_item);
int unsigned payload_length;
`uvm_object_utils(my_base_sequence)

`uvm_declare_p_sequencer(my_sequencer)

function new(string name="my_base_sequence");


super.new(name);
endfunction : new

task body();
endtask : body
endclass : my_base_sequence

class my_sequence extends my_base_sequence;


`uvm_object_utils(my_sequence)

function new(string name="my_sequence");


super.new(name);
endfunction : new

task body();
my_seq_item req;
my_seq_item rsp;
`uvm_create(req)
req.cfg = p_sequencer.parent.cfg;
if (!req.randomize() with {payload_length == local::payload_length;}) begin
`uvm_fatal(get_name(), $sformatf("Randomization failed"))
end
else begin
`uvm_info(get_name(),
$sformatf("After randomization tr in seq:\n%s", req.convert2string()), UVM_LOW)
end
`uvm_send(req)
get_response(rsp);
`uvm_info(get_name(),
$sformatf("Got response from driver"), UVM_LOW)
endtask : body
endclass : my_sequence

//-----------------------------------------------------------------------------
// Test Class
//-----------------------------------------------------------------------------
class my_test extends uvm_test;
my_vif act_vif;
my_vif psv_vif;
my_agent act_agent;
my_agent psv_agent;
my_agent_cfg act_agent_cfg;
my_agent_cfg psv_agent_cfg;
// The number of times the test has run so far
int unsigned run_count;

`uvm_component_utils_begin(my_test)
`uvm_field_int(run_count, UVM_DEFAULT | UVM_DEC)
`uvm_field_object(act_agent, UVM_DEFAULT)
`uvm_field_object(act_agent_cfg, UVM_DEFAULT)
`uvm_field_object(psv_agent, UVM_DEFAULT)
`uvm_field_object(psv_agent_cfg, UVM_DEFAULT)
`uvm_component_utils_end

function new(string name="my_test", uvm_component parent=null);


super.new(name, parent);
endfunction : new

function void build_phase (uvm_phase phase);


super.build_phase(phase);
if (!uvm_config_db#(my_vif) :: get(this, "", $sformatf("act_vif"), act_vif)) begin
`uvm_fatal(get_name(), $sformatf("act_vif is not set for this class from top module"))
end
if (!uvm_config_db#(my_vif) :: get(this, "", $sformatf("psv_vif"), psv_vif)) begin
`uvm_fatal(get_name(), $sformatf("psv_vif is not set for this class from top module"))
end
act_agent = my_agent :: type_id :: create ($sformatf("act_agent"), this);
psv_agent = my_agent :: type_id :: create ($sformatf("psv_agent"), this);

act_agent_cfg = my_agent_cfg :: type_id :: create ($sformatf("act_agent_cfg"), this);


act_agent_cfg.is_active = UVM_ACTIVE;
psv_agent_cfg = my_agent_cfg :: type_id :: create ($sformatf("psv_agent_cfg"), this);
psv_agent_cfg.is_active = UVM_PASSIVE;

uvm_config_db#(my_vif) :: set(this, $sformatf("act_agent"), "vif", act_vif);


uvm_config_db#(my_vif) :: set(this, $sformatf("psv_agent"), "vif", psv_vif);
uvm_config_db#(my_agent_cfg) :: set(this, $sformatf("act_agent"), "cfg", act_agent_cfg);
uvm_config_db#(my_agent_cfg) :: set(this, $sformatf("psv_agent"), "cfg", psv_agent_cfg);
endfunction : build_phase

task main_phase (uvm_phase phase);


phase.raise_objection(this);
if (run_count == 0) begin
fork
begin
// Run sequence
my_sequence seq;
seq = my_sequence :: type_id :: create ("seq");
seq.payload_length = 50;
seq.start(act_agent.sqr);
`uvm_info(get_name(), $sformatf("finished first seq"), UVM_LOW)
#1000;
`uvm_info(get_name(),
$sformatf("finished thread parallel to waiting for rstn"), UVM_LOW)
end
begin
@(negedge act_vif.rstn);
`uvm_info(get_name(), $sformatf("rstn assertion detected"), UVM_LOW)
end
join_any
disable fork;
end
else if (run_count == 1) begin
// Run sequence
my_sequence seq;
seq = my_sequence :: type_id :: create ("seq");
seq.payload_length = 40;
seq.start(act_agent.sqr);
#100;
end

if (run_count == 0) begin
phase.get_objection().set_report_severity_id_override(UVM_WARNING, "OBJTN_CLEAR",
UVM_INFO);
phase.jump(uvm_pre_reset_phase::get());
end
else begin
phase.drop_objection(this);
end
run_count ++;
endtask : main_phase

endclass : my_test

//-----------------------------------------------------------------------------
// TB TOP module
//-----------------------------------------------------------------------------
module top();
bit clk;
logic rstn;

my_interface act_if (clk, rstn);


my_interface psv_if (clk, rstn);

initial begin
run_test("my_test");
end

assign psv_if.length_in_bytes = act_if.length_in_bytes;


assign psv_if.start_addr = act_if.start_addr;
assign psv_if.data_reg = act_if.data_reg;
assign psv_if.valid = act_if.valid;

initial begin
uvm_config_db#(virtual my_interface) :: set(uvm_root::get(), "uvm_test_top",
$sformatf("act_vif"), act_if);
uvm_config_db#(my_vif) :: set(uvm_root::get(), "uvm_test_top", $sformatf("psv_vif"), psv_if);
end

initial begin
forever begin
#5 clk = !clk;
end
end

initial begin
#7 rstn = 1'b1;
# 30 rstn = 1'b0;
#100 rstn = 1'b1;
#270 rstn = 1'b0;
#70 rstn = 1'b1;
#1000 $finish;
end
endmodule : top
view raw phase_jump_3.sv hosted with by GitHub
----------------------------------------------------------------------
When test enters main_phase initially first time at that time run_count is 0, so on assertion of
Reset test will do phase.jump method and move to pre_reset_phase from main_phase.
When test enters main_phase second time at that time run_count is 1, so at that time it will not do
phase jumping.
Note: It is not good to use a phase jumping feature in case any of the components of testbench
dont use the sub-phases of UVM.

Reference:
1) http://www.sunburst-design.com/papers/HunterSNUGSV_UVM_Resets_paper.pdf
Posted by Sagar Shah No comments:
Email ThisBlogThis!Share to TwitterShare to FacebookShare to Pinterest
Labels: Phase Jump, phase jumping, Reset testing, systemverilog, UVM, verification

Saturday, 22 July 2017


Extend run_phase using set_drain_time and all_dropped callback after all
objection drops

It is more often that two or more components in verification environment are not in sync with
each other. And there may be a case where driver/transmitter finish it's job first and call
item_done. After item_done is called from driver and if there is no action pending in sequence
then start method of sequence finishes and objection is also dropped.
But we want that simulation (more precisely we can say run_phase) should extend to some more
time after all objection are dropped, so that other components which are late with respect to
driver can finish it's job. We can achieve this by using set_drain_time in UVM.

Let's go through example and see how we can achieve this using set_drain_time in UVM.
--------------------------------------------------------------------
`timescale 1ns/1ns
`include "uvm.sv"
import uvm_pkg::*;
`include "uvm_macros.svh"

// In this example, a drain time of 10 is set on the component.


// The component then forks 4 processes which consume different
// amounts of time. When the last process is done (time 85),
// the drain time takes effect. The test is completed at time 95.
class my_agent extends uvm_agent;
`uvm_component_utils(my_agent)
function new (string name="my_agent", uvm_component parent=null);
super.new(name, parent);
endfunction : new
virtual task run_phase(uvm_phase phase);
// Run a bunch of processes in parallel
fork
doit(phase, 85);
doit(phase, 55);
join
endtask : run_phase

// A simple task that consumes some time.


task doit (uvm_phase phase, time delay);
static int s_inst = 0;
int inst = s_inst++;

//Raise an objection before starting the activity


phase.raise_objection(this);

uvm_report_info(get_name(), $sformatf("Starting doit (%0d) with delay %0t", inst, delay),


UVM_NONE);
#delay;
uvm_report_info(get_name(), $sformatf("Ending doit (%0d)", inst), UVM_NONE);

//Drop the objection when done


phase.drop_objection(this);
endtask : doit
endclass : my_agent

class my_env extends uvm_test;


my_agent agent;
`uvm_component_utils(my_env)

function new (string name="my_env", uvm_component parent=null);


super.new(name, parent);
endfunction : new

function void build_phase (uvm_phase phase);


super.build_phase(phase);
agent = my_agent :: type_id :: create ("agent", this);
endfunction : build_phase

virtual task run_phase(uvm_phase phase);


// Run a bunch of processes in parallel
fork
doit(phase, 35);
doit(phase, 60);
join
endtask : run_phase

// A simple task that consumes some time.


task doit (uvm_phase phase, time delay);
static int s_inst = 0;
int inst = s_inst++;

//Raise an objection before starting the activity


phase.raise_objection(this);

uvm_report_info(get_name(), $sformatf("Starting doit (%0d) with delay %0t", inst, delay),


UVM_NONE);
#delay;
uvm_report_info(get_name(), $sformatf("Ending doit (%0d)", inst), UVM_NONE);

//Drop the objection when done


phase.drop_objection(this);
endtask : doit
endclass : my_env

class my_test extends uvm_test;


my_env env;
`uvm_component_utils(my_test)

function new (string name, uvm_component parent);


super.new(name, parent);
endfunction : new

function void build_phase (uvm_phase phase);


super.build_phase(phase);
env = my_env :: type_id::create("env", this);
endfunction : build_phase

virtual task run_phase(uvm_phase phase);


// Set a drain time on the objection if needed
`uvm_info("drain", "Setting drain time of 10", UVM_NONE)
// uvm-1.1d or earlier (depricated in uvm-1.2
//uvm_test_done.set_drain_time(this,10);
// uvm-1.2
phase.phase_done.set_drain_time(this,10);

// Run a bunch of processes in parallel


fork
doit(phase, 25);
doit(phase, 50);
join
endtask : run_phase

// A simple task that consumes some time.


task doit (uvm_phase phase, time delay);
static int s_inst = 0;
int inst = s_inst++;

//Raise an objection before starting the activity


phase.raise_objection(
this, // uvm_object obj
"", // string description=""
1 // int count=1, default value = 1 which increment objection count by 1
);

uvm_report_info(get_name(), $sformatf("Starting doit (%0d) with delay %0t", inst, delay),


UVM_NONE);
#delay;
uvm_report_info(get_name(), $sformatf("Ending doit (%0d)", inst), UVM_NONE);

//Drop the objection when done


phase.drop_objection(
this, // uvm_object obj
"", // string description=""
1 // int count=1, default value = 1 which decrement objection count by 1
);
endtask : doit
endclass : my_test

module top;
initial begin
run_test("my_test");
end
endmodule : top

// Output:
// UVM_INFO @ 0: reporter [RNTST] Running test my_test...
// UVM_INFO top.sv(98) @ 0: uvm_test_top [drain] Setting drain time of 10
// UVM_INFO @ 0: uvm_test_top [uvm_test_top] Starting doit (0) with delay 25
// UVM_INFO @ 0: uvm_test_top [uvm_test_top] Starting doit (1) with delay 50
// UVM_INFO @ 0: uvm_test_top.env [env] Starting doit (0) with delay 35
// UVM_INFO @ 0: uvm_test_top.env [env] Starting doit (1) with delay 60
// UVM_INFO @ 0: uvm_test_top.env.agent [agent] Starting doit (0) with delay 85
// UVM_INFO @ 0: uvm_test_top.env.agent [agent] Starting doit (1) with delay 55
// UVM_INFO @ 25: uvm_test_top [uvm_test_top] Ending doit (0)
// UVM_INFO @ 35: uvm_test_top.env [env] Ending doit (0)
// UVM_INFO @ 50: uvm_test_top [uvm_test_top] Ending doit (1)
// UVM_INFO @ 55: uvm_test_top.env.agent [agent] Ending doit (1)
// UVM_INFO @ 60: uvm_test_top.env [env] Ending doit (1)
// UVM_INFO @ 85: uvm_test_top.env.agent [agent] Ending doit (0)
// UVM_INFO /home/shahs/gotcha/uvm/uvm-1.2/src/base/uvm_objection.svh(1271) @ 95:
reporter [TEST_DONE] 'run' phase is ready to proceed to the 'extract' phase
// UVM_INFO /home/shahs/gotcha/uvm/uvm-1.2/src/base/uvm_report_server.svh(847) @ 95:
reporter [UVM/REPORT/SERVER]
view raw set_drain_time.sv hosted with by GitHub

--------------------------------------------------------------------

UVM also provides callback hookups when every objection raises and drops and when all
objection drops.
Let's go through example and see how it works,

--------------------------------------------------------------------
`timescale 1ns/1ns
`include "uvm.sv"
import uvm_pkg::*;
`include "uvm_macros.svh"

// In this example, a drain time of 10 is set on the component.


// The component then forks 4 processes which consume different
// amounts of time. When the last process is done (time 85),
// the drain time takes effect. The test is completed at time 95.
// After drain time finished, all_dopped callback takes effect
// which takes 50 timeunit and it is completed at time (at time 145)
class my_agent extends uvm_agent;
`uvm_component_utils(my_agent)
function new (string name="my_agent", uvm_component parent=null);
super.new(name, parent);
endfunction : new

virtual task run_phase(uvm_phase phase);


// Run a bunch of processes in parallel
fork
doit(phase, 85);
doit(phase, 55);
join
endtask : run_phase

// A simple task that consumes some time.


task doit (uvm_phase phase, time delay);
static int s_inst = 0;
int inst = s_inst++;
//Raise an objection before starting the activity
phase.raise_objection(this);

uvm_report_info(get_name(), $sformatf("Starting doit (%0d) with delay %0t", inst, delay),


UVM_NONE);
#delay;
uvm_report_info(get_name(), $sformatf("Ending doit (%0d)", inst), UVM_NONE);

//Drop the objection when done


phase.drop_objection(this);
endtask : doit
endclass : my_agent

class my_env extends uvm_test;


my_agent agent;
`uvm_component_utils(my_env)

function new (string name="my_env", uvm_component parent=null);


super.new(name, parent);
endfunction : new

function void build_phase (uvm_phase phase);


super.build_phase(phase);
agent = my_agent :: type_id :: create ("agent", this);
endfunction : build_phase

virtual task run_phase(uvm_phase phase);


// Run a bunch of processes in parallel
fork
doit(phase, 35);
doit(phase, 60);
join
endtask : run_phase

// A simple task that consumes some time.


task doit (uvm_phase phase, time delay);
static int s_inst = 0;
int inst = s_inst++;
//Raise an objection before starting the activity
phase.raise_objection(this);

uvm_report_info(get_name(), $sformatf("Starting doit (%0d) with delay %0t", inst, delay),


UVM_NONE);
#delay;
uvm_report_info(get_name(), $sformatf("Ending doit (%0d)", inst), UVM_NONE);

//Drop the objection when done


phase.drop_objection(this);
endtask : doit
endclass : my_env

class my_test extends uvm_test;


my_env env;
`uvm_component_utils(my_test)

function new (string name, uvm_component parent);


super.new(name, parent);
endfunction : new

function void build_phase (uvm_phase phase);


super.build_phase(phase);
env = my_env :: type_id::create("env", this);
endfunction : build_phase

virtual task run_phase(uvm_phase phase);


// Set a drain time on the objection if needed
`uvm_info("drain", "Setting drain time of 10", UVM_NONE)
// uvm-1.1d or earlier (depricated in uvm-1.2
//uvm_test_done.set_drain_time(this,10);
// uvm-1.2
phase.phase_done.set_drain_time(this,10);

// Run a bunch of processes in parallel


fork
doit(phase, 25);
doit(phase, 50);
join
endtask : run_phase

// A simple task that consumes some time.


task doit (uvm_phase phase, time delay);
static int s_inst = 0;
int inst = s_inst++;

//Raise an objection before starting the activity


phase.raise_objection(
this, // uvm_object obj
"", // string description=""
1 // int count=1, default value = 1 which increment objection count by 1
);
uvm_report_info(get_name(), $sformatf("Starting doit (%0d) with delay %0t", inst, delay),
UVM_NONE);
#delay;
uvm_report_info(get_name(), $sformatf("Ending doit (%0d)", inst), UVM_NONE);

//Drop the objection when done


phase.drop_objection(
this, // uvm_object obj
"", // string description=""
1 // int count=1, default value = 1 which decrement objection count by 1
);
endtask : doit

// Called when this or a descendant of this component instance raises the specified objection.
// source_obj - the object that originally raised the objection.
// description - optionally provided by the source_obj to give a reason for raising the objection.
// count - indicates the number of objections raised by the source_obj.
virtual function void raised (uvm_objection objection,
uvm_object source_obj,
string description, // 2nd argument of phase.raise_objection method
int count);
`uvm_info("raised", $sformatf("%d objection(s) raised from %s, total count is now %0d",
count, source_obj.get_full_name, objection.get_objection_total(this)), UVM_NONE)
// description is empty
//`uvm_info("raised", $sformatf("description=%s", description), UVM_LOW)
endfunction : raised

// Called when this or a descendant of this component instance drops the specified objection.
// source_obj - the object that originally dropped the objection.
// description - optionally provided by the source_obj to give a reason for dropping the objection.
// count - indicates the number of objections dropped by the source_obj.
virtual function void dropped (uvm_objection objection,
uvm_object source_obj,
string description, // 2nd argument of phase.drop_objection method
int count);
`uvm_info("dropped", $sformatf("%d objection(s) dropped from %s, total count is now %0d",
count, source_obj.get_full_name, objection.get_objection_total(this)), UVM_NONE)
endfunction : dropped

// Called when all objections have been dropped by this component and all its descendants.
// source_obj - the object that dropped the last objection.
// description - optionally provided by the source_obj to give a reason for dropping the objection.
// count - indicates the number of objections dropped by the source_obj.
virtual task all_dropped (uvm_objection objection,
uvm_object source_obj,
string description, // 2nd argument of phase.drop_objection method
int count);
`uvm_info("all_dropped", $sformatf("Last %d objection(s) dropped from %s, total count is now
%0d",
count, source_obj.get_full_name, objection.get_objection_total(this)), UVM_NONE)
#50;
endtask : all_dropped

endclass : my_test

module top;
initial begin
run_test("my_test");
end
endmodule : top
view raw all_dropped.sv hosted with by GitHub

--------------------------------------------------------------------
--------------------------------------------------------------------
//Output:
// UVM_INFO @ 0: reporter [RNTST] Running test my_test...
// UVM_INFO top.sv(94) @ 0: uvm_test_top [drain] Setting drain time of 10
// UVM_INFO top.sv(140) @ 0: uvm_test_top [raised] 1 objection(s) raised from uvm_test_top,
total count is now 1
// UVM_INFO @ 0: uvm_test_top [uvm_test_top] Starting doit (0) with delay 25
// UVM_INFO top.sv(140) @ 0: uvm_test_top [raised] 1 objection(s) raised from uvm_test_top,
total count is now 2
// UVM_INFO @ 0: uvm_test_top [uvm_test_top] Starting doit (1) with delay 50
// UVM_INFO top.sv(140) @ 0: uvm_test_top [raised] 1 objection(s) raised from
uvm_test_top.env, total count is now 3
// UVM_INFO @ 0: uvm_test_top.env [env] Starting doit (0) with delay 35
// UVM_INFO top.sv(140) @ 0: uvm_test_top [raised] 1 objection(s) raised from
uvm_test_top.env, total count is now 4
// UVM_INFO @ 0: uvm_test_top.env [env] Starting doit (1) with delay 60
// UVM_INFO top.sv(140) @ 0: uvm_test_top [raised] 1 objection(s) raised from
uvm_test_top.env.agent, total count is now 5
// UVM_INFO @ 0: uvm_test_top.env.agent [agent] Starting doit (0) with delay 85
// UVM_INFO top.sv(140) @ 0: uvm_test_top [raised] 1 objection(s) raised from
uvm_test_top.env.agent, total count is now 6
// UVM_INFO @ 0: uvm_test_top.env.agent [agent] Starting doit (1) with delay 55
// UVM_INFO @ 25: uvm_test_top [uvm_test_top] Ending doit (0)
// UVM_INFO top.sv(154) @ 25: uvm_test_top [dropped] 1 objection(s) dropped from
uvm_test_top, total count is now 5
// UVM_INFO @ 35: uvm_test_top.env [env] Ending doit (0)
// UVM_INFO top.sv(154) @ 35: uvm_test_top [dropped] 1 objection(s) dropped from
uvm_test_top.env, total count is now 4
// UVM_INFO @ 50: uvm_test_top [uvm_test_top] Ending doit (1)
// UVM_INFO top.sv(154) @ 50: uvm_test_top [dropped] 1 objection(s) dropped from
uvm_test_top, total count is now 3
// UVM_INFO @ 55: uvm_test_top.env.agent [agent] Ending doit (1)
// UVM_INFO top.sv(154) @ 55: uvm_test_top [dropped] 1 objection(s) dropped from
uvm_test_top.env.agent, total count is now 2
// UVM_INFO @ 60: uvm_test_top.env [env] Ending doit (1)
// UVM_INFO top.sv(154) @ 60: uvm_test_top [dropped] 1 objection(s) dropped from
uvm_test_top.env, total count is now 1
// UVM_INFO @ 85: uvm_test_top.env.agent [agent] Ending doit (0)
// UVM_INFO top.sv(154) @ 85: uvm_test_top [dropped] 1 objection(s) dropped from
uvm_test_top.env.agent, total count is now 0
// UVM_INFO top.sv(166) @ 95: uvm_test_top [all_dropped] Last 1 objection(s) dropped from
uvm_test_top.env.agent, total count is now 0
// UVM_INFO /home/shahs/gotcha/uvm/uvm-1.2/src/base/uvm_objection.svh(1271) @ 145:
reporter [TEST_DONE] 'run' phase is ready to proceed to the 'extract' phase
// UVM_INFO /home/shahs/gotcha/uvm/uvm-1.2/src/base/uvm_report_server.svh(847) @ 145:
reporter [UVM/REPORT/SERVER]
view raw all_dropped_output.sv hosted with by GitHub

--------------------------------------------------------------------

Once all the objections are dropped, Drain time takes effect. After Drain time is finished,
all_dropped callback takes effect.
Posted by Sagar Shah No comments:
Email ThisBlogThis!Share to TwitterShare to FacebookShare to Pinterest
Labels: all_dropped, objection, objection callback, set_drain_time, systemverilog, UVM,
verification

Pros and Cons of Pointers in C

Advantages of Pointer:

1) Pointers allow us to perform dynamic memory allocation and deallocation


2) Using pointer we can return more than one value from the function
3) Using pointer can pass array or string more efficiency
4) Pointer helps us to build complex data structure like linked-list, stack, tree, graphs
etc.
5) Pointers permit references to functions and thereby facilitating passing of functions
as arguments to other functions.
6) Use function call by reference.
4) Increase the execution speed of program. how?

Drawback of Pointer:

1) Uninitialized pointers might cause segmentation fault.


2) Dynamically allocated block needs to be freed explicitly. Otherwise, it would lead to
memory leak.
3) If pointers are updated with incorrect values, it might lead to memory corruption.
4) Pointer bugs are difficult to debug.
Posted by Sagar Shah No comments:
Email ThisBlogThis!Share to TwitterShare to FacebookShare to Pinterest
Labels: C, pointer

Thursday, 23 March 2017


Automatic raise/drop objection with UVM-1.2

Variable uvm_sequence_base::starting_phase is deprecated and replaced by two new methods


set_starting_phase and get_starting_phase, which prevent starting_phase from being
modified in the middle of a phase. This change is not backward-compatible with UVM 1.1,
though variable starting_phase, although deprecated, has not yet been removed from the base
class library.

New method uvm_sequence_base::set_automatic_phase_objection causes raise_objection


and drop_objection to be called automatically around a sequence, avoiding the need to call
raise/drop_objection manually in one common situation.

Lets understand it trough below mentioned example.


------------------------------------------------
import uvm_pkg :: *;

class my_seq_item extends uvm_sequence_item;


rand logic [7:0] addr;
rand logic [7:0] data;

constraint addr_range_cn {
addr inside {[10:20]};
}
constraint data_range_cn {
data inside {[100:200]};
}
`uvm_object_utils_begin(my_seq_item)
`uvm_field_int(addr, UVM_ALL_ON| UVM_DEC)
`uvm_field_int(data, UVM_ALL_ON| UVM_DEC)
`uvm_object_utils_end

function new(string name="my_seq_item");


super.new(name);
endfunction : new

virtual function string convert2string();


convert2string = $sformatf("addr=%0d, data=%0d", addr, data);
endfunction : convert2string
endclass : my_seq_item

class my_sequencer extends uvm_sequencer #(my_seq_item);


`uvm_component_utils (my_sequencer)

function new (string name="my_sequencer", uvm_component parent=null);


super.new(name, parent);
endfunction : new
endclass : my_sequencer

class my_driver extends uvm_driver #(my_seq_item);


`uvm_component_utils (my_driver)

function new (string name="my_driver", uvm_component parent=null);


super.new(name, parent);
endfunction : new

function void build_phase (uvm_phase phase);


super.build_phase(phase);
endfunction : build_phase

task run_phase(uvm_phase phase);


forever begin
seq_item_port.get_next_item(req);
`uvm_info(get_name(),
$sformatf("in driver after get_next_item my_seq_item= %s", req.convert2string()),
UVM_LOW);
#50;
`uvm_info(get_name(), $sformatf("item_done called"), UVM_LOW);
seq_item_port.item_done();
end
endtask : run_phase
endclass : my_driver

class my_agent extends uvm_agent;


`uvm_component_utils (my_agent)
my_sequencer sqr;
my_driver drv;

function new (string name="my_agent", uvm_component parent=null);


super.new(name, parent);
endfunction : new

function void build_phase (uvm_phase phase);


super.build_phase(phase);
sqr = my_sequencer :: type_id :: create("sqr", this);
drv = my_driver :: type_id :: create("drv", this);
endfunction : build_phase

function void connect_phase (uvm_phase phase);


super.connect_phase(phase);
drv.seq_item_port.connect(sqr.seq_item_export);
endfunction : connect_phase
endclass : my_agent

class my_seq extends uvm_sequence #(my_seq_item);


`uvm_object_utils (my_seq)
function new(string name="my_seq");
super.new(name);

// The most common interaction with the starting phase


// within a sequence is to simply ~raise~ the phase's objection
// prior to executing the sequence, and ~drop~ the objection
// after ending the sequence (either naturally, or
// via a call to <kill>). In order to
// simplify this interaction for the user, the UVM
// provides the ability to perform this functionality
// automatically.

// From a timeline point of view, the automatic phase objection


// looks like:
//| start() is executed
//| --! Objection is raised !--
//| pre_start() is executed
//| pre_body() is optionally executed
//| body() is executed
//| post_body() is optionally executed
//| post_start() is executed
//| --! Objection is dropped !--
//| start() unblocks

// NEVER set the automatic phase objection bit to 1 if your sequence


// runs with a forever loop inside of the body, as the objection will
// never get dropped!
set_automatic_phase_objection(1);
endfunction : new

task body ();


`uvm_create(req)
if(!req.randomize()) begin
`uvm_fatal(get_name(), $sformatf("Randomization failed"))
end
`uvm_info (get_name(),
$sformatf("After randomizating in my_seq my_seq_item= %s",
req.convert2string()), UVM_LOW)
`uvm_send(req)
endtask : body
endclass : my_seq

class my_test extends uvm_test;


`uvm_component_utils (my_test)
my_agent agent;

function new (string name="my_test", uvm_component parent=null);


super.new(name, parent);
endfunction : new

function void build_phase (uvm_phase phase);


super.build_phase(phase);
agent = my_agent::type_id::create("agent", this);
endfunction : build_phase

task run_phase(uvm_phase phase);


my_seq seq;
uvm_phase starting_phase;
bit automatic_phase_objection_status;
seq = my_seq::type_id::create ("seq");
// Function: set_starting_phase
// Sets the 'starting phase'.
seq.set_starting_phase(phase);

// If set_automatic_phase_objection is not called in new (constructor)


// of sequence then can be calleb from test-case
// seq.set_automatic_phase_objection(1);

fork
begin
#30;
// Function: get_starting_phase
// Returns the 'starting phase'.
// If non-null, the starting phase specifies the phase in which this
// sequence was started.
starting_phase = seq.get_starting_phase();
`uvm_info(get_name(),
$sformatf("starting_phase:%s", starting_phase.get_full_name()), UVM_LOW)

// Function: get_automatic_phase_objection
// Returns (and locks) the value of the 'automatically object to
// starting phase' bit.
//
// If 1, then the sequence will automatically raise an objection
// to the starting phase (if the starting phase is not ~null~) immediately
// prior to <pre_start> being called. The objection will be dropped
// after <post_start> has executed, or <kill> has been called.
automatic_phase_objection_status = seq.get_automatic_phase_objection();
`uvm_info(get_name(),
$sformatf("during seq is running, get_automatic_phase_objection returns :%b",
automatic_phase_objection_status), UVM_LOW)
end
join_none
seq.start(agent.sqr);
automatic_phase_objection_status = seq.get_automatic_phase_objection();
`uvm_info(get_name(),
$sformatf("After seq finished, get_automatic_phase_objection returns :%b",
automatic_phase_objection_status), UVM_LOW)
endtask : run_phase
endclass : my_test

module top();
initial begin
run_test("my_test");
end
endmodule : top

//Output:
// UVM_INFO @ 0: reporter [RNTST] Running test my_test...
// UVM_INFO @ 0: run [OBJTN_TRC] Object uvm_test_top.agent.sqr.seq raised 1 objection(s)
(automatic phase objection): count=1 total=1
// UVM_INFO @ 0: run [OBJTN_TRC] Object uvm_test_top.agent.sqr added 1 objection(s) to
its total (raised from source object , automatic phase objection): count=0 total=1
// UVM_INFO @ 0: run [OBJTN_TRC] Object uvm_test_top.agent added 1 objection(s) to its
total (raised from source object , automatic phase objection): count=0 total=1
// UVM_INFO @ 0: run [OBJTN_TRC] Object uvm_test_top added 1 objection(s) to its total
(raised from source object uvm_test_top.agent.sqr.seq, automatic phase objection): count=0
total=1
// UVM_INFO @ 0: run [OBJTN_TRC] Object uvm_top added 1 objection(s) to its total (raised
from source object uvm_test_top.agent.sqr.seq, automatic phase objection): count=0 total=1
// UVM_INFO testbench.sv(118) @ 0: uvm_test_top.agent.sqr@@seq [seq] After randomizating
in my_seq my_seq_item= addr=19, data=140
// UVM_INFO testbench.sv(50) @ 0: uvm_test_top.agent.drv [drv] in driver after get_next_item
my_seq_item= addr=19, data=140
// UVM_INFO testbench.sv(158) @ 30: uvm_test_top [uvm_test_top]
starting_phase:common.run
// UVM_INFO testbench.sv(170) @ 30: uvm_test_top [uvm_test_top] during seq is running,
get_automatic_phase_objection returns :1
// UVM_INFO testbench.sv(52) @ 50: uvm_test_top.agent.drv [drv] item_done called
// UVM_INFO @ 50: run [OBJTN_TRC] Object uvm_test_top.agent.sqr.seq dropped 1
objection(s) (automatic phase objection): count=0 total=0
// UVM_INFO @ 50: run [OBJTN_TRC] Object uvm_test_top.agent.sqr.seq all_dropped 1
objection(s) (automatic phase objection): count=0 total=0
// UVM_INFO @ 50: run [OBJTN_TRC] Object uvm_test_top.agent.sqr subtracted 1
objection(s) from its total (dropped from source object , automatic phase objection): count=0
total=0
// UVM_INFO @ 50: run [OBJTN_TRC] Object uvm_test_top.agent.sqr subtracted 1
objection(s) from its total (all_dropped from source object , automatic phase objection): count=0
total=0
// UVM_INFO @ 50: run [OBJTN_TRC] Object uvm_test_top.agent subtracted 1 objection(s)
from its total (dropped from source object , automatic phase objection): count=0 total=0
// UVM_INFO @ 50: run [OBJTN_TRC] Object uvm_test_top.agent subtracted 1 objection(s)
from its total (all_dropped from source object , automatic phase objection): count=0 total=0
// UVM_INFO @ 50: run [OBJTN_TRC] Object uvm_test_top subtracted 1 objection(s) from its
total (dropped from source object uvm_test_top.agent.sqr.seq, automatic phase objection):
count=0 total=0
// UVM_INFO @ 50: run [OBJTN_TRC] Object uvm_test_top subtracted 1 objection(s) from its
total (all_dropped from source object uvm_test_top.agent.sqr.seq, automatic phase objection):
count=0 total=0
// UVM_INFO @ 50: run [OBJTN_TRC] Object uvm_top subtracted 1 objection(s) from its total
(dropped from source object uvm_test_top.agent.sqr.seq, automatic phase objection): count=0
total=0
// UVM_INFO @ 50: run [OBJTN_TRC] Object uvm_top subtracted 1 objection(s) from its total
(all_dropped from source object uvm_test_top.agent.sqr.seq, automatic phase objection):
count=0 total=0
// UVM_INFO uvm-1.2/src/base/uvm_objection.svh(1271) @ 50: reporter [TEST_DONE] 'run'
phase is ready to proceed to the 'extract' phase
// UVM_INFO testbench.sv(176) @ 50: uvm_test_top [uvm_test_top] After seq finished,
get_automatic_phase_objection returns :1
// UVM_INFO uvm-1.2/src/base/uvm_report_server.svh(847) @ 50: reporter
[UVM/REPORT/SERVER]
view raw automatic_objection_raise_drop_in_uvm_1_2_ex.sv hosted with by GitHub

------------------------------------------------

Ref:
1) https://www.doulos.com/knowhow/sysverilog/uvm/uvm-1.2/

Posted by Sagar Shah 6 comments:


Email ThisBlogThis!Share to TwitterShare to FacebookShare to Pinterest
Labels: ASIC, automatic objection, drop objection, raise objection, systemverilog, UVM, uvm-
1.2, verification

Simulation timeout in UVM using set_timeout and +UVM_TIMEOUT

Default timeout for simulation or you can say timeout for run_phase (as rest all phases are non-
time consuming) is `UVM_DEFAULT_TIMEOUT, if not overridden by uvm_root::set_timeout
or uvm_cmdline_processor::+UVM_TIMEOUT.

Default value of `UVM_DEFAULT_TIMEOUT is 9200 second.


-------------------------------------------------
uvm-1.2/src/base/uvm_objection.svh
Line 57: `define UVM_DEFAULT_TIMEOUT 9200s
view raw uvm_default_timeout_1.sv hosted with by GitHub
-------------------------------------------------

Example 1 (Timeout at default time which is 9200 second):


-------------------------------------------------
`timescale 1ns/1ns

import uvm_pkg::*;
class test extends uvm_test;
`uvm_component_utils(test)

function new(string name, uvm_component parent = null);


super.new(name, parent);
endfunction : new

function void start_of_simulation_phase(uvm_phase phase);


super.start_of_simulation_phase(phase);
endfunction : start_of_simulation_phase

task pre_main_phase(uvm_phase phase);


phase.raise_objection(this);
#100;
phase.drop_objection(this);
endtask : pre_main_phase

task main_phase(uvm_phase phase);


phase.raise_objection(this);
// Will cause a time-out
// because we forgot to drop the objection
endtask : main_phase

task shutdown_phase(uvm_phase phase);


phase.raise_objection(this);
#100;
phase.drop_objection(this);
endtask : shutdown_phase
endclass : test

module top();
initial begin
run_test("test");
end
endmodule : top

//Output (with +UVM_OBJECTION_TRACE simulation switch):


// UVM_INFO @ 0: reporter [RNTST] Running test test...
// UVM_FATAL uvm-1.2/src/base/uvm_phase.svh(1491) @ 9200000000000: reporter
[PH_TIMEOUT] Default timeout of 9200000000000 hit, indicating a probable testbench issue
// UVM_INFO uvm-1.2/src/base/uvm_report_server.svh(847) @ 9200000000000: reporter
[UVM/REPORT/SERVER]
view raw default_timeout_ex_1.sv hosted with by GitHub
-------------------------------------------------

1) Overridden by uvm_root::set_timeout
-------------------------------------------------
uvm-1.2/src/base/uvm_root.svh
Line 213: // Variable- phase_timeout
// Specifies the timeout for the run phase. Default is `UVM_DEFAULT_TIMEOUT
time phase_timeout = `UVM_DEFAULT_TIMEOUT;

Line 139: // Function: set_timeout


// Specifies the timeout for the simulation. Default is <`UVM_DEFAULT_TIMEOUT>
// The timeout is simply the maximum absolute simulation time allowed before a
// ~FATAL~ occurs. If the timeout is set to 20ns, then the simulation must end
// before 20ns, or a ~FATAL~ timeout will occur.
// This is provided so that the user can prevent the simulation from potentially
// consuming too many resources (Disk, Memory, CPU, etc) when the testbench is
// essentially hung.
function void uvm_root::set_timeout(time timeout, bit overridable=1);
static bit m_uvm_timeout_overridable = 1;
if (m_uvm_timeout_overridable == 0) begin
uvm_report_info("NOTIMOUTOVR",
$sformatf("The global timeout setting of %0d is not overridable to %0d due to a previous
setting.",
phase_timeout, timeout), UVM_NONE);
return;
end
m_uvm_timeout_overridable = overridable;
phase_timeout = timeout;
endfunction
view raw uvm_default_timeout_2.sv hosted with by GitHub
-------------------------------------------------
-------------------------------------------------
uvm-1.2/src/base/uvm_phase.svh
Line 1297: task uvm_phase::execute_phase();
uvm_task_phase task_phase;
uvm_root top;
uvm_phase_state_change state_chg;
uvm_coreservice_t cs;

cs = uvm_coreservice_t::get();
top = cs.get_root();
...........
// TIMEOUT
begin
if (this.get_name() == "run") begin
if (top.phase_timeout == 0)
wait(top.phase_timeout != 0);
if (m_phase_trace)
`UVM_PH_TRACE("PH/TRC/TO_WAIT", $sformatf("STARTING PHASE TIMEOUT
WATCHDOG (timeout == %t)", top.phase_timeout), this, UVM_HIGH)
`uvm_delay(top.phase_timeout)
if ($time == `UVM_DEFAULT_TIMEOUT) begin
if (m_phase_trace)
`UVM_PH_TRACE("PH/TRC/TIMEOUT", "PHASE TIMEOUT WATCHDOG EXPIRED",
this, UVM_LOW)
foreach (m_executing_phases[p]) begin
if ((p.phase_done != null) && (p.phase_done.get_objection_total() > 0)) begin
if (m_phase_trace)
`UVM_PH_TRACE("PH/TRC/TIMEOUT/OBJCTN",
$sformatf("Phase '%s' has outstanding objections:\n%s", p.get_full_name(),
p.phase_done.convert2string()),
this,
UVM_LOW)
end
end

`uvm_fatal("PH_TIMEOUT",
$sformatf("Default timeout of %0t hit, indicating a probable testbench issue",
`UVM_DEFAULT_TIMEOUT))
end
else begin
if (m_phase_trace)
`UVM_PH_TRACE("PH/TRC/TIMEOUT", "PHASE TIMEOUT WATCHDOG EXPIRED",
this, UVM_LOW)
foreach (m_executing_phases[p]) begin
if ((p.phase_done != null) && (p.phase_done.get_objection_total() > 0)) begin
if (m_phase_trace)
`UVM_PH_TRACE("PH/TRC/TIMEOUT/OBJCTN",
$sformatf("Phase '%s' has outstanding objections:\n%s", p.get_full_name(),
p.phase_done.convert2string()),
this,
UVM_LOW)
end
end

`uvm_fatal("PH_TIMEOUT",
$sformatf("Explicit timeout of %0t hit, indicating a probable testbench issue",
top.phase_timeout))
end
if (m_phase_trace)
`UVM_PH_TRACE("PH/TRC/EXE/3","PHASE EXIT TIMEOUT",this,UVM_DEBUG)
end // if (this.get_name() == "run")
else begin
wait (0); // never unblock for non-run phase
end
end // if (m_phase_trace)
view raw uvm_default_timeout_3.sv hosted with by GitHub
-------------------------------------------------

Example 2 (Timeout at specified time which is specified using set_timeout):


-------------------------------------------------
`timescale 1ns/1ns

import uvm_pkg::*;
class test extends uvm_test;
`uvm_component_utils(test)

function new(string name, uvm_component parent = null);


super.new(name, parent);
endfunction : new

function void start_of_simulation_phase(uvm_phase phase);


super.start_of_simulation_phase(phase);
// uvm_top is a constant handle of uvm_root declared in uvm_root.svh file
uvm_top.set_timeout(100s, 1); // Override default timeout to 1oo second
// or you can use below syntax as well
// uvm_root::get().set_timeout(100s, 1);
endfunction : start_of_simulation_phase

task pre_main_phase(uvm_phase phase);


phase.raise_objection(this);
#100;
phase.drop_objection(this);
endtask : pre_main_phase

task main_phase(uvm_phase phase);


phase.raise_objection(this);
// Will cause a time-out
// because we forgot to drop the objection
endtask : main_phase

task shutdown_phase(uvm_phase phase);


phase.raise_objection(this);
#100;
phase.drop_objection(this);
endtask : shutdown_phase
endclass : test

module top();
initial begin
run_test("test");
end
endmodule : top

//Output:
// UVM_INFO @ 0: reporter [RNTST] Running test test...
// UVM_FATAL uvm-1.2/src/base/uvm_phase.svh(1508) @ 100000000000: reporter
[PH_TIMEOUT] Explicit timeout of 100000000000 hit, indicating a probable testbench issue
// UVM_INFO uvm-1.2/src/base/uvm_report_server.svh(847) @ 100000000000: reporter
[UVM/REPORT/SERVER]
view raw set_timeout_ex.sv hosted with by GitHub
-------------------------------------------------

2) Overridden by
uvm_cmdline_processor::+UVM_TIMEOUT
+UVM_TIMEOUT=, allows users to change the global timeout of the UVM framework. The
argument (YES or NO) specifies whether user code can subsequently change this value. If
set to NO and the user code tries to change the global timeout value, a warning message will be
generated.

Example 3 (Timeout at 100s using simulation switch +UVM_TIMEOUT=100000000000):


Note: Here you need to give simulation time in format of timescale defined in simulation
-------------------------------------------------
`timescale 1ns/1ns

import uvm_pkg::*;
class test extends uvm_test;
`uvm_component_utils(test)

function new(string name, uvm_component parent = null);


super.new(name, parent);
endfunction : new

function void start_of_simulation_phase(uvm_phase phase);


super.start_of_simulation_phase(phase);
endfunction : start_of_simulation_phase

task pre_main_phase(uvm_phase phase);


phase.raise_objection(this);
#100;
phase.drop_objection(this);
endtask : pre_main_phase

task main_phase(uvm_phase phase);


phase.raise_objection(this);
// Will cause a time-out
// because we forgot to drop the objection
endtask : main_phase

task shutdown_phase(uvm_phase phase);


phase.raise_objection(this);
#100;
phase.drop_objection(this);
endtask : shutdown_phase
endclass : test

module top();
initial begin
run_test("test");
end
endmodule : top

//Output:
// UVM_INFO @ 0: reporter [RNTST] Running test test...
// UVM_INFO @ 0: reporter [TIMOUTSET] '+UVM_TIMEOUT=100000000000' provided on
the command line is being applied.
// UVM_FATAL uvm-1.2/src/base/uvm_phase.svh(1508) @ 100000000000: reporter
[PH_TIMEOUT] Explicit timeout of 100000000000 hit, indicating a probable testbench issue
// UVM_INFO uvm-1.2/src/base/uvm_report_server.svh(847) @ 100000000000: reporter
[UVM/REPORT/SERVER]
view raw cmd_uvm_timeout_ex.sv hosted with by GitHub
-------------------------------------------------
Posted by Sagar Shah No comments:
Email ThisBlogThis!Share to TwitterShare to FacebookShare to Pinterest
Labels: ASI, global timeout, set_timeout, systemverilog, UVM, UVM_DEFAULT_TIMEOUT,
UVM_TIMEOUT, verification

Tuesday, 21 February 2017


Lock and Grab of sequencer in UVM
There are a number of modelling scenarios where one sequence needs to have exclusive access
to a driver via a sequencer. One example of this type of scenario is a sequence which is
responding to an interrupt.
In order to accommodate this requirement, the uvm_sequencer provides 2 types of mechanism
called lock()-unlock() and grab()-ungrab().

If sequencer is doing some sequence and based on some external events if user wants sequencer
to pause the current sequence, he/she can grab/lock sequencer and start another sequence. Once
the started sequence finishes sequencer can resume the normal operation, upon ungrab/unlock.
This mechanism is generally used to mimic CPU behavior, where CPU is doing a normal bus
operation and when interrupt comes, CPU needs to suspend the normal operation and start
interrupt handling. Once interrupt handling is over, CPU should resume the normal operation
from where it was suspended.

A lock might be used to model a prioritized interrupt and a grab might be used to model a non-
mask able interrupt (NMI).
The lock() and grab() calls have antidote calls to release a lock and these are unlock() and
ungrab().

Lock()
1) A lock() request is put in back of the arbitration queue . A lock request will be arbitrated the
same as any other request.
2) A lock is granted after all earlier requests are completed and no other locks or grabs are
blocking this sequence.
3) A lock() is blocking task and when access is granted, it will unblock.
4) If no argument is supplied, then current default sequencer is chosen.

Grab()
1) A grab() request is put in front of the arbitration queue. A grab() request will be arbitrated
before any other requests.
2) A grab() is granted when no other grabs or locks are blocking this sequence. (The only thing
that stops a sequence from grabbing a sequencer is a pre-existing lock() or grab() condition.)
3) A grab() is blocking task and when access is granted, it will unblock.
4) If no argument is supplied, then current default sequencer is chosen.

Unlock()
The unlock sequencer function is called from within a sequence to give up its lock or grab. A
locking sequence must call unlock before completion; otherwise the sequencer will remain
locked.

Ungrab()
An alias of function unlock().
What happens if 2 sequences try to grab or lock the same sequencer?
The most recent grab goes to the front of the queue; the most recent lock goes to the back of the
queue.

Priority in lock() and grab().


The most recent grab comes first, then the previous grab... then the oldest lock, then the most
recent lock.

Lets go through basic example of lock() and grab()


1) Lock
---------------------------------------------
`include "uvm_pkg.sv"
import uvm_pkg::*;

typedef enum {PUSH_A,PUSH_B,ADD,SUB,MUL,DIV,POP_C} inst_e;

//-----Packet/Transaction-----
class my_seq_item extends uvm_sequence_item;
rand inst_e inst;
`uvm_object_utils_begin(my_seq_item)
`uvm_field_enum(inst_e,inst, UVM_DEFAULT)
`uvm_object_utils_end

function new (string name = "my_seq_item");


super.new(name);
endfunction : new

function string convert2string();


convert2string = $sformatf("inst:%s", inst.name());
endfunction : convert2string
endclass : my_seq_item

//-----Sequencer-----
class my_sequencer extends uvm_sequencer #(my_seq_item);
`uvm_sequencer_utils(my_sequencer)

function new (string name = "my_sequencer", uvm_component parent = null);


super.new(name, parent);
`uvm_update_sequence_lib_and_item(my_seq_item)
endfunction : new
endclass : my_sequencer

//-----Driver-----
class my_driver extends uvm_driver #(my_seq_item);
`uvm_component_utils(my_driver)

function new (string name = "my_driver", uvm_component parent = null);


super.new(name, parent);
endfunction : new

task run_phase (uvm_phase phase);


forever begin
seq_item_port.get_next_item(req);
$display($time," Driving pkt %s", req.convert2string());
#10;
seq_item_port.item_done();
end
endtask : run_phase
endclass : my_driver

//-----Agent-----
class my_agent extends uvm_agent;
my_sequencer sqr;
my_driver drv;
`uvm_component_utils(my_agent)

function new (string name = "my_agent", uvm_component parent = null);


super.new(name, parent);
endfunction : new

function void build_phase (uvm_phase phase);


super.build_phase(phase);
sqr = my_sequencer::type_id::create("sqr", this);
drv = my_driver::type_id::create("drv", this);
endfunction : build_phase

function void connect_phase (uvm_phase phase);


super.connect_phase(phase);
drv.seq_item_port.connect(sqr.seq_item_export);
endfunction : connect_phase
endclass : my_agent

//-----seq_a-----
class seq_a extends uvm_sequence #(my_seq_item);
my_seq_item req;
`uvm_object_utils(seq_a)

function new(string name="seq_a");


super.new(name);
endfunction : new

virtual task body();


repeat(4) begin
`uvm_do_with(req, { inst == PUSH_A; });
end
endtask : body
endclass : seq_a

//-----seq_b-----
class seq_b extends uvm_sequence #(my_seq_item);
my_seq_item req;
`uvm_object_utils(seq_b)

function new(string name="seq_b");


super.new(name);
endfunction : new
virtual task body();
lock(); // or lock(m_sequencer);
repeat(4) begin
`uvm_do_with(req, { inst == PUSH_B; });
end
unlock(); // or unlock(m_sequencer);
endtask : body
endclass : seq_b

//-----seq_c-----
class seq_c extends uvm_sequence #(my_seq_item);
my_seq_item req;
`uvm_object_utils(seq_c)

function new(string name="seq_c");


super.new(name);
endfunction : new

virtual task body();


repeat(4) begin
`uvm_do_with(req, { inst == POP_C; });
end
endtask : body
endclass : seq_c

//-----Virtual sequence-----
class parallel_sequence extends uvm_sequence #(my_seq_item);
seq_a s_a;
seq_b s_b;
seq_c s_c;
`uvm_object_utils(parallel_sequence)

function new(string name="parallel_sequence");


super.new(name);
endfunction : new

virtual task body();


s_a = seq_a::type_id::create("s_a");
s_b = seq_b::type_id::create("s_b");
s_c = seq_c::type_id::create("s_c");
fork
s_a.start(m_sequencer);
s_b.start(m_sequencer);
s_c.start(m_sequencer);
join
endtask : body
endclass : parallel_sequence

//-----Test-----
class my_test extends uvm_test;
my_agent agent;
`uvm_component_utils(my_test)

function new (string name = "my_test", uvm_component parent = null);


super.new(name, parent);
endfunction : new

function void build_phase (uvm_phase phase);


super.build_phase(phase);
agent = my_agent::type_id::create("agent", this);
endfunction : build_phase

task run_phase(uvm_phase phase);


parallel_sequence p_seq;
p_seq = parallel_sequence::type_id::create("p_seq");
phase.raise_objection(this);
p_seq.start(agent.sqr);
phase.drop_objection(this);
endtask : run_phase
endclass : my_test

module top();
initial begin
run_test("my_test");
end
endmodule : top

// Output:
// 0 Driving pkt inst:PUSH_A
// 10 Driving pkt inst:PUSH_B
// 20 Driving pkt inst:PUSH_B
// 30 Driving pkt inst:PUSH_B
// 40 Driving pkt inst:PUSH_B
// 50 Driving pkt inst:POP_C
// 60 Driving pkt inst:PUSH_A
// 70 Driving pkt inst:POP_C
// 80 Driving pkt inst:PUSH_A
// 90 Driving pkt inst:POP_C
// 100 Driving pkt inst:PUSH_A
// 110 Driving pkt inst:POP_C
view raw lock_in_uvm.sv hosted with by GitHub
---------------------------------------------

2) Grab
---------------------------------------------
`include "uvm_pkg.sv"
import uvm_pkg::*;

typedef enum {PUSH_A,PUSH_B,ADD,SUB,MUL,DIV,POP_C} inst_e;


//-----Packet/Transaction-----
class my_seq_item extends uvm_sequence_item;
rand inst_e inst;
`uvm_object_utils_begin(my_seq_item)
`uvm_field_enum(inst_e,inst, UVM_DEFAULT)
`uvm_object_utils_end

function new (string name = "my_seq_item");


super.new(name);
endfunction : new

function string convert2string();


convert2string = $sformatf("inst:%s", inst.name());
endfunction : convert2string
endclass : my_seq_item

//-----Sequencer-----
class my_sequencer extends uvm_sequencer #(my_seq_item);
`uvm_sequencer_utils(my_sequencer)

function new (string name = "my_sequencer", uvm_component parent = null);


super.new(name, parent);
`uvm_update_sequence_lib_and_item(my_seq_item)
endfunction : new
endclass : my_sequencer

//-----Driver-----
class my_driver extends uvm_driver #(my_seq_item);
`uvm_component_utils(my_driver)

function new (string name = "my_driver", uvm_component parent = null);


super.new(name, parent);
endfunction : new

task run_phase (uvm_phase phase);


forever begin
seq_item_port.get_next_item(req);
$display($time," Driving pkt %s", req.convert2string());
#10;
seq_item_port.item_done();
end
endtask : run_phase
endclass : my_driver

//-----Agent-----
class my_agent extends uvm_agent;
my_sequencer sqr;
my_driver drv;
`uvm_component_utils(my_agent)

function new (string name = "my_agent", uvm_component parent = null);


super.new(name, parent);
endfunction : new

function void build_phase (uvm_phase phase);


super.build_phase(phase);
sqr = my_sequencer::type_id::create("sqr", this);
drv = my_driver::type_id::create("drv", this);
endfunction : build_phase

function void connect_phase (uvm_phase phase);


super.connect_phase(phase);
drv.seq_item_port.connect(sqr.seq_item_export);
endfunction : connect_phase
endclass : my_agent

//-----seq_a-----
class seq_a extends uvm_sequence #(my_seq_item);
my_seq_item req;
`uvm_object_utils(seq_a)

function new(string name="seq_a");


super.new(name);
endfunction : new

virtual task body();


repeat(4) begin
`uvm_do_with(req, { inst == PUSH_A; });
end
endtask : body
endclass : seq_a

//-----seq_b-----
class seq_b extends uvm_sequence #(my_seq_item);
my_seq_item req;
`uvm_object_utils(seq_b)

function new(string name="seq_b");


super.new(name);
endfunction : new

virtual task body();


grab(); // or grab(m_sequencer);
repeat(4) begin
`uvm_do_with(req, { inst == PUSH_B; });
end
ungrab(); // or ungrab(m_sequencer);
endtask : body
endclass : seq_b

//-----seq_c-----
class seq_c extends uvm_sequence #(my_seq_item);
my_seq_item req;
`uvm_object_utils(seq_c)

function new(string name="seq_c");


super.new(name);
endfunction : new

virtual task body();


repeat(4) begin
`uvm_do_with(req, { inst == POP_C; });
end
endtask : body
endclass : seq_c

//-----Virtual Sequence-----
class parallel_sequence extends uvm_sequence #(my_seq_item);
seq_a s_a;
seq_b s_b;
seq_c s_c;
`uvm_object_utils(parallel_sequence)

function new(string name="parallel_sequence");


super.new(name);
endfunction : new

virtual task body();


fork
`uvm_do(s_a)
`uvm_do(s_b)
`uvm_do(s_c)
join
endtask : body
endclass : parallel_sequence
//-----Test-----
class my_test extends uvm_test;
my_agent agent;
`uvm_component_utils(my_test)

function new (string name = "my_test", uvm_component parent = null);


super.new(name, parent);
endfunction : new

function void build_phase (uvm_phase phase);


super.build_phase(phase);
agent = my_agent::type_id::create("agent", this);
endfunction : build_phase

task run_phase(uvm_phase phase);


parallel_sequence p_seq;
p_seq = parallel_sequence::type_id::create("p_seq");
phase.raise_objection(this);
p_seq.start(agent.sqr);
phase.drop_objection(this);
endtask : run_phase
endclass : my_test

module top();
initial begin
run_test("my_test");
end
endmodule : top

// Output:
// 0 Driving pkt inst:PUSH_B
// 10 Driving pkt inst:PUSH_B
// 20 Driving pkt inst:PUSH_B
// 30 Driving pkt inst:PUSH_B
// 40 Driving pkt inst:PUSH_A
// 50 Driving pkt inst:POP_C
// 60 Driving pkt inst:PUSH_A
// 70 Driving pkt inst:POP_C
// 80 Driving pkt inst:PUSH_A
// 90 Driving pkt inst:POP_C
// 100 Driving pkt inst:PUSH_A
// 110 Driving pkt inst:POP_C
view raw grab_in_uvm.sv hosted with by GitHub
---------------------------------------------
From output of above two examples, we can see the difference between lock() and grab() as
mentioned above.

When a hierarchical sequence locks/grab a sequencer, then its child sequences will have access
to the sequencer.
If one of the child sequences issues a lock/grab, then the parent sequence will not be able to start
any parallel sequences or send any sequence_items until the child sequence has unlocked.
---------------------------------------------
`include "uvm_pkg.sv"
import uvm_pkg::*;

typedef enum {PUSH_A,PUSH_B,ADD,SUB,MUL,DIV,POP_C} inst_e;

//-----Packet/Transaction-----
class my_seq_item extends uvm_sequence_item;
rand inst_e inst;
`uvm_object_utils_begin(my_seq_item)
`uvm_field_enum(inst_e,inst, UVM_DEFAULT)
`uvm_object_utils_end

function new (string name = "my_seq_item");


super.new(name);
endfunction : new
function string convert2string();
convert2string = $sformatf("inst:%s", inst.name());
endfunction : convert2string
endclass : my_seq_item

//-----Sequencer-----
class my_sequencer extends uvm_sequencer #(my_seq_item);
`uvm_sequencer_utils(my_sequencer)

function new (string name = "my_sequencer", uvm_component parent = null);


super.new(name, parent);
`uvm_update_sequence_lib_and_item(my_seq_item)
endfunction : new
endclass : my_sequencer

//-----Driver-----
class my_driver extends uvm_driver #(my_seq_item);
`uvm_component_utils(my_driver)

function new (string name = "my_driver", uvm_component parent = null);


super.new(name, parent);
endfunction : new

task run_phase (uvm_phase phase);


forever begin
seq_item_port.get_next_item(req);
$display($time," Driving pkt %s", req.convert2string());
#10;
seq_item_port.item_done();
end
endtask : run_phase
endclass : my_driver

//-----Agent-----
class my_agent extends uvm_agent;
my_sequencer sqr;
my_driver drv;
`uvm_component_utils(my_agent)

function new (string name = "my_agent", uvm_component parent = null);


super.new(name, parent);
endfunction : new

function void build_phase (uvm_phase phase);


super.build_phase(phase);
sqr = my_sequencer::type_id::create("sqr", this);
drv = my_driver::type_id::create("drv", this);
endfunction : build_phase

function void connect_phase (uvm_phase phase);


super.connect_phase(phase);
drv.seq_item_port.connect(sqr.seq_item_export);
endfunction : connect_phase
endclass : my_agent

//-----Virtual Sequencer-----
class my_virtual_sqr extends uvm_sequencer;
my_sequencer sqr1;
my_sequencer sqr2;
`uvm_component_utils(my_virtual_sqr)

function new (string name = "my_virtual_sqr", uvm_component parent = null);


super.new(name, parent);
endfunction : new

endclass : my_virtual_sqr

//-----seq_a-----
class seq_a extends uvm_sequence #(my_seq_item);
my_seq_item req;
`uvm_object_utils(seq_a)

function new(string name="seq_a");


super.new(name);
endfunction : new

virtual task body();


repeat(4) begin
`uvm_do_with(req, { inst == PUSH_A; });
end
endtask : body
endclass : seq_a

//-----seq_b-----
class seq_b extends uvm_sequence #(my_seq_item);
my_seq_item req;
`uvm_object_utils(seq_b)

function new(string name="seq_b");


super.new(name);
endfunction : new

virtual task body();


repeat(4) begin
`uvm_do_with(req, { inst == PUSH_B; });
end
endtask : body
endclass : seq_b

//-----seq_c-----
class seq_c extends uvm_sequence #(my_seq_item);
my_seq_item req;
`uvm_object_utils(seq_c)
function new(string name="seq_c");
super.new(name);
endfunction : new

virtual task body();


repeat(4) begin
`uvm_do_with(req, { inst == POP_C; });
end
endtask : body
endclass : seq_c

//-----Virtual Sequence-----
class parallel_sequence extends uvm_sequence #(my_seq_item);
seq_a s_a;
seq_b s_b;
seq_c s_c;
`uvm_object_utils(parallel_sequence)

`uvm_declare_p_sequencer(my_virtual_sqr)

function new(string name="parallel_sequence");


super.new(name);
endfunction : new

virtual task body();


// parallel_sequence put grab on sequencer sqr1,
// but still it's child sequences (seq_a, seq_b, seq_c) will have access of sequencer sqr1
grab(p_sequencer.sqr1);
fork
begin
`uvm_create_on(s_a, p_sequencer.sqr1)
`uvm_rand_send(s_a)
end
begin
`uvm_create_on(s_b, p_sequencer.sqr1)
`uvm_rand_send(s_b)
end
begin
`uvm_create_on(s_c, p_sequencer.sqr1)
`uvm_rand_send(s_c)
end
join
ungrab(p_sequencer.sqr1);
endtask : body
endclass : parallel_sequence

//-----Test-----
class my_test extends uvm_test;
my_agent agent1;
my_agent agent2;
my_virtual_sqr vsqr;
`uvm_component_utils(my_test)

function new (string name = "my_test", uvm_component parent = null);


super.new(name, parent);
endfunction : new

function void build_phase (uvm_phase phase);


super.build_phase(phase);
agent1 = my_agent::type_id::create("agent1", this);
agent2 = my_agent::type_id::create("agent2", this);
vsqr = my_virtual_sqr::type_id::create("vsqr", this);
endfunction : build_phase

function void connect_phase(uvm_phase phase);


super.connect_phase(phase);
vsqr.sqr1 = agent1.sqr;
vsqr.sqr2 = agent2.sqr;
endfunction : connect_phase

task run_phase(uvm_phase phase);


parallel_sequence p_seq;
p_seq = parallel_sequence::type_id::create("p_seq");
phase.raise_objection(this);
p_seq.start(vsqr);
phase.drop_objection(this);
endtask : run_phase
endclass : my_test

module top();
initial begin
run_test("my_test");
end
endmodule : top

// Output:
// 0 Driving pkt inst:PUSH_A
// 10 Driving pkt inst:PUSH_B
// 20 Driving pkt inst:POP_C
// 30 Driving pkt inst:PUSH_A
// 40 Driving pkt inst:PUSH_B
// 50 Driving pkt inst:POP_C
// 60 Driving pkt inst:PUSH_A
// 70 Driving pkt inst:PUSH_B
// 80 Driving pkt inst:POP_C
// 90 Driving pkt inst:PUSH_A
// 100 Driving pkt inst:PUSH_B
// 110 Driving pkt inst:POP_C
view raw child_has_access_of_grab_lock_sqr.sv hosted with by GitHub
---------------------------------------------

A locking or grabbing sequence must always unlock before it completes,


---------------------------------------------
`include "uvm_pkg.sv"
import uvm_pkg::*;

typedef enum {PUSH_A,PUSH_B,ADD,SUB,MUL,DIV,POP_C} inst_e;

//-----Packet/Transaction-----
class my_seq_item extends uvm_sequence_item;
rand inst_e inst;
`uvm_object_utils_begin(my_seq_item)
`uvm_field_enum(inst_e,inst, UVM_DEFAULT)
`uvm_object_utils_end

function new (string name = "my_seq_item");


super.new(name);
endfunction : new

function string convert2string();


convert2string = $sformatf("inst:%s", inst.name());
endfunction : convert2string
endclass : my_seq_item

//-----Sequencer-----
class my_sequencer extends uvm_sequencer #(my_seq_item);
`uvm_sequencer_utils(my_sequencer)

function new (string name = "my_sequencer", uvm_component parent = null);


super.new(name, parent);
`uvm_update_sequence_lib_and_item(my_seq_item)
endfunction : new
endclass : my_sequencer
//-----Driver-----
class my_driver extends uvm_driver #(my_seq_item);
`uvm_component_utils(my_driver)

function new (string name = "my_driver", uvm_component parent = null);


super.new(name, parent);
endfunction : new

task run_phase (uvm_phase phase);


forever begin
seq_item_port.get_next_item(req);
$display($time," Driving pkt %s", req.convert2string());
#10;
seq_item_port.item_done();
end
endtask : run_phase
endclass : my_driver

//-----Agent-----
class my_agent extends uvm_agent;
my_sequencer sqr;
my_driver drv;
`uvm_component_utils(my_agent)

function new (string name = "my_agent", uvm_component parent = null);


super.new(name, parent);
endfunction : new

function void build_phase (uvm_phase phase);


super.build_phase(phase);
sqr = my_sequencer::type_id::create("sqr", this);
drv = my_driver::type_id::create("drv", this);
endfunction : build_phase
function void connect_phase (uvm_phase phase);
super.connect_phase(phase);
drv.seq_item_port.connect(sqr.seq_item_export);
endfunction : connect_phase
endclass : my_agent

//-----Virtual Sequencer-----
class my_virtual_sqr extends uvm_sequencer;
my_sequencer sqr1;
my_sequencer sqr2;
`uvm_component_utils(my_virtual_sqr)

function new (string name = "my_virtual_sqr", uvm_component parent = null);


super.new(name, parent);
endfunction : new

endclass : my_virtual_sqr

//-----seq_a-----
class seq_a extends uvm_sequence #(my_seq_item);
my_seq_item req;
`uvm_object_utils(seq_a)

function new(string name="seq_a");


super.new(name);
endfunction : new

virtual task body();


repeat(4) begin
`uvm_do_with(req, { inst == PUSH_A; });
end
endtask : body
endclass : seq_a

//-----seq_b-----
class seq_b extends uvm_sequence #(my_seq_item);
my_seq_item req;
`uvm_object_utils(seq_b)

function new(string name="seq_b");


super.new(name);
endfunction : new

virtual task body();


repeat(4) begin
`uvm_do_with(req, { inst == PUSH_B; });
end
endtask : body
endclass : seq_b

//-----seq_c-----
class seq_c extends uvm_sequence #(my_seq_item);
my_seq_item req;
`uvm_object_utils(seq_c)

function new(string name="seq_c");


super.new(name);
endfunction : new

virtual task body();


repeat(4) begin
`uvm_do_with(req, { inst == POP_C; });
end
endtask : body
endclass : seq_c

//-----Virtual Sequence-----
class parallel_sequence extends uvm_sequence #(my_seq_item);
seq_a s_a;
seq_b s_b;
seq_c s_c;
`uvm_object_utils(parallel_sequence)
`uvm_declare_p_sequencer(my_virtual_sqr)

function new(string name="parallel_sequence");


super.new(name);
endfunction : new

virtual task body();


fork
begin
`uvm_create_on(s_a, p_sequencer.sqr1)
`uvm_rand_send(s_a)
end
begin
`uvm_create_on(s_b, p_sequencer.sqr1)
s_b.grab(p_sequencer.sqr1);
// or p_sequencer.sqr1.grab(s_b);
`uvm_rand_send(s_b)
s_b.ungrab(p_sequencer.sqr1);
// or p_sequencer.sqr1.ungrab(s_b);
ungrab(p_sequencer.sqr1);
end
begin
`uvm_create_on(s_c, p_sequencer.sqr1)
`uvm_rand_send(s_c)
end
join
endtask : body
endclass : parallel_sequence
//-----Test-----
class my_test extends uvm_test;
my_agent agent1;
my_agent agent2;
my_virtual_sqr vsqr;
`uvm_component_utils(my_test)

function new (string name = "my_test", uvm_component parent = null);


super.new(name, parent);
endfunction : new

function void build_phase (uvm_phase phase);


super.build_phase(phase);
agent1 = my_agent::type_id::create("agent1", this);
agent2 = my_agent::type_id::create("agent2", this);
vsqr = my_virtual_sqr::type_id::create("vsqr", this);
endfunction : build_phase

function void connect_phase(uvm_phase phase);


super.connect_phase(phase);
vsqr.sqr1 = agent1.sqr;
vsqr.sqr2 = agent2.sqr;
endfunction : connect_phase

task run_phase(uvm_phase phase);


parallel_sequence p_seq;
p_seq = parallel_sequence::type_id::create("p_seq");
phase.raise_objection(this);
p_seq.start(vsqr);
phase.drop_objection(this);
endtask : run_phase
endclass : my_test
module top();
initial begin
run_test("my_test");
end
endmodule : top

// Output:
// 0 Driving pkt inst:PUSH_B
// 10 Driving pkt inst:PUSH_B
// 20 Driving pkt inst:PUSH_B
// 30 Driving pkt inst:PUSH_B
// UVM_ERROR .../uvm-1.2/seq/uvm_sequencer_base.svh(1296) @ 40:
uvm_test_top.agent1.sqr [SEQFINERR] Parent sequence 'uvm_test_top.vsqr.p_seq.s_b' should
not finish before locks from itself and descedent sequences are removed. The lock held by the
child sequence 'uvm_test_top.vsqr.p_seq.s_b' is being removed.
// UVM_WARNING @ 40: uvm_test_top.agent1.sqr [SQRUNL] Sequence
'uvm_test_top.vsqr.p_seq.s_b' called ungrab / unlock, but didn't have lock
// UVM_WARNING @ 40: uvm_test_top.agent1.sqr [SQRUNL] Sequence
'uvm_test_top.vsqr.p_seq' called ungrab / unlock, but didn't have lock
// 40 Driving pkt inst:PUSH_A
// 50 Driving pkt inst:POP_C
// 60 Driving pkt inst:PUSH_A
// 70 Driving pkt inst:POP_C
// 80 Driving pkt inst:PUSH_A
// 90 Driving pkt inst:POP_C
// 100 Driving pkt inst:PUSH_A
// 110 Driving pkt inst:POP_C
view raw unlock_after_seq_finished.sv hosted with by GitHub
---------------------------------------------

Now lets go through one example where 2 virtual sequences are running in parallel and one
virtual sequence put lock/grab on agents sequencer.

---------------------------------------------
`include "uvm_pkg.sv"
import uvm_pkg::*;

typedef enum {PUSH_A,PUSH_B,ADD,SUB,MUL,DIV,POP_C} inst_e;

//-----Packet/Transaction-----
class my_seq_item extends uvm_sequence_item;
rand inst_e inst;
`uvm_object_utils_begin(my_seq_item)
`uvm_field_enum(inst_e,inst, UVM_DEFAULT)
`uvm_object_utils_end

function new (string name = "my_seq_item");


super.new(name);
endfunction : new

function string convert2string();


convert2string = $sformatf("inst:%s", inst.name());
endfunction : convert2string
endclass : my_seq_item

//-----Sequencer-----
class my_sequencer extends uvm_sequencer #(my_seq_item);
`uvm_sequencer_utils(my_sequencer)

function new (string name = "my_sequencer", uvm_component parent = null);


super.new(name, parent);
`uvm_update_sequence_lib_and_item(my_seq_item)
endfunction : new
endclass : my_sequencer

//-----Driver-----
class my_driver extends uvm_driver #(my_seq_item);
`uvm_component_utils(my_driver)

function new (string name = "my_driver", uvm_component parent = null);


super.new(name, parent);
endfunction : new

task run_phase (uvm_phase phase);


forever begin
seq_item_port.get_next_item(req);
`uvm_info(get_name(), $sformatf("Driving pkt %s", req.convert2string()), UVM_LOW)
#10;
seq_item_port.item_done();
end
endtask : run_phase
endclass : my_driver

//-----Agent-----
class my_agent extends uvm_agent;
my_sequencer sqr;
my_driver drv;
`uvm_component_utils(my_agent)

function new (string name = "my_agent", uvm_component parent = null);


super.new(name, parent);
endfunction : new

function void build_phase (uvm_phase phase);


super.build_phase(phase);
sqr = my_sequencer::type_id::create("sqr", this);
drv = my_driver::type_id::create("drv", this);
endfunction : build_phase

function void connect_phase (uvm_phase phase);


super.connect_phase(phase);
drv.seq_item_port.connect(sqr.seq_item_export);
endfunction : connect_phase
endclass : my_agent

//-----Virtual Sequencer-----
class my_virtual_sqr extends uvm_sequencer;
my_sequencer sqr1;
my_sequencer sqr2;
`uvm_component_utils(my_virtual_sqr)

function new (string name = "my_virtual_sqr", uvm_component parent = null);


super.new(name, parent);
endfunction : new
endclass : my_virtual_sqr

//-----seq_a-----
class seq_a extends uvm_sequence #(my_seq_item);
my_seq_item req;
`uvm_object_utils(seq_a)

function new(string name="seq_a");


super.new(name);
endfunction : new

virtual task body();


for (int unsigned i=0; i<4; i ++) begin
`uvm_do_with(req, { inst == PUSH_A; });
`uvm_info(get_full_name(), $sformatf("completed :%0d iteration", i), UVM_LOW)
end
endtask : body
endclass : seq_a

//-----seq_b-----
class seq_b extends uvm_sequence #(my_seq_item);
my_seq_item req;
`uvm_object_utils(seq_b)
function new(string name="seq_b");
super.new(name);
endfunction : new

virtual task body();


for (int unsigned i=0; i<4; i ++) begin
`uvm_do_with(req, { inst == PUSH_B; });
`uvm_info(get_full_name(), $sformatf("completed :%0d iteration", i), UVM_LOW)
end
endtask : body
endclass : seq_b

//-----seq_c-----
class seq_c extends uvm_sequence #(my_seq_item);
my_seq_item req;
`uvm_object_utils(seq_c)

function new(string name="seq_c");


super.new(name);
endfunction : new

virtual task body();


for (int unsigned i=0; i<4; i ++) begin
`uvm_do_with(req, { inst == POP_C; });
`uvm_info(get_full_name(), $sformatf("completed :%0d iteration", i), UVM_LOW)
end
endtask : body
endclass : seq_c

//-----Virtual Sequence-----
class parallel_sequence extends uvm_sequence #(my_seq_item);
seq_a s_a;
seq_b s_b;
seq_c s_c;
`uvm_object_utils(parallel_sequence)
`uvm_declare_p_sequencer(my_virtual_sqr)

function new(string name="parallel_sequence");


super.new(name);
endfunction : new

virtual task body();


grab(p_sequencer.sqr1);
fork
begin
`uvm_create_on(s_a, p_sequencer.sqr1)
`uvm_rand_send(s_a)
`uvm_info(get_name(), $sformatf("s_a completed"), UVM_LOW)
end
begin
`uvm_create_on(s_b, p_sequencer.sqr1)
`uvm_rand_send(s_b)
`uvm_info(get_name(), $sformatf("s_b completed"), UVM_LOW)
end
begin
`uvm_create_on(s_c, p_sequencer.sqr2)
`uvm_rand_send(s_c)
`uvm_info(get_name(), $sformatf("s_c completed"), UVM_LOW)
end
join
ungrab(p_sequencer.sqr1);
endtask : body
endclass : parallel_sequence

//-----Virtual Sequence-----
class parallel_sequence1 extends uvm_sequence #(my_seq_item);
seq_a s_a;
seq_b s_b;
seq_c s_c;
`uvm_object_utils(parallel_sequence1)
`uvm_declare_p_sequencer(my_virtual_sqr)

function new(string name="parallel_sequence1");


super.new(name);
endfunction : new

virtual task body();


fork
begin
`uvm_create_on(s_a, p_sequencer.sqr1)
`uvm_rand_send(s_a)
`uvm_info(get_name(), $sformatf("s_a completed"), UVM_LOW)
end
begin
`uvm_create_on(s_b, p_sequencer.sqr1)
`uvm_rand_send(s_b)
`uvm_info(get_name(), $sformatf("s_b completed"), UVM_LOW)
end
begin
`uvm_create_on(s_c, p_sequencer.sqr2)
`uvm_rand_send(s_c)
`uvm_info(get_name(), $sformatf("s_c completed"), UVM_LOW)
end
join
endtask : body
endclass : parallel_sequence1
//-----Test-----
class my_test extends uvm_test;
my_agent agent1;
my_agent agent2;
my_virtual_sqr vsqr;
`uvm_component_utils(my_test)

function new (string name = "my_test", uvm_component parent = null);


super.new(name, parent);
endfunction : new

function void build_phase (uvm_phase phase);


super.build_phase(phase);
agent1 = my_agent::type_id::create("agent1", this);
agent2 = my_agent::type_id::create("agent2", this);
vsqr = my_virtual_sqr::type_id::create("vsqr", this);
endfunction : build_phase

function void connect_phase(uvm_phase phase);


super.connect_phase(phase);
vsqr.sqr1 = agent1.sqr;
vsqr.sqr2 = agent2.sqr;
endfunction : connect_phase

task run_phase(uvm_phase phase);


parallel_sequence p_seq;
parallel_sequence1 p1_seq;
p_seq = parallel_sequence::type_id::create("p_seq");
p1_seq = parallel_sequence1::type_id::create("p1_seq");
phase.raise_objection(this);
fork
p_seq.start(vsqr);
p1_seq.start(vsqr);
join
phase.drop_objection(this);
endtask : run_phase
endclass : my_test

module top();
initial begin
run_test("my_test");
end
endmodule : top

// Output:
// UVM_INFO grab_top_4.sv(42) @ 0: uvm_test_top.agent2.drv [drv] Driving pkt inst:POP_C
// UVM_INFO grab_top_4.sv(42) @ 0: uvm_test_top.agent1.drv [drv] Driving pkt inst:PUSH_A
// UVM_INFO grab_top_4.sv(128) @ 10: uvm_test_top.agent2.sqr@@p_seq.s_c
[uvm_test_top.vsqr.p_seq.s_c] completed :0 iteration
// UVM_INFO grab_top_4.sv(94) @ 10: uvm_test_top.agent1.sqr@@p_seq.s_a
[uvm_test_top.vsqr.p_seq.s_a] completed :0 iteration
// UVM_INFO grab_top_4.sv(42) @ 10: uvm_test_top.agent1.drv [drv] Driving pkt
inst:PUSH_B
// UVM_INFO grab_top_4.sv(42) @ 10: uvm_test_top.agent2.drv [drv] Driving pkt inst:POP_C
// UVM_INFO grab_top_4.sv(111) @ 20: uvm_test_top.agent1.sqr@@p_seq.s_b
[uvm_test_top.vsqr.p_seq.s_b] completed :0 iteration
// UVM_INFO grab_top_4.sv(128) @ 20: uvm_test_top.agent2.sqr@@p1_seq.s_c
[uvm_test_top.vsqr.p1_seq.s_c] completed :0 iteration
// UVM_INFO grab_top_4.sv(42) @ 20: uvm_test_top.agent2.drv [drv] Driving pkt inst:POP_C
// UVM_INFO grab_top_4.sv(42) @ 20: uvm_test_top.agent1.drv [drv] Driving pkt
inst:PUSH_A
// UVM_INFO grab_top_4.sv(128) @ 30: uvm_test_top.agent2.sqr@@p_seq.s_c
[uvm_test_top.vsqr.p_seq.s_c] completed :1 iteration
// UVM_INFO grab_top_4.sv(94) @ 30: uvm_test_top.agent1.sqr@@p_seq.s_a
[uvm_test_top.vsqr.p_seq.s_a] completed :1 iteration
// UVM_INFO grab_top_4.sv(42) @ 30: uvm_test_top.agent1.drv [drv] Driving pkt
inst:PUSH_B
// UVM_INFO grab_top_4.sv(42) @ 30: uvm_test_top.agent2.drv [drv] Driving pkt inst:POP_C
// UVM_INFO grab_top_4.sv(111) @ 40: uvm_test_top.agent1.sqr@@p_seq.s_b
[uvm_test_top.vsqr.p_seq.s_b] completed :1 iteration
// UVM_INFO grab_top_4.sv(128) @ 40: uvm_test_top.agent2.sqr@@p1_seq.s_c
[uvm_test_top.vsqr.p1_seq.s_c] completed :1 iteration
// UVM_INFO grab_top_4.sv(42) @ 40: uvm_test_top.agent2.drv [drv] Driving pkt inst:POP_C
// UVM_INFO grab_top_4.sv(42) @ 40: uvm_test_top.agent1.drv [drv] Driving pkt
inst:PUSH_A
// UVM_INFO grab_top_4.sv(128) @ 50: uvm_test_top.agent2.sqr@@p_seq.s_c
[uvm_test_top.vsqr.p_seq.s_c] completed :2 iteration
// UVM_INFO grab_top_4.sv(94) @ 50: uvm_test_top.agent1.sqr@@p_seq.s_a
[uvm_test_top.vsqr.p_seq.s_a] completed :2 iteration
// UVM_INFO grab_top_4.sv(42) @ 50: uvm_test_top.agent1.drv [drv] Driving pkt
inst:PUSH_B
// UVM_INFO grab_top_4.sv(42) @ 50: uvm_test_top.agent2.drv [drv] Driving pkt inst:POP_C
// UVM_INFO grab_top_4.sv(111) @ 60: uvm_test_top.agent1.sqr@@p_seq.s_b
[uvm_test_top.vsqr.p_seq.s_b] completed :2 iteration
// UVM_INFO grab_top_4.sv(128) @ 60: uvm_test_top.agent2.sqr@@p1_seq.s_c
[uvm_test_top.vsqr.p1_seq.s_c] completed :2 iteration
// UVM_INFO grab_top_4.sv(42) @ 60: uvm_test_top.agent2.drv [drv] Driving pkt inst:POP_C
// UVM_INFO grab_top_4.sv(42) @ 60: uvm_test_top.agent1.drv [drv] Driving pkt
inst:PUSH_A
// UVM_INFO grab_top_4.sv(128) @ 70: uvm_test_top.agent2.sqr@@p_seq.s_c
[uvm_test_top.vsqr.p_seq.s_c] completed :3 iteration
// UVM_INFO grab_top_4.sv(94) @ 70: uvm_test_top.agent1.sqr@@p_seq.s_a
[uvm_test_top.vsqr.p_seq.s_a] completed :3 iteration
// UVM_INFO grab_top_4.sv(161) @ 70: uvm_test_top.vsqr@@p_seq [p_seq] s_c completed
// UVM_INFO grab_top_4.sv(151) @ 70: uvm_test_top.vsqr@@p_seq [p_seq] s_a completed
// UVM_INFO grab_top_4.sv(42) @ 70: uvm_test_top.agent1.drv [drv] Driving pkt
inst:PUSH_B
// UVM_INFO grab_top_4.sv(42) @ 70: uvm_test_top.agent2.drv [drv] Driving pkt inst:POP_C
// UVM_INFO grab_top_4.sv(111) @ 80: uvm_test_top.agent1.sqr@@p_seq.s_b
[uvm_test_top.vsqr.p_seq.s_b] completed :3 iteration
// UVM_INFO grab_top_4.sv(128) @ 80: uvm_test_top.agent2.sqr@@p1_seq.s_c
[uvm_test_top.vsqr.p1_seq.s_c] completed :3 iteration
// UVM_INFO grab_top_4.sv(156) @ 80: uvm_test_top.vsqr@@p_seq [p_seq] s_b completed
// UVM_INFO grab_top_4.sv(195) @ 80: uvm_test_top.vsqr@@p1_seq [p1_seq] s_c completed
// UVM_INFO grab_top_4.sv(42) @ 80: uvm_test_top.agent1.drv [drv] Driving pkt
inst:PUSH_A
// UVM_INFO grab_top_4.sv(94) @ 90: uvm_test_top.agent1.sqr@@p1_seq.s_a
[uvm_test_top.vsqr.p1_seq.s_a] completed :0 iteration
// UVM_INFO grab_top_4.sv(42) @ 90: uvm_test_top.agent1.drv [drv] Driving pkt
inst:PUSH_B
// UVM_INFO grab_top_4.sv(111) @ 100: uvm_test_top.agent1.sqr@@p1_seq.s_b
[uvm_test_top.vsqr.p1_seq.s_b] completed :0 iteration
// UVM_INFO grab_top_4.sv(42) @ 100: uvm_test_top.agent1.drv [drv] Driving pkt
inst:PUSH_A
// UVM_INFO grab_top_4.sv(94) @ 110: uvm_test_top.agent1.sqr@@p1_seq.s_a
[uvm_test_top.vsqr.p1_seq.s_a] completed :1 iteration
// UVM_INFO grab_top_4.sv(42) @ 110: uvm_test_top.agent1.drv [drv] Driving pkt
inst:PUSH_B
// UVM_INFO grab_top_4.sv(111) @ 120: uvm_test_top.agent1.sqr@@p1_seq.s_b
[uvm_test_top.vsqr.p1_seq.s_b] completed :1 iteration
// UVM_INFO grab_top_4.sv(42) @ 120: uvm_test_top.agent1.drv [drv] Driving pkt
inst:PUSH_A
// UVM_INFO grab_top_4.sv(94) @ 130: uvm_test_top.agent1.sqr@@p1_seq.s_a
[uvm_test_top.vsqr.p1_seq.s_a] completed :2 iteration
// UVM_INFO grab_top_4.sv(42) @ 130: uvm_test_top.agent1.drv [drv] Driving pkt
inst:PUSH_B
// UVM_INFO grab_top_4.sv(111) @ 140: uvm_test_top.agent1.sqr@@p1_seq.s_b
[uvm_test_top.vsqr.p1_seq.s_b] completed :2 iteration
// UVM_INFO grab_top_4.sv(42) @ 140: uvm_test_top.agent1.drv [drv] Driving pkt
inst:PUSH_A
// UVM_INFO grab_top_4.sv(94) @ 150: uvm_test_top.agent1.sqr@@p1_seq.s_a
[uvm_test_top.vsqr.p1_seq.s_a] completed :3 iteration
// UVM_INFO grab_top_4.sv(185) @ 150: uvm_test_top.vsqr@@p1_seq [p1_seq] s_a
completed
// UVM_INFO grab_top_4.sv(42) @ 150: uvm_test_top.agent1.drv [drv] Driving pkt
inst:PUSH_B
// UVM_INFO grab_top_4.sv(111) @ 160: uvm_test_top.agent1.sqr@@p1_seq.s_b
[uvm_test_top.vsqr.p1_seq.s_b] completed :3 iteration
// UVM_INFO grab_top_4.sv(190) @ 160: uvm_test_top.vsqr@@p1_seq [p1_seq] s_b
completed
view raw two_virtual_running_in_parallel.sv hosted with by GitHub
---------------------------------------------

Posted by Sagar Shah No comments:


Email ThisBlogThis!Share to TwitterShare to FacebookShare to Pinterest
Labels: ASIC, grab, lock, systemverilog, ungrab, unlock, UVM, verification

Thursday, 16 February 2017


Difference between @event and wait(event.triggered) in SystemVerilog and
usage of non-blocking event

The event data type provides a handle to a synchronization object.

There are two ways through which we can wait for particular event to be triggered.
So let's understand what is the exact difference between those 2 ways.

-----------------------------------------------
event e;
// Triggered event 'e'
->e;

// wait for event 'e' to be triggered (instantaneous)


@(e);

// wait for event 'e' to be triggered (Persistent)


wait(e.triggered);
view raw sv_event_1.sv hosted with by GitHub

-----------------------------------------------

An event trigger ->e is an instantaneous event. The event waiting process @ shall execute before
the triggering process -> executes. If the trigger executes first, then the waiting process remains
blocked.

The triggered event property evaluates to true (1'b1) if the given event has been triggered in the
current time step and false (1'b0) otherwise.
Now you no longer have to worry which came first, the triggering process > or the waiting
process @ statement. But you still have to execute the waiting process @ in the current time slot
to catch the event.
Lets see the behavior with examples,
-----------------------------------------------
class event_class;
event ev;

task trig;
->ev;
endtask : trig

task execute1;
@(ev);
$display("Testing of the event @");
endtask : execute1

// First trigger event and after that


// wait for event to be triggered in same simulation time
task ex1;
trig;
execute1;
endtask : ex1
endclass : event_class

module top();
event_class E;

initial begin
E = new();
fork
begin
E.ex1; // wait using @
end
begin
#10;
$display("Missed trigger of event");
end
join_any
disable fork;
end
endmodule : top

// Output:
// Missed trigger of event
view raw sv_event_2.sv hosted with by GitHub

-----------------------------------------------

-----------------------------------------------
class event_class;
event ev;

task trig;
->ev;
endtask : trig

task execute2;
wait(ev.triggered);
$display("Testing of the event wait(.triggered)");
endtask : execute2

// First trigger event and after that


// wait for event to be triggered in same simulation time
task ex2;
trig;
execute2;
endtask : ex2
endclass : event_class

module top();
event_class E;
initial begin
E = new();
fork
begin
E.ex2; // wait using wait(event.triggered)
end
begin
#10;
$display("Missed trigger of event");
end
join_any
disable fork;
end
endmodule : top

// Output:
// Testing of the event wait(.triggered)
view raw sv_event_3.sv hosted with by GitHub

-----------------------------------------------

The other workaround is to use nonblocking event

Non-blocking event ->>


Nonblocking events are triggered using the ->> operator.

The effect of the ->> operator is that the statement executes without blocking, and it creates a
nonblocking assign update event in the time in which the delay control expires or the event
control occurs. The effect of this update event shall be to trigger the referenced event in the
nonblocking assignment region of the simulation cycle.

-----------------------------------------------
module top();
event blocking_ev;
event non_blocking_ev;
process process_b;
process process_nb;

initial begin
fork
begin
process_b = process::self();
-> blocking_ev;
@ blocking_ev;
end
begin
process_nb = process::self();
->> non_blocking_ev;
@ non_blocking_ev;
end
join_none
#10;
$display("process_b.status:%s", process_b.status);
$display("process_nb.status:%s", process_nb.status);
end
endmodule : top

// Output:
// process_b.status:WAITING
// process_nb.status:FINISHED
view raw non_blocking_event.sv hosted with by GitHub
-----------------------------------------------

Wednesday, 23 November 2016


Kill process in SystemVerilog using "disable fork" and "disable LABEL"

Most of us, have faced these some issues at least one time in our SystemVerilog programming
while using "disable fork" and "disable LABEL".
Let's first go through below example,
------------------------------------------------------------------------------
class abc;
string name;
task multiple_process(input int unsigned delay);
fork
begin
forever begin
#20;
$display ($time, " %s, Process:1", name);
end
end
join_none

fork
begin
#delay;
$display ($time, " %s, Process:2", name);
end
begin
#10;
$display ($time, " %s, Process:3", name);
end
join_any
disable fork;
$display ($time, " %s, multiple_process completed", name);
endtask : multiple_process
endclass : abc

module top1();
abc a1, a2;
initial begin
a1 = new();
a1.name = "a1";
a2 = new();
a2.name = "a2";
fork
a1.multiple_process(5);
a2.multiple_process(7);
join
#30 $finish;
end
endmodule : top1

//Output:
// 5 a1, Process:2
// 5 a1, multiple_process completed
// 7 a2, Process:2
// 7 a2, multiple_process completed
view raw disable_process_1.sv hosted with by GitHub

------------------------------------------------------------------------------

As shown in above example, "Process:1" is running continuously. Two different processes,


"Process:2" and "Process:3" should run in parallel and any of two processes is completed, other
process shall stop its execution due to join_any statement.

While simulating above code, you may face that when the disable fork is executed, "Process:1"
also stop it's execution. So, to avoid this kind of situation, it's better to use "disable LABEL"
statement.
------------------------------------------------------------------------------
class abc;
string name;
task multiple_process(input int unsigned delay);
fork
begin
forever begin
#20;
$display ($time, " %s, Process:1", name);
end
end
join_none

fork : LABLE
begin
#delay;
$display ($time, " %s, Process:2", name);
end
begin
#10;
$display ($time, " %s, Process:3", name);
end
join_any
disable LABLE;
$display ($time, " %s, multiple_process completed", name);
endtask : multiple_process
endclass : abc

module top2();
abc a1;
initial begin
a1 = new();
a1.name = "a1";
a1.multiple_process(5);
#30 $finish;
end
endmodule : top2
//Output:
// 5 a1, Process:2
// 5 a1, multiple_process completed
// 20 a1, Process:1
view raw disable_process_2.sv hosted with by GitHub

------------------------------------------------------------------------------

Above code works fine with a single instance of that class. But when there are multiple instances
of the same class in the test-bench and all the instances are executing their threads
simultaneously then the simulation will stop after executing "disable LABEL" statement of any
instance.
------------------------------------------------------------------------------
class abc;
string name;
task multiple_process(input int unsigned delay);
fork
begin
forever begin
#20;
$display ($time, " %s, Process:1", name);
end
end
join_none

fork : LABLE
begin
#delay;
$display ($time, " %s, Process:2", name);
end
begin
#10;
$display ($time, " %s, Process:3", name);
end
join_any
disable LABLE;
$display ($time, " %s, multiple_process completed", name);
endtask : multiple_process
endclass : abc

module top2();
abc a1, a2;
initial begin
a1 = new();
a1.name = "a1";
a2 = new();
a2.name = "a2";

fork
a1.multiple_process(5);
a2.multiple_process(7);
join
#30 $finish;
end
endmodule : top2

//Output:
// 5 a1, Process:2
// 5 a1, multiple_process completed
// 5 a2, multiple_process completed
// 20 a1, Process:1
// 20 a2, Process:1
view raw disable_process_3.sv hosted with by GitHub

------------------------------------------------------------------------------

There are two ways to handle these kind of situations.


1) Limiting scope of "disable fork" by adding one extra hierarchy of fork...join.
2) Using "process" class of SystemVerilog

Let's see both ways through example,


------------------------------------------------------------------------------
class abc;
string name;
task multiple_process(input int unsigned delay);
fork
begin
forever begin
#20;
$display ($time, " %s, Process:1", name);
end
end
join_none

fork
begin
fork //extra level of hierarchy to limit scope of "disable fork"
begin
#delay;
$display ($time, " %s, Process:2", name);
end
begin
#10;
$display ($time, " %s, Process:3", name);
end
join_any
disable fork;
end
join //extra level of hierarchy to limit scope of "disable fork"
$display ($time, " %s, multiple_process completed", name);
endtask : multiple_process
endclass : abc

module top3();

abc a1, a2;

initial begin
a1 = new();
a1.name = "a1";
a2 = new();
a2.name = "a2";

fork
a1.multiple_process(5);
a2.multiple_process(7);
join
#30 $finish;
end
endmodule : top3

//Output:
// 5 a1, Process:2
// 5 a1, multiple_process completed
// 7 a2, Process:2
// 7 a2, multiple_process completed
// 20 a1, Process:1
// 20 a2, Process:1

view raw disable_process_4.sv hosted with by GitHub

------------------------------------------------------------------------------

------------------------------------------------------------------------------
class abc;
string name;
process process2;
process process3;
task multiple_process(input int unsigned delay);
fork
begin
forever begin
#20;
$display ($time, " %s, Process:1", name);
end
end
join_none

fork
begin
process2 = process::self();
#delay;
$display ($time, " %s, Process:2", name);
end
begin
process3 = process::self();
#10;
$display ($time, " %s, Process:3", name);
end
join_any
if (process2.status != process::FINISHED) begin
process2.kill();
end
if (process3.status != process::FINISHED) begin
process3.kill();
end
$display ($time, " %s, multiple_process completed", name);
endtask : multiple_process
endclass : abc

module top3();
abc a1, a2;
initial begin
a1 = new();
a1.name = "a1";
a2 = new();
a2.name = "a2";

fork
a1.multiple_process(5);
a2.multiple_process(7);
join
#30 $finish;
end
endmodule : top3

//Output:
// 5 a1, Process:2
// 5 a1, multiple_process completed
// 7 a2, Process:2
// 7 a2, multiple_process completed
// 20 a1, Process:1
// 20 a2, Process:1
view raw disable_process_5.sv hosted with by GitHub

------------------------------------------------------------------------------
Posted by Sagar Shah No comments:
Email ThisBlogThis!Share to TwitterShare to FacebookShare to Pinterest
Labels: ASIC, disable fork, disable label, process, systemverilog, verification

Wait for more than one processes of fork...join_none to complete


In our project some time we want to wait for more than one process which is invoked from
fork...join_none or join_any before proceeding further.

How to achieve this using SystemVerilog constructs, that we will understand through
an example.

Let's go through below code,


-------------------------------------------------------------------------------------
class abc;
semaphore s;
function new();
s = new(0); // Initialized with zero key
endfunction : new

task multiple_process();
fork
begin : process1
#5;
$display ($time," process1");
s.put(1);
end
begin
#10;
$display ($time," process2");
s.put(1);
end
begin
#15;
$display ($time," process3");
s.put(1);
end
begin
#12;
$display ($time," process4");
s.put(1);
end
join_none // You can use join_any also
s.get(2); // wait for any two process to be completed
disable fork; // kills remaining process
s = null; // removes semaphore (if you plan to reuse s)
$display ($time," multiple_process completed");
endtask : multiple_process
endclass : abc

module top();
abc A;
initial begin
A = new();
A.multiple_process();
end
endmodule : top

//Output:
// 5 process1
// 10 process2
// 10 multiple_process completed
view raw wait_for_more_than_1_process_using_fork_join.sv hosted with by GitHub

-------------------------------------------------------------------------------------

In above code, class abc is having one method named multiple_process().


In API, within fork...join_none 4 process are invoked in parallel.
Each process puts one key into semaphore just before it's completed (Initially semaphore doesn't
have any key).

After fork...join_none, I am waiting for semaphore to get at least two key ().

Posted by Sagar Shah No comments:


Email ThisBlogThis!Share to TwitterShare to FacebookShare to Pinterest
Labels: ASIC, fork...join_none, semaphore, systemverilog, verification

Friday, 26 August 2016


Callback vs Factory in UVM

Callbacks and factory address different areas of re-usability.

Callback: Add functionality to existing logic.

Factory: Change the existing component before build, keeps environment same.

Although the callback and factory can be interchangeably used to address the same problem.
Depending on the need and demand, a wise decision should be made while adopting either of the
techniques as they have their own merits and demerits.

Posted by Sagar Shah No comments:


Email ThisBlogThis!Share to TwitterShare to FacebookShare to Pinterest
Labels: ASIC, systemverilog, UVM

Wednesday, 22 June 2016


Strength in Verilog

Strengths can be used to resolve which value should appear on a net or gate output.
A strength specification shall have the following two components:
The strength of the 0 portion of the net value, called strength0, designated as one of the
following:
supply0 strong0 pull0 weak0 highz0
The strength of the 1 portion of the net value, called strength1, designated as one of the
following:
supply1 strong1 pull1 weak1 highz1
The combinations (highz0, highz1) and (highz1, highz0) shall be considered illegal.

There are four driving strengths: supply strong pull weak


Signals with driving strengths shall propagate from gate outputs and continuous assignment
outputs.

There are three charge storage strengths: large medium small


Signals with the charge storage strengths shall originate in the trireg net type.

It is possible to think of the strengths of signals as locations on the scale

When signals combine, their strengths and values shall determine the strength and value of the
resulting signal in accordance with the principle.

1) If two or more drivers drive a signal with different strength then it will have the value of
the strongest driver
Ex-1:
buf (strong1, weak0) g1 (y, a);
buf (pull1, supply0) g2 (y, b);
If a = 0 and b = 0 then y will be 0 with supply strength because both gates will set y to 0 and
supply (7) strength has bigger value than weak (3) strength.
If a = 0 and b = 1 then y will be 1 with pull strength because g1 will set y to 0 with weak (3)
strength and g2 will set y to 1 with pull (5) strength (pull strength is stronger than the weak
strength).
If a = 1 and b = 0 then y will be 0 with supply strength because g1 will set y to 1 with strong (6)
strength and g2 will set y to 0 with supply (7) strength (supply strength is stronger than the
strong strength).
If a = 1 and b = 1 then y will be 1 with strong strength because g1 will set y to 1 with strong (6)
strength and g2 will set y to 1 with pull (5) strength.

2) The combination of signals identical in strength and value shall result in the same signal
(If two drivers of a net have the same strength and value, then the net result will have the
same value and strength)
Ex-2:
buf (strong1, weak0) g1 (y, a);
buf (strong1, weak0) g1 (y, b);
If a = 0 and b = 0 then y will be 0 with weak strength.
If a = 1 and b = 1 then y will be 1 with strong strength.

3) If two drivers of a net have the same strength but different values then signal value will
be unknown and it will have the same strength as both drivers
Ex-3:
buf (strong1, weak0) g1 (y, a);
buf (weak1, strong0) g1 (y, b);
If a = 1 and b = 0 then y will be x with strong strength.

Important Notes:
If one of the drivers has an H or L value, then the output value will be X.

Reference:
1) http://verilog.renerta.com/source/vrg00047.htm
2) System Verilog LRM (1800-2012)
Posted by Sagar Shah No comments:
Email ThisBlogThis!Share to TwitterShare to FacebookShare to Pinterest
Labels: ASIC, strength, systemverilog, verification

Saturday, 30 April 2016


Override in UVM using factory with Example

One of the main advantage of UVM is Creating each components using factory enables them to
be overridden in different tests or environments without changing underlying code base.

uvm_factory provides four different methods to override particular instance or all instances of
particular class.
set_inst_override_by_type
set_inst_override_by_name
set_type_override_by_type
set_type_override_by_name

Let's go through example of each one of above four ways.

set_inst_override_by_type
-------------------------------------------------------
// set_inst_override_by_type
`include "uvm.svh"
import uvm_pkg::*;
//--------------------uvm_component------------------------------
class A extends uvm_agent;
`uvm_component_utils(A)

function new (string name="A", uvm_component parent);


super.new(name, parent);
`uvm_info(get_full_name, $sformatf("A new"), UVM_LOW);
endfunction : new

virtual function hello();


`uvm_info(get_full_name, $sformatf("HELLO from Original class 'A'"), UVM_LOW);
endfunction : hello
endclass : A

class A_ovr extends A;


`uvm_component_utils(A_ovr)

function new (string name="A_ovr", uvm_component parent);


super.new(name, parent);
`uvm_info(get_full_name, $sformatf("A_ovr new"), UVM_LOW);
endfunction : new

function hello();
`uvm_info(get_full_name, $sformatf("HELLO from override class 'A_ovr'"), UVM_LOW);
endfunction : hello
endclass : A_ovr

//--------------------uvm_object------------------------------
class B extends uvm_object;
`uvm_object_utils(B)

function new (string name="B");


super.new(name);
`uvm_info(get_full_name, $sformatf("B new"), UVM_LOW);
endfunction : new

virtual function hello();


`uvm_info(get_full_name, $sformatf("HELLO from Original class 'B'"), UVM_LOW);
endfunction : hello
endclass : B
class B_ovr extends B;
`uvm_object_utils(B_ovr)

function new (string name="B_ovr");


super.new(name);
`uvm_info(get_full_name, $sformatf("B_ovr new"), UVM_LOW);
endfunction : new

function hello();
`uvm_info(get_full_name, $sformatf("HELLO from override class 'B_ovr'"), UVM_LOW);
endfunction : hello
endclass : B_ovr

class B_override extends B_ovr;


`uvm_object_utils(B_override)

function new (string name="B_override");


super.new(name);
`uvm_info(get_full_name, $sformatf("B_override new"), UVM_LOW);
endfunction : new

function hello();
`uvm_info(get_full_name, $sformatf("HELLO from override class 'B_override'"), UVM_LOW);
endfunction : hello
endclass : B_override

//--------------------env class--------------------
class environment extends uvm_env;
`uvm_component_utils(environment)
A a1;
B b1, b2;

function new(string name="environment", uvm_component parent);


super.new(name, parent);
endfunction : new
function void build_phase(uvm_phase phase);
super.build_phase(phase);
// arguments of create method:
// 1. string name = ""
// 2. uvm_component parent = null
// 3. string contxt = ""
// The contxt argument, if supplied, supercedes the parent's context.
a1 = A::type_id::create("a1", this);
b1 = B::type_id::create("b1", , "path1");
b2 = B::type_id::create("b2", , "path2");

a1.hello(); // This will print from overridden class A_ovr


b1.hello(); // This will print from overridden class B_ovr
b2.hello(); // This will print from overridden class B_override
endfunction : build_phase
endclass : environment

//-------------------test class--------------------------
class test extends uvm_test;
`uvm_component_utils(test)
environment env;

function new(string name = "test", uvm_component parent = null);


super.new(name, parent);
endfunction : new

virtual function void build_phase(uvm_phase phase);


super.build_phase(phase);
env = environment::type_id::create("env", this);
`uvm_info(get_full_name, $sformatf("TEST set_inst_override_by_type"), UVM_LOW);

factory.set_inst_override_by_type(A::get_type(), A_ovr::get_type(), {get_full_name, ".",


"env.a1"}); // Working
//factory.set_inst_override_by_type(B::get_type(), B_ovr::get_type(), {get_full_name, ".",
"env.b1"}); // Not working
factory.set_inst_override_by_type(B::get_type(), B_ovr::get_type(), "path1.b1"); // Working

//factory.set_inst_override_by_type(B::get_type(), B_override::get_type(), {get_full_name, ".",


"env.b2"}); // Not working
factory.set_inst_override_by_type(B::get_type(), B_override::get_type(), "path2.b2"); //
Working

factory.print(); // This will print info about overridden classes.


endfunction : build_phase
endclass : test

module top();
initial begin
run_test("test");
end
endmodule : top
view raw set_instance_override_by_type.sv hosted with by GitHub

-------------------------------------------------------

-------------------------------------------------------
//Output:
// UVM_INFO @ 0: reporter [RNTST] Running test test...
// UVM_INFO top.sv(118) @ 0: uvm_test_top [uvm_test_top] TEST set_inst_override_by_type
//
// #### Factory Configuration (*)
// Instance Overrides:
// Requested Type Override Path Override Type
// -------------- ------------------- -------------
// A uvm_test_top.env.a1 A_ovr
// B path1.b1 B_ovr
// B path2.b2 B_override
//
// No type overrides are registered with this factory
//
// All types registered with the factory: 45 total
// (types without type names will not be printed)
// Type Name
// ---------
// A
// A_ovr
// B
// B_override
// B_ovr
// environment
// test
// (*) Types with no associated type name will be printed as <unknown>
// ####
//
// UVM_INFO top.sv(15) @ 0: uvm_test_top.env.a1 [uvm_test_top.env.a1] A new
// UVM_INFO top.sv(28) @ 0: uvm_test_top.env.a1 [uvm_test_top.env.a1] A_ovr new
// UVM_INFO top.sv(42) @ 0: reporter [B_ovr] B new
// UVM_INFO top.sv(55) @ 0: reporter [B_ovr] B_ovr new
// UVM_INFO top.sv(42) @ 0: reporter [B_override] B new
// UVM_INFO top.sv(55) @ 0: reporter [B_override] B_ovr new
// UVM_INFO top.sv(68) @ 0: reporter [B_override] B_override new
// UVM_INFO top.sv(32) @ 0: uvm_test_top.env.a1 [uvm_test_top.env.a1] HELLO from
override class 'A_ovr'
// UVM_INFO top.sv(59) @ 0: reporter [b1] HELLO from override class 'B_ovr'
// UVM_INFO top.sv(72) @ 0: reporter [b2] HELLO from override class 'B_override'
view raw set_instance_override_by_type_op.sv hosted with by GitHub

-------------------------------------------------------
set_inst_override_by_name
-------------------------------------------------------
// set_inst_override_by_name
`include "uvm.svh"
import uvm_pkg::*;
//--------------------uvm_component------------------------------
class A extends uvm_agent;
`uvm_component_utils(A)

function new (string name="A", uvm_component parent);


super.new(name, parent);
`uvm_info(get_full_name, $sformatf("A new"), UVM_LOW);
endfunction : new

virtual function hello();


`uvm_info(get_full_name, $sformatf("HELLO from Original class 'A'"), UVM_LOW);
endfunction : hello
endclass : A

class A_ovr extends A;


`uvm_component_utils(A_ovr)

function new (string name="A_ovr", uvm_component parent);


super.new(name, parent);
`uvm_info(get_full_name, $sformatf("A_ovr new"), UVM_LOW);
endfunction : new

function hello();
`uvm_info(get_full_name, $sformatf("HELLO from override class 'A_ovr'"), UVM_LOW);
endfunction : hello
endclass : A_ovr

//--------------------uvm_object------------------------------
class B extends uvm_object;
`uvm_object_utils(B)
function new (string name="B");
super.new(name);
`uvm_info(get_full_name, $sformatf("B new"), UVM_LOW);
endfunction : new

virtual function hello();


`uvm_info(get_full_name, $sformatf("HELLO from Original class 'B'"), UVM_LOW);
endfunction : hello
endclass : B

class B_ovr extends B;


`uvm_object_utils(B_ovr)

function new (string name="B_ovr");


super.new(name);
`uvm_info(get_full_name, $sformatf("B_ovr new"), UVM_LOW);
endfunction : new

function hello();
`uvm_info(get_full_name, $sformatf("HELLO from override class 'B_ovr'"), UVM_LOW);
endfunction : hello
endclass : B_ovr

class B_override extends B_ovr;


`uvm_object_utils(B_override)

function new (string name="B_override");


super.new(name);
`uvm_info(get_full_name, $sformatf("B_override new"), UVM_LOW);
endfunction : new

function hello();
`uvm_info(get_full_name, $sformatf("HELLO from override class 'B_override'"), UVM_LOW);
endfunction : hello
endclass : B_override

//--------------------env class--------------------
class environment extends uvm_env;
`uvm_component_utils(environment)
A a1;
B b1, b2;

function new(string name="environment", uvm_component parent);


super.new(name, parent);
endfunction : new

function void build_phase(uvm_phase phase);


super.build_phase(phase);
// arguments of create method:
// 1. string name = ""
// 2. uvm_component parent = null
// 3. string contxt = ""
// The contxt argument, if supplied, supercedes the parent's context.
a1 = A::type_id::create("a1", this);
b1 = B::type_id::create("b1", , "path1");
b2 = B::type_id::create("b2", , "path2");

a1.hello(); // This will print from overridden class A_ovr


b1.hello(); // This will print from overridden class B_ovr
b2.hello(); // This will print from overridden class B_override
endfunction : build_phase
endclass : environment

//-------------------test class--------------------------
class test extends uvm_test;
`uvm_component_utils(test)
environment env;
function new(string name = "test", uvm_component parent = null);
super.new(name, parent);
endfunction : new

virtual function void build_phase(uvm_phase phase);


super.build_phase(phase);
env = environment::type_id::create("env", this);
`uvm_info(get_full_name, $sformatf("TEST set_inst_override_by_name"), UVM_LOW);

factory.set_inst_override_by_name("A", "A_ovr", {get_full_name, ".", "env.a1"}); // Working

//factory.set_inst_override_by_name("B", "B_ovr", {get_full_name, ".", "env.b1"}); // Not


working
factory.set_inst_override_by_name("B", "B_ovr", "path1.b1"); // Working

//factory.set_inst_override_by_name("B", "B_override", {get_full_name, ".", "env.b2"}); // Not


working
factory.set_inst_override_by_name("B", "B_override", "path2.b2"); // Working

factory.print(); // This will print info about overridden classes.


endfunction : build_phase
endclass : test

module top();
initial begin
run_test("test");
end
endmodule : top
view raw set_instance_override_by_name.sv hosted with by GitHub

-------------------------------------------------------

-------------------------------------------------------
//Output:
// UVM_INFO @ 0: reporter [RNTST] Running test test...
// UVM_INFO top.sv(118) @ 0: uvm_test_top [uvm_test_top] TEST
set_inst_override_by_name
//
// #### Factory Configuration (*)
// Instance Overrides:
// Requested Type Override Path Override Type
// -------------- ------------------- -------------
// A uvm_test_top.env.a1 A_ovr
// B path1.b1 B_ovr
// B path2.b2 B_override
//
// No type overrides are registered with this factory
//
// All types registered with the factory: 45 total
// (types without type names will not be printed)
// Type Name
// ---------
// A
// A_ovr
// B
// B_override
// B_ovr
// environment
// test
// (*) Types with no associated type name will be printed as <unknown>
// ####
//
// UVM_INFO top.sv(15) @ 0: uvm_test_top.env.a1 [uvm_test_top.env.a1] A new
// UVM_INFO top.sv(28) @ 0: uvm_test_top.env.a1 [uvm_test_top.env.a1] A_ovr new
// UVM_INFO top.sv(42) @ 0: reporter [B_ovr] B new
// UVM_INFO top.sv(55) @ 0: reporter [B_ovr] B_ovr new
// UVM_INFO top.sv(42) @ 0: reporter [B_override] B new
// UVM_INFO top.sv(55) @ 0: reporter [B_override] B_ovr new
// UVM_INFO top.sv(68) @ 0: reporter [B_override] B_override new
// UVM_INFO top.sv(32) @ 0: uvm_test_top.env.a1 [uvm_test_top.env.a1] HELLO from
override class 'A_ovr'
// UVM_INFO top.sv(59) @ 0: reporter [b1] HELLO from override class 'B_ovr'
// UVM_INFO top.sv(72) @ 0: reporter [b2] HELLO from override class 'B_override'
view raw set_instance_override_by_name_op.sv hosted with by GitHub

-------------------------------------------------------

set_type_override_by_type
-------------------------------------------------------
// set_type_override_by_type
`include "uvm.svh"
import uvm_pkg::*;
//--------------------uvm_component------------------------------
class A extends uvm_agent;
`uvm_component_utils(A)

function new (string name="A", uvm_component parent);


super.new(name, parent);
`uvm_info(get_full_name, $sformatf("A new"), UVM_LOW);
endfunction : new

virtual function void hello();


`uvm_info(get_full_name, $sformatf("HELLO from Original class 'A'"), UVM_LOW);
endfunction : hello
endclass : A

class A_ovr extends A;


`uvm_component_utils(A_ovr)

function new (string name="A_ovr", uvm_component parent);


super.new(name, parent);
`uvm_info(get_full_name, $sformatf("A_ovr new"), UVM_LOW);
endfunction : new

function void hello();


`uvm_info(get_full_name, $sformatf("HELLO from override class 'A_ovr'"), UVM_LOW);
endfunction : hello
endclass : A_ovr

//--------------------uvm_object------------------------------
class B extends uvm_object;
`uvm_object_utils(B)

function new (string name="B");


super.new(name);
`uvm_info(get_full_name, $sformatf("B new"), UVM_LOW);
endfunction : new

virtual function void hello();


`uvm_info(get_full_name, $sformatf("HELLO from Original class 'B'"), UVM_LOW);
endfunction : hello
endclass : B

class B_ovr extends B;


`uvm_object_utils(B_ovr)

function new (string name="B_ovr");


super.new(name);
`uvm_info(get_full_name, $sformatf("B_ovr new"), UVM_LOW);
endfunction : new

function void hello();


`uvm_info(get_full_name, $sformatf("HELLO from override class 'B_ovr'"), UVM_LOW);
endfunction : hello
endclass : B_ovr
class B_override extends B_ovr;
`uvm_object_utils(B_override)

function new (string name="B_override");


super.new(name);
`uvm_info(get_full_name, $sformatf("B_override new"), UVM_LOW);
endfunction : new

function void hello();


`uvm_info(get_full_name, $sformatf("HELLO from override class 'B_override'"), UVM_LOW);
endfunction : hello
endclass : B_override

//--------------------env class--------------------
class environment extends uvm_env;
`uvm_component_utils(environment)
A a1;
B b1, b2;

function new(string name="environment", uvm_component parent);


super.new(name, parent);
endfunction : new

function void build_phase(uvm_phase phase);


super.build_phase(phase);
// arguments of create method:
// 1. string name = ""
// 2. uvm_component parent = null
// 3. string contxt = ""
// The contxt argument, if supplied, supercedes the parent's context.
a1 = A::type_id::create("a1", this);
b1 = B::type_id::create("b1", , "path1");
b2 = B::type_id::create("b2", , "path2");
void'(a1.hello()); // This will print from overridden class A_ovr
void'(b1.hello()); // This will print from overridden class B_override
void'(b2.hello()); // This will print from overridden class B_override
endfunction : build_phase
endclass : environment

//-------------------test class--------------------------
class test extends uvm_test;
`uvm_component_utils(test)
environment env;

function new(string name = "test", uvm_component parent = null);


super.new(name, parent);
endfunction : new

virtual function void build_phase(uvm_phase phase);


super.build_phase(phase);
env = environment::type_id::create("env", this);
`uvm_info(get_full_name, $sformatf("TEST set_inst_override_by_name"), UVM_LOW);

factory.set_type_override_by_type(A::get_type(), A_ovr::get_type()); // Working

factory.set_type_override_by_type(B::get_type(), B_override::get_type()); // Working

factory.print(); // This will print info about overridden classes.


endfunction : build_phase
endclass : test

module top();
initial begin
run_test("test");
end
endmodule : top
view raw set_type_override_by_type.sv hosted with by GitHub

-------------------------------------------------------
-------------------------------------------------------
//Output:
UVM_INFO @ 0: reporter [RNTST] Running test test...
UVM_INFO testbench.sv(109) @ 0: uvm_test_top [uvm_test_top] TEST
set_inst_override_by_name

#### Factory Configuration (*)

No instance overrides are registered with this factory

Type Overrides:

Requested Type Override Type


-------------- -------------
A A_ovr
B B_override

All types registered with the factory: 45 total


(types without type names will not be printed)

Type Name
---------
A
A_ovr
B
B_override
B_ovr
environment
snps_uvm_reg_bank_group
snps_uvm_reg_map
test
(*) Types with no associated type name will be printed as <unknown>

####
UVM_INFO testbench.sv(9) @ 0: uvm_test_top.env.a1 [uvm_test_top.env.a1] A new
UVM_INFO testbench.sv(22) @ 0: uvm_test_top.env.a1 [uvm_test_top.env.a1] A_ovr new
UVM_INFO testbench.sv(36) @ 0: reporter [B_override] B new
UVM_INFO testbench.sv(49) @ 0: reporter [B_override] B_ovr new
UVM_INFO testbench.sv(62) @ 0: reporter [B_override] B_override new
UVM_INFO testbench.sv(36) @ 0: reporter [B_override] B new
UVM_INFO testbench.sv(49) @ 0: reporter [B_override] B_ovr new
UVM_INFO testbench.sv(62) @ 0: reporter [B_override] B_override new
UVM_INFO testbench.sv(26) @ 0: uvm_test_top.env.a1 [uvm_test_top.env.a1] HELLO from
override class 'A_ovr'
UVM_INFO testbench.sv(66) @ 0: reporter [b1] HELLO from override class 'B_override'
UVM_INFO testbench.sv(66) @ 0: reporter [b2] HELLO from override class 'B_override'
view raw set_type_override_by_type_op.sv hosted with by GitHub

-------------------------------------------------------

set_type_override_by_name
-------------------------------------------------------
// set_type_override_by_name
`include "uvm.svh"
import uvm_pkg::*;
//--------------------uvm_component------------------------------
class A extends uvm_agent;
`uvm_component_utils(A)

function new (string name="A", uvm_component parent);


super.new(name, parent);
`uvm_info(get_full_name, $sformatf("A new"), UVM_LOW);
endfunction : new

virtual function void hello();


`uvm_info(get_full_name, $sformatf("HELLO from Original class 'A'"), UVM_LOW);
endfunction : hello
endclass : A

class A_ovr extends A;


`uvm_component_utils(A_ovr)

function new (string name="A_ovr", uvm_component parent);


super.new(name, parent);
`uvm_info(get_full_name, $sformatf("A_ovr new"), UVM_LOW);
endfunction : new

function void hello();


`uvm_info(get_full_name, $sformatf("HELLO from override class 'A_ovr'"), UVM_LOW);
endfunction : hello
endclass : A_ovr

//--------------------uvm_object------------------------------
class B extends uvm_object;
`uvm_object_utils(B)

function new (string name="B");


super.new(name);
`uvm_info(get_full_name, $sformatf("B new"), UVM_LOW);
endfunction : new

virtual function void hello();


`uvm_info(get_full_name, $sformatf("HELLO from Original class 'B'"), UVM_LOW);
endfunction : hello
endclass : B

class B_ovr extends B;


`uvm_object_utils(B_ovr)

function new (string name="B_ovr");


super.new(name);
`uvm_info(get_full_name, $sformatf("B_ovr new"), UVM_LOW);
endfunction : new

function void hello();


`uvm_info(get_full_name, $sformatf("HELLO from override class 'B_ovr'"), UVM_LOW);
endfunction : hello
endclass : B_ovr

class B_override extends B_ovr;


`uvm_object_utils(B_override)

function new (string name="B_override");


super.new(name);
`uvm_info(get_full_name, $sformatf("B_override new"), UVM_LOW);
endfunction : new

function void hello();


`uvm_info(get_full_name, $sformatf("HELLO from override class 'B_override'"), UVM_LOW);
endfunction : hello
endclass : B_override

//--------------------env class--------------------
class environment extends uvm_env;
`uvm_component_utils(environment)
A a1;
B b1, b2;
B_ovr b3;

function new(string name="environment", uvm_component parent);


super.new(name, parent);
endfunction : new

function void build_phase(uvm_phase phase);


super.build_phase(phase);
// arguments of create method:
// 1. string name = ""
// 2. uvm_component parent = null
// 3. string contxt = ""
// The contxt argument, if supplied, supercedes the parent's context.
// contxt argument is not required for set_type_override_*,
// It is only required for set_inst_override_* to locate
// instance of uvm_object which is not part of uvm hierarchy.
a1 = A::type_id::create("a1", this);
b1 = B::type_id::create("b1", , "path1");
b2 = B::type_id::create("b2");
b3 = B_ovr::type_id::create("b3");

void'(a1.hello()); // This will print from overridden class A_ovr


void'(b1.hello()); // This will print from overridden class B_override
void'(b2.hello()); // This will print from overridden class B_override
void'(b3.hello()); // This will print from overridden class B_ovr
endfunction : build_phase
endclass : environment

//-------------------test class--------------------------
class test extends uvm_test;
`uvm_component_utils(test)
environment env;

function new(string name = "test", uvm_component parent = null);


super.new(name, parent);
endfunction : new

virtual function void build_phase(uvm_phase phase);


super.build_phase(phase);
env = environment::type_id::create("env", this);
`uvm_info(get_full_name, $sformatf("TEST set_inst_override_by_name"), UVM_LOW);

factory.set_type_override_by_name("A", "A_ovr"); // Working


factory.set_type_override_by_name("B", "B_override"); // Working

factory.print(); // This will print info about overridden classes.


endfunction : build_phase
endclass : test

module top();
initial begin
run_test("test");
end
endmodule : top
view raw set_type_override_by_name.sv hosted with by GitHub

-------------------------------------------------------

-------------------------------------------------------
//Output:
UVM_INFO @ 0: reporter [RNTST] Running test test...
UVM_INFO testbench.sv(117) @ 0: uvm_test_top [uvm_test_top] TEST
set_inst_override_by_name

#### Factory Configuration (*)

No instance overrides are registered with this factory

Type Overrides:

Requested Type Override Type


-------------- -------------
A A_ovr
B B_override

All types registered with the factory: 45 total


(types without type names will not be printed)

Type Name
---------
A
A_ovr
B
B_override
B_ovr
environment
snps_uvm_reg_bank_group
snps_uvm_reg_map
test
(*) Types with no associated type name will be printed as <unknown>

####

UVM_INFO testbench.sv(11) @ 0: uvm_test_top.env.a1 [uvm_test_top.env.a1] A new


UVM_INFO testbench.sv(24) @ 0: uvm_test_top.env.a1 [uvm_test_top.env.a1] A_ovr new
UVM_INFO testbench.sv(38) @ 0: reporter [B_override] B new
UVM_INFO testbench.sv(51) @ 0: reporter [B_override] B_ovr new
UVM_INFO testbench.sv(64) @ 0: reporter [B_override] B_override new
UVM_INFO testbench.sv(38) @ 0: reporter [B_override] B new
UVM_INFO testbench.sv(51) @ 0: reporter [B_override] B_ovr new
UVM_INFO testbench.sv(64) @ 0: reporter [B_override] B_override new
UVM_INFO testbench.sv(38) @ 0: reporter [B_ovr] B new
UVM_INFO testbench.sv(51) @ 0: reporter [B_ovr] B_ovr new
UVM_INFO testbench.sv(28) @ 0: uvm_test_top.env.a1 [uvm_test_top.env.a1] HELLO from
override class 'A_ovr'
UVM_INFO testbench.sv(68) @ 0: reporter [b1] HELLO from override class 'B_override'
UVM_INFO testbench.sv(68) @ 0: reporter [b2] HELLO from override class 'B_override'
UVM_INFO testbench.sv(55) @ 0: reporter [b3] HELLO from override class 'B_ovr'
view raw set_type_override_by_name_op.sv hosted with by GitHub

-------------------------------------------------------

set_inst_override_* has high precedence than set_type_override_*.


i.e. If any particular instance of class is override by using set_inst_override_* and type of same
class is overridden by using set_type_override_* then that particular instance of class is
overridden by set_inst_override_* and rest other instances are overridden by
set_type_override_*

-------------------------------------------------------
// set_inst_override_* hase high priority than set_type_override_*
`include "uvm.svh"
import uvm_pkg::*;
//--------------------uvm_component------------------------------
class A extends uvm_agent;
`uvm_component_utils(A)

function new (string name="A", uvm_component parent);


super.new(name, parent);
`uvm_info(get_full_name, $sformatf("A new"), UVM_LOW);
endfunction : new

virtual function void hello();


`uvm_info(get_full_name, $sformatf("HELLO from Original class 'A'"), UVM_LOW);
endfunction : hello
endclass : A

class A_ovr extends A;


`uvm_component_utils(A_ovr)

function new (string name="A_ovr", uvm_component parent);


super.new(name, parent);
`uvm_info(get_full_name, $sformatf("A_ovr new"), UVM_LOW);
endfunction : new

function void hello();


`uvm_info(get_full_name, $sformatf("HELLO from override class 'A_ovr'"), UVM_LOW);
endfunction : hello
endclass : A_ovr

class A_override extends A;


`uvm_component_utils(A_override)

function new (string name="A_override", uvm_component parent);


super.new(name, parent);
`uvm_info(get_full_name, $sformatf("A_override new"), UVM_LOW);
endfunction : new

function void hello();


`uvm_info(get_full_name, $sformatf("HELLO from override class 'A_override'"), UVM_LOW);
endfunction : hello
endclass : A_override

//--------------------uvm_object------------------------------
class B extends uvm_object;
`uvm_object_utils(B)

function new (string name="B");


super.new(name);
`uvm_info(get_full_name, $sformatf("B new"), UVM_LOW);
endfunction : new

virtual function void hello();


`uvm_info(get_full_name, $sformatf("HELLO from Original class 'B'"), UVM_LOW);
endfunction : hello
endclass : B

class B_ovr extends B;


`uvm_object_utils(B_ovr)

function new (string name="B_ovr");


super.new(name);
`uvm_info(get_full_name, $sformatf("B_ovr new"), UVM_LOW);
endfunction : new

function void hello();


`uvm_info(get_full_name, $sformatf("HELLO from override class 'B_ovr'"), UVM_LOW);
endfunction : hello
endclass : B_ovr

class B_override extends B_ovr;


`uvm_object_utils(B_override)

function new (string name="B_override");


super.new(name);
`uvm_info(get_full_name, $sformatf("B_override new"), UVM_LOW);
endfunction : new

function void hello();


`uvm_info(get_full_name, $sformatf("HELLO from override class 'B_override'"), UVM_LOW);
endfunction : hello
endclass : B_override

//--------------------env class--------------------
class environment extends uvm_env;
`uvm_component_utils(environment)
A a1, a2, a3;
B b1, b2, b3;

function new(string name="environment", uvm_component parent);


super.new(name, parent);
endfunction : new

function void build_phase(uvm_phase phase);


super.build_phase(phase);

a1 = A::type_id::create("a1", this);
a2 = A::type_id::create("a2", this);
a3 = A::type_id::create("a3", this);
b1 = B::type_id::create("b1", , "path1");
b2 = B::type_id::create("b2", , "path2");
b3 = B::type_id::create("b3", , "path3");

void'(a1.hello()); // This will print from overridden class A_ovr


void'(a2.hello()); // This will print from overridden class A_ovr
void'(a3.hello()); // This will print from overridden class A_override
void'(b1.hello()); // This will print from overridden class B_ovr
void'(b2.hello()); // This will print from overridden class B_override
void'(b3.hello()); // This will print from overridden class B_override
endfunction : build_phase
endclass : environment

//-------------------test class--------------------------
class test extends uvm_test;
`uvm_component_utils(test)
environment env;

function new(string name = "test", uvm_component parent = null);


super.new(name, parent);
endfunction : new

virtual function void build_phase(uvm_phase phase);


super.build_phase(phase);
env = environment::type_id::create("env", this);
`uvm_info(get_full_name, $sformatf("TEST set_inst_override_by_name"), UVM_LOW);

factory.set_type_override_by_type(A::get_type(), A_ovr::get_type()); // Working


factory.set_type_override_by_name("B", "B_override"); // Working

factory.set_inst_override_by_type(A::get_type(), A_override::get_type(), {get_full_name, ".",


"env.a3"});
factory.set_inst_override_by_name("B", "B_ovr", "path1.b1");

factory.print(); // This will print info about overridden classes.


endfunction : build_phase
endclass : test

module top();
initial begin
run_test("test");
end
endmodule : top
view raw override_precedence.sv hosted with by GitHub

-------------------------------------------------------

-------------------------------------------------------
//Output:
UVM_INFO @ 0: reporter [RNTST] Running test test...
UVM_INFO testbench.sv(122) @ 0: uvm_test_top [uvm_test_top] TEST
set_inst_override_by_name

#### Factory Configuration (*)

Instance Overrides:

Requested Type Override Path Override Type


-------------- ------------------- -------------
A uvm_test_top.env.a3 A_override
B path1.b1 B_ovr

Type Overrides:

Requested Type Override Type


-------------- -------------------
A A_ovr
B B_override

All types registered with the factory: 46 total


(types without type names will not be printed)

Type Name
---------
A
A_override
A_ovr
B
B_override
B_ovr
environment
snps_uvm_reg_bank_group
snps_uvm_reg_map
test
(*) Types with no associated type name will be printed as <unknown>

####

UVM_INFO testbench.sv(7) @ 0: uvm_test_top.env.a1 [uvm_test_top.env.a1] A new


UVM_INFO testbench.sv(20) @ 0: uvm_test_top.env.a1 [uvm_test_top.env.a1] A_ovr new
UVM_INFO testbench.sv(7) @ 0: uvm_test_top.env.a2 [uvm_test_top.env.a2] A new
UVM_INFO testbench.sv(20) @ 0: uvm_test_top.env.a2 [uvm_test_top.env.a2] A_ovr new
UVM_INFO testbench.sv(7) @ 0: uvm_test_top.env.a3 [uvm_test_top.env.a3] A new
UVM_INFO testbench.sv(33) @ 0: uvm_test_top.env.a3 [uvm_test_top.env.a3] A_override new
UVM_INFO testbench.sv(47) @ 0: reporter [B_ovr] B new
UVM_INFO testbench.sv(60) @ 0: reporter [B_ovr] B_ovr new
UVM_INFO testbench.sv(47) @ 0: reporter [B_override] B new
UVM_INFO testbench.sv(60) @ 0: reporter [B_override] B_ovr new
UVM_INFO testbench.sv(73) @ 0: reporter [B_override] B_override new
UVM_INFO testbench.sv(47) @ 0: reporter [B_override] B new
UVM_INFO testbench.sv(60) @ 0: reporter [B_override] B_ovr new
UVM_INFO testbench.sv(73) @ 0: reporter [B_override] B_override new
UVM_INFO testbench.sv(24) @ 0: uvm_test_top.env.a1 [uvm_test_top.env.a1] HELLO from
override class 'A_ovr'
UVM_INFO testbench.sv(24) @ 0: uvm_test_top.env.a2 [uvm_test_top.env.a2] HELLO from
override class 'A_ovr'
UVM_INFO testbench.sv(37) @ 0: uvm_test_top.env.a3 [uvm_test_top.env.a3] HELLO from
override class 'A_override'
UVM_INFO testbench.sv(64) @ 0: reporter [b1] HELLO from override class 'B_ovr'
UVM_INFO testbench.sv(77) @ 0: reporter [b2] HELLO from override class 'B_override'
UVM_INFO testbench.sv(77) @ 0: reporter [b3] HELLO from override class 'B_override'
view raw override_precedence_op.sv hosted with by GitHub

-------------------------------------------------------

UVM also support override through command line,


+uvm_set_inst_override=,,
+uvm_set_type_override=,[,]
work like the name based overrides in the factory--factory.set_inst_override_by_name() and
factory.set_type_override_by_name().

Let's implement same example as above using command line arguments.


-------------------------------------------------------
//--------------------uvm_component------------------------------
class A extends uvm_agent;
`uvm_component_utils(A)

function new (string name="A", uvm_component parent);


super.new(name, parent);
`uvm_info(get_full_name, $sformatf("A new"), UVM_LOW);
endfunction : new

virtual function void hello();


`uvm_info(get_full_name, $sformatf("HELLO from Original class 'A'"), UVM_LOW);
endfunction : hello
endclass : A

class A_ovr extends A;


`uvm_component_utils(A_ovr)

function new (string name="A_ovr", uvm_component parent);


super.new(name, parent);
`uvm_info(get_full_name, $sformatf("A_ovr new"), UVM_LOW);
endfunction : new

function void hello();


`uvm_info(get_full_name, $sformatf("HELLO from override class 'A_ovr'"), UVM_LOW);
endfunction : hello
endclass : A_ovr

class A_override extends A;


`uvm_component_utils(A_override)

function new (string name="A_override", uvm_component parent);


super.new(name, parent);
`uvm_info(get_full_name, $sformatf("A_override new"), UVM_LOW);
endfunction : new

function void hello();


`uvm_info(get_full_name, $sformatf("HELLO from override class 'A_override'"), UVM_LOW);
endfunction : hello
endclass : A_override

//--------------------uvm_object------------------------------
class B extends uvm_object;
`uvm_object_utils(B)

function new (string name="B");


super.new(name);
`uvm_info(get_full_name, $sformatf("B new"), UVM_LOW);
endfunction : new

virtual function void hello();


`uvm_info(get_full_name, $sformatf("HELLO from Original class 'B'"), UVM_LOW);
endfunction : hello
endclass : B
class B_ovr extends B;
`uvm_object_utils(B_ovr)

function new (string name="B_ovr");


super.new(name);
`uvm_info(get_full_name, $sformatf("B_ovr new"), UVM_LOW);
endfunction : new

function void hello();


`uvm_info(get_full_name, $sformatf("HELLO from override class 'B_ovr'"), UVM_LOW);
endfunction : hello
endclass : B_ovr

class B_override extends B_ovr;


`uvm_object_utils(B_override)

function new (string name="B_override");


super.new(name);
`uvm_info(get_full_name, $sformatf("B_override new"), UVM_LOW);
endfunction : new

function void hello();


`uvm_info(get_full_name, $sformatf("HELLO from override class 'B_override'"), UVM_LOW);
endfunction : hello
endclass : B_override

//--------------------env class--------------------
class environment extends uvm_env;
`uvm_component_utils(environment)
A a1, a2, a3;
B b1, b2, b3;

function new(string name="environment", uvm_component parent);


super.new(name, parent);
endfunction : new

function void build_phase(uvm_phase phase);


super.build_phase(phase);

a1 = A::type_id::create("a1", this);
a2 = A::type_id::create("a2", this);
a3 = A::type_id::create("a3", this);
b1 = B::type_id::create("b1", , "path1");
b2 = B::type_id::create("b2", , "path2");
b3 = B::type_id::create("b3", , "path3");

void'(a1.hello()); // This will print from overridden class A_ovr


void'(a2.hello()); // This will print from overridden class A_ovr
void'(a3.hello()); // This will print from overridden class A_override
void'(b1.hello()); // This will print from overridden class B_ovr
void'(b2.hello()); // This will print from overridden class B_override
void'(b3.hello()); // This will print from overridden class B_override
endfunction : build_phase
endclass : environment

//-------------------test class--------------------------
class test extends uvm_test;
`uvm_component_utils(test)
environment env;

function new(string name = "test", uvm_component parent = null);


super.new(name, parent);
endfunction : new

virtual function void build_phase(uvm_phase phase);


super.build_phase(phase);
env = environment::type_id::create("env", this);
`uvm_info(get_full_name, $sformatf("TEST set_inst_override_by_name"), UVM_LOW);
//factory.set_type_override_by_type(A::get_type(), A_ovr::get_type()); // Working
//factory.set_type_override_by_name("B", "B_override"); // Working

//factory.set_inst_override_by_type(A::get_type(), A_override::get_type(), {get_full_name, ".",


"env.a3"});
//factory.set_inst_override_by_name("B", "B_ovr", "path1.b1");

factory.print(); // This will print info about overridden classes.


endfunction : build_phase
endclass : test

module top();
initial begin
run_test("test");
end
endmodule : top
view raw override_by_cmd_line.sv hosted with by GitHub

-------------------------------------------------------

Simulation time argument:


+uvm_set_inst_override=A,A_override,uvm_test_top.env.a3 \
+uvm_set_inst_override=B,B_ovr,path1.b1 \
+uvm_set_type_override=A,A_ovr \
+uvm_set_type_override=B,B_override
-------------------------------------------------------
UVM_INFO @ 0: reporter [RNTST] Running test test...
UVM_INFO @ 0: reporter [INSTOVR] Applying instance override from the command line:
+uvm_set_inst_override=A,A_override,uvm_test_top.env.a3
UVM_INFO @ 0: reporter [INSTOVR] Applying instance override from the command line:
+uvm_set_inst_override=B,B_ovr,path1.b1
UVM_INFO @ 0: reporter [UVM_CMDLINE_PROC] Applying type override from the
command line: +uvm_set_type_override=A,A_ovr
UVM_INFO @ 0: reporter [UVM_CMDLINE_PROC] Applying type override from the
command line: +uvm_set_type_override=B,B_override
UVM_INFO testbench.sv(122) @ 0: uvm_test_top [uvm_test_top] TEST
set_inst_override_by_name
#### Factory Configuration (*)

Instance Overrides:

Requested Type Override Path Override Type


-------------- ------------------- -------------
A uvm_test_top.env.a3 A_override
B path1.b1 B_ovr

Type Overrides:

Requested Type Override Type


-------------- -------------------
A A_ovr
B B_override

All types registered with the factory: 46 total


(types without type names will not be printed)

Type Name
---------
A
A_override
A_ovr
B
B_override
B_ovr
environment
snps_uvm_reg_bank_group
snps_uvm_reg_map
test
(*) Types with no associated type name will be printed as <unknown>

####
UVM_INFO testbench.sv(7) @ 0: uvm_test_top.env.a1 [uvm_test_top.env.a1] A new
UVM_INFO testbench.sv(20) @ 0: uvm_test_top.env.a1 [uvm_test_top.env.a1] A_ovr new
UVM_INFO testbench.sv(7) @ 0: uvm_test_top.env.a2 [uvm_test_top.env.a2] A new
UVM_INFO testbench.sv(20) @ 0: uvm_test_top.env.a2 [uvm_test_top.env.a2] A_ovr new
UVM_INFO testbench.sv(7) @ 0: uvm_test_top.env.a3 [uvm_test_top.env.a3] A new
UVM_INFO testbench.sv(33) @ 0: uvm_test_top.env.a3 [uvm_test_top.env.a3] A_override new
UVM_INFO testbench.sv(47) @ 0: reporter [B_ovr] B new
UVM_INFO testbench.sv(60) @ 0: reporter [B_ovr] B_ovr new
UVM_INFO testbench.sv(47) @ 0: reporter [B_override] B new
UVM_INFO testbench.sv(60) @ 0: reporter [B_override] B_ovr new
UVM_INFO testbench.sv(73) @ 0: reporter [B_override] B_override new
UVM_INFO testbench.sv(47) @ 0: reporter [B_override] B new
UVM_INFO testbench.sv(60) @ 0: reporter [B_override] B_ovr new
UVM_INFO testbench.sv(73) @ 0: reporter [B_override] B_override new
UVM_INFO testbench.sv(24) @ 0: uvm_test_top.env.a1 [uvm_test_top.env.a1] HELLO from
override class 'A_ovr'
UVM_INFO testbench.sv(24) @ 0: uvm_test_top.env.a2 [uvm_test_top.env.a2] HELLO from
override class 'A_ovr'
UVM_INFO testbench.sv(37) @ 0: uvm_test_top.env.a3 [uvm_test_top.env.a3] HELLO from
override class 'A_override'
UVM_INFO testbench.sv(64) @ 0: reporter [b1] HELLO from override class 'B_ovr'
UVM_INFO testbench.sv(77) @ 0: reporter [b2] HELLO from override class 'B_override'
UVM_INFO testbench.sv(77) @ 0: reporter [b3] HELLO from override class 'B_override'
view raw override_by_cmd_line_op.sv hosted with by GitHub

-------------------------------------------------------
Posted by Sagar Shah 4 comments:
Email ThisBlogThis!Share to TwitterShare to FacebookShare to Pinterest
Labels: ASIC, override, set_inst_override_by_name, set_inst_override_by_type,
set_type_override_by_name, set_type_override_by_type, systemverilog, UVM,
uvm_set_inst_override, uvm_set_type_override, verification

Singleton class in System Verilog

Sometimes it is required to have only one object of some classes like configuration classes. For
this purpose we create singleton classes.
Only one object is created for a singleton class and whenever we try to create a new object, same
object is returned.

System verilog does not provide construct to create a singleton class. But we can create it with
some manipulation.

---------------------------------------------------------------------
class singleton;
int unsigned var1;

// Need to declare it as static,


// as it is accessed by static method 'create'
static singleton single;

// Declared as 'protected',
// so user can't directly create instance of this class
protected function new();
endfunction : new

// Make it static,
// so user can use it before class is constructed
// To create instance of this class first time when this it is not create
static function singleton create();
if (single == null) begin
$display("Object single is null, so creating new object");
single = new();
end
return single;
endfunction : create
endclass : singleton

module top();
singleton s1, s2;

initial begin
// create is static method so we can use it directly
// using <class_name :: method_name>
s1 = singleton :: create();
$display (" 1 : s1.var1 = %0d", s1.var1);
s1.var1 = 10;
$display (" 2 : s1.var1 = %0d", s1.var1);

s2 = singleton :: create();
$display (" 3 : s2.var1 = %0d", s2.var1);

s2.var1 = 20;
$display (" 4 : s2.var1 = %0d", s2.var1);
$display (" 5 : s1.var1 = %0d", s1.var1);
end
endmodule : top

//Output:
// Object single is null, so creating new object
// 1 : s1.var1 = 0
// 2 : s1.var1 = 10
// 3 : s2.var1 = 10
// 4 : s2.var1 = 20
// 5 : s1.var1 = 20
view raw singleton.sv hosted with by GitHub

---------------------------------------------------------------------

uvm_root class defined as a singleton class in UVM source code.


---------------------------------------------------------------------
// Snippet of UVM souce code for singleton
virtual class uvm_coreservice_t;
local static `UVM_CORESERVICE_TYPE inst;
static function uvm_coreservice_t get();
if(inst==null)
inst=new;
return inst;
endfunction // get
pure virtual function uvm_root get_root();
endclass

class uvm_default_coreservice_t extends uvm_coreservice_t;


pure virtual function uvm_root get_root();
virtual function uvm_root get_root();
return uvm_root::m_uvm_get_root();
endfunction
endclass

class uvm_root extends uvm_component;


// singleton handle
static local uvm_root m_inst;

extern protected function new ();


function uvm_root::new();
super.new("__top__", null);
m_rh.set_name("reporter");
clp = uvm_cmdline_processor::get_inst();
report_header();
// This sets up the global verbosity. Other command line args may
// change individual component verbosity.
m_check_verbosity();
endfunction

// internal function not to be used


// get the initialized singleton instance of uvm_root
static function uvm_root m_uvm_get_root();
if (m_inst == null) begin
m_inst = new();
void'(uvm_domain::get_common_domain());
m_inst.m_domain = uvm_domain::get_uvm_domain();
end
return m_inst;
endfunction

uvm_coreservice_t cs;
extern static function uvm_root get();
function uvm_root uvm_root::get();
uvm_coreservice_t cs = uvm_coreservice_t::get();
return cs.get_root();
endfunction
endclass
view raw singleton_uvm.sv hosted with by GitHub

---------------------------------------------------------------------
Posted by Sagar Shah No comments:
Email ThisBlogThis!Share to TwitterShare to FacebookShare to Pinterest
Labels: ASIC, singleton, systemverilog, verification

Monday, 25 April 2016


UVM FAQ2

Why phasing is used? What are the different phases in uvm?


UVM Phases is used to control the behavior of simulation in a systematic way & execute in a
sequential ordered to avoid race condition. This could also be done in system verilog but
manually.
Which phases of UVM are Top-Down?
build_phase() & final_phase() are Top-Down, rest all phases are Bottom-Up.

Which phases of UVM are task?


run_phase(),
pre_reset_phase(), reset_phase(), post_reset_phase(),
pre_configure_phase(), configure_phase(), post_configure_phase(),
pre_main_phase(), main_phase(), post_main_phase(),
pre_shutdown_phase(), shutdown_phase(), post_shutdown_phase()
How do uvm phases initiate?
Calling run_test() constructs the UVM environment root component and then initiates
the UVM phasing.

Why is the build_phase() in UVM executed in a Top - Down fashion and the other phases in
Bottom - Up fashion?
The build phase has to be that way because the parent component's build_phase constructs the
child components. You couldn't call the child's build_phase before the parent's build_phase
because they the child objects haven't been constructed yet. You need a constructed object to call
its method.
The build_phase() is also executed top-down so that the parent can provide override setting that
the children will use when they execute their build_phase()
The ordering within the other phases should not matter, except you might want know that the top
level's report_phase comes last.

What is the order of execution of run_phase() ?


The run_phase() of each component is executed concurrently with no defined order you can
depend on.

During the run_phase() is there something like super.run_phase(phase) called?


You only need to call super.method() if you are extending a class an need the functionality of the
base method. There is nothing inside the run_phase() of a uvm_component, so there is no need to
call super.run_phase() when extending from it.
You may want to call it when extending your classes from your base classes.

What is the difference between run_phase and main_phase in uvm_component?


Actually, you can start a sequence in any phase. It is more important to understand the
domain/scheduling relationships between the task based (i.e. runtime) phases.
UVM undergoes a number of pre-simulation phases (build, connect, end_of_elaboration,
start_of_simulation) that are all implemented with functions. Once those are completed, the task
based phases begin.
The standard includes two schedules.

One is simply the run_phase, which starts executing at time zero and continues until all
components have dropped their objections within the run_phase.
The other schedule contains twelve phases that execute parallel to the run phase. They
are: pre_reset, reset, post_reset, pre_config, config, post_config, pre_main, main,
post_main, pre_shutdown, shutdown, and post_shutdown. They execute in sequence.

Every component has the opportunity to define or not define tasks to execute these phases. A
phase starts only when all components in the previous phase have dropped their objections. A
phase continues to execute until all components have dropped their objections in the current
phase.

Why connect_phase() is bottom-up?

Posted by Sagar Shah No comments:


Email ThisBlogThis!Share to TwitterShare to FacebookShare to Pinterest
Labels: ASIC, interview_question, phase, systemverilog, UVM, uvm_phase, verification

Sunday, 24 April 2016


Difference between m_sequencer and p_sequencer in UVM

To understand difference between m_sequencer and p_sequencer, let's first go through couple
of classes from UVM library.
-------------------------------------------------------------------------------------
// Snippet of uvm_sequence_item class
class uvm_sequence_item extends uvm_transaction;
protected uvm_sequencer_base m_sequencer;
protected uvm_sequence_base m_parent_sequence;

// Set the sequence and sequencer execution context for a sequence item
function void set_item_context(uvm_sequence_base parent_seq,
uvm_sequencer_base sequencer = null);
set_use_sequence_info(1);
if (parent_seq != null) set_parent_sequence(parent_seq);
if (sequencer == null && m_parent_sequence != null) sequencer =
m_parent_sequence.get_sequencer();
set_sequencer(sequencer);
if (m_parent_sequence != null) set_depth(m_parent_sequence.get_depth() + 1);
reseed();
endfunction

// Sets the default sequencer for the sequence to sequencer. It will take
// effect immediately, so it should not be called while the sequence is
// actively communicating with the sequencer.
virtual function void set_sequencer(uvm_sequencer_base sequencer);
m_sequencer = sequencer;
m_set_p_sequencer();
endfunction
endclass
view raw m_sequencer_vs_p_sequencer_1.sv hosted with by GitHub

-------------------------------------------------------------------------------------

-------------------------------------------------------------------------------------
// Snippet of uvm_sequence_base class
class uvm_sequence_base extends uvm_sequence_item;
// Executes this sequence, returning when the sequence has completed.
//
// The ~sequencer~ argument specifies the sequencer on which to run this
// sequence. The sequencer must be compatible with the sequence.
virtual task start (uvm_sequencer_base sequencer,
uvm_sequence_base parent_sequence = null,
int this_priority = -1,
bit call_pre_post = 1);

set_item_context(parent_sequence, sequencer);
...
endtask
endclass

// `uvm_declare_p_sequencer macro definition


//
// This macro is used to declare a variable ~p_sequencer~ whose type is
// specified by ~SEQUENCER~.
`define uvm_declare_p_sequencer(SEQUENCER) \
SEQUENCER p_sequencer;\
virtual function void m_set_p_sequencer();\
super.m_set_p_sequencer(); \
if( !$cast(p_sequencer, m_sequencer)) \
`uvm_fatal("DCLPSQ", \
$sformatf("%m %s Error casting p_sequencer, please verify that this sequence/sequence item is
intended to execute on this type of sequencer", get_full_name())) \
endfunction
view raw m_sequencer_vs_p_sequencer_2.sv hosted with by GitHub

-------------------------------------------------------------------------------------

When you call `uvm_declare_p_sequencer from sequence, it overrides m_set_p_sequencer


function.
When you call start method of sequence, it calls set_item_context method,
Then set_item_context method calls set_sequencer method,
Then set_sequencer method assign handle of sequencer (which you pass in start method of
sequence) to m_sequencer,
set_sequencer also calls m_set_p_sequencer method, but you have override the
m_set_p_sequencer method by declaring `uvm_declare_p_sequencer macro.
So m_set_p_sequencer defined in macro will be executed, and it casts m_sequencer into
p_sequencer,
where p_sequencer's type is specified by the argument of `uvm_declare_p_sequencer macro.

Conclusion:
m_sequencer and p_sequencer both point to the same thing (the sequencer on which the
sequence is running). However, there are some important differences:
m_sequencer is a generic uvm sequencer pointer of type uvm_sequencer_base. It will always
exist for an uvm_sequence and is initialized when the sequence is started.

p_sequencer is a reference to uvm_sequencer#(REQ,RSP), the user derived parameterized


sequencer class.
Other way you can say that p_sequencer is a type specific sequencer pointer.
p_sequencer will not exist if the `uvm_declare_p_sequencer macros aren't used.
Advantage of p_sequencer over m_sequencer:
Being type specific, you will be able to access anything added to the sequencer (i.e. pointers to
other sequencers, handle of environment class (which is defined in user derived virtual
sequencer class) etc.).

Drawback of p_sequencer over m_sequencer:


p_sequencer creates an additional dependency, means sequence which use p_sequencer may not
be executed on all the sequencers. Sequence requires resource in sequencer class which is
declared as p_sequencer (i.e. pointers to other sequencers, handle of environment class, etc.)
Posted by Sagar Shah 5 comments:
Email ThisBlogThis!Share to TwitterShare to FacebookShare to Pinterest
Labels: ASIC, m_sequencer, p_sequencer, UVM, verification

Saturday, 23 April 2016


Randomize Non-random (State) variable using randomize() method of Class

The randomize() method can be used to temporarily control the set of random and state variables
within a class instance or object.
When randomize is called with arguments, those arguments designate the complete set of
random variables within that object; all other variables in the object are considered state
variables.
The randomize method accepts the special argument null to indicate no random variables for the
duration of the call. In other words, all class members behave as state variables.
Consider following Example:
----------------------------------------------------
class rand_mo;
rand integer Var1;
integer Var2;
endclass

program rand_mo_p_38;
rand_mo obj = new();
initial begin
// Random variable: Var1, State Variable: Var2
void'(obj.randomize());
$display(" 1 : Var1 : %0d, Var2 : %0d",obj.Var1, obj.Var2);
// Random variable: Var2, State Variable: Var1
void'(obj.randomize(Var2));
$display(" 2 : Var1 : %0d, Var2 : %0d",obj.Var1, obj.Var2);

// Random variable: Var1, Var2


void'(obj.randomize(Var1, Var2));
$display(" 3 : Var1 : %0d, Var2 : %0d",obj.Var1, obj.Var2);

// State variable: Var1, Var2


void'(obj.randomize(null));
$display(" 4 : Var1 : %0d, Var2 : %0d",obj.Var1, obj.Var2);
end
endprogram

// Output:
// 1 : Var1 : -902462825, Var2 : x
// 2 : Var1 : -902462825, Var2 : -1241023056
// 3 : Var1 : 69704603, Var2 : -1877783293
// 4 : Var1 : 69704603, Var2 : -1877783293
view raw randomize_with_arguments.sv hosted with by GitHub
----------------------------------------------------
Posted by Sagar Shah No comments:
Email ThisBlogThis!Share to TwitterShare to FacebookShare to Pinterest
Labels: ASIC, randomization, randomize, systemverilog, verification

rand_mode and constraint_mode in System Verilog

rand_mode:
The random nature of variables declared as rand or randc can be turned on or off dynamically
by using in-built method called rand_mode(). rand_mode() can be called as function or task.

In below example, rand_mode of all variable of class is disabled and enabled.


---------------------------------------------------------------------
class rand_mo;
rand integer Var1;
randc integer Var2;
endclass

program rand_mo_p_23;
rand_mo obj = new();
initial begin
void'(obj.randomize());
$display(" 1 : Var1 : %d, Var2 : %d ",obj.Var1, obj.Var2);

// Var1 and Var2 will be treated as State variables.


obj.rand_mode(0);
void'(obj.randomize());
$display(" 2 : Var1 : %d, Var2 : %d ",obj.Var1, obj.Var2);

// Var1 and Var2 will be treated as random variables.


obj.rand_mode(1);
void'(obj.randomize());
$display(" 3 : Var1 : %d, Var2 : %d ",obj.Var1, obj.Var2);
end
endprogram

//Output:
// 1 : Var1 : -902462825, Var2 : 906460592
// 2 : Var1 : -902462825, Var2 : 906460592 //Remain same (not randomized)
// 3 : Var1 : 69704603, Var2 : 1917593266
view raw rand_mode_1.sv hosted with by GitHub
---------------------------------------------------------------------

We can also change rand_mode of specific variable. Consider below example,


---------------------------------------------------------------------
class rand_mo;
rand integer Var1;
rand integer Var2;
endclass

program rand_mo_p_24;
rand_mo obj = new();
initial begin
void'(obj.randomize());
$display(" 1 : Var1 : %d Var2 : %d ",obj.Var1,obj.Var2);

// Var1 will become State variable


obj.Var1.rand_mode(0);
void'(obj.randomize());
$display(" 2 : Var1 : %d Var2 : %d ",obj.Var1,obj.Var2);

// Var2 will also become State variable


obj.Var2.rand_mode(0);
$display(" 3 : Var1 : %d Var2 : %d ",obj.Var1,obj.Var2);

// Var1 will become random variable


obj.Var1.rand_mode(1);
void'(obj.randomize());
$display(" 4 : Var1 : %d Var2 : %d ",obj.Var1,obj.Var2);
end
endprogram

//Output:
// 1 : Var1 : -902462825 Var2 : -1241023056 // Botn Var1 and Var2 are randomized
// 2 : Var1 : -902462825 Var2 : 69704603 // Var1 remain unchanged (Not randomized)
// 3 : Var1 : -902462825 Var2 : 69704603 // Var1 and Var2 both remain unchanged (Not
randomized)
// 4 : Var1 : -1877783293 Var2 : 69704603 // Var1 changed (randomized), Var2 reamin
unchanged (Not randomized)
view raw rand_mode_2.sv hosted with by GitHub
---------------------------------------------------------------------

When rand_mode method is called as function, it returns the active status of the specified
random variable.
When called as a function, rand_mode() returns the current active state of the specified random
variable. It returns 1 if the variable is active (ON) and 0 if the variable is inactive (OFF).
---------------------------------------------------------------------
class rand_mo;
rand integer Var1;
rand integer Var2;
endclass

program rand_mo_p_24;
rand_mo obj = new();
initial begin
void'(obj.randomize());
$display(" 1 : Var1 : %d Var2 : %d ",obj.Var1,obj.Var2);

obj.Var1.rand_mode(0);
void'(obj.randomize());
$display(" 2 : Var1 : %d Var2 : %d ",obj.Var1,obj.Var2);

if(obj.Var1.rand_mode()) begin
$display(" 3a : Var1 is random");
end
else begin
$display(" 3b : Var1 is nonrandom");
end

void'(obj.randomize());
$display(" 4 : Var1 : %d Var2 : %d ",obj.Var1,obj.Var2);
end
endprogram

//Output:
// 1 : Var1 : -902462825 Var2 : -1241023056
// 2 : Var1 : -902462825 Var2 : 69704603
// 3b : Var1 is nonrandom
// 4 : Var1 : -902462825 Var2 : -1877783293
view raw rand_mode_3.sv hosted with by GitHub
---------------------------------------------------------------------

A compiler error shall be issued if the specified variable does not exist within the class hierarchy
or even though it exists but not declared as rand or randc. The following example illustrates the
second case.

rand_mode of rand static variable,


---------------------------------------------------------------------
class A;
rand static integer Var1;
rand integer Var2;
endclass

program A_p_27;
A obj_1 = new;
A obj_2 = new;

initial begin
obj_2.Var1.rand_mode(0);
obj_2.Var2.rand_mode(0);
repeat(2) begin
void'(obj_1.randomize());
$display(" 1 : obj_1.Var1 : %0d, obj_1.Var2 : %0d, obj_2.Var1 : %0d, obj_2.Var2 :
%0d",obj_1.Var1,obj_1.Var2,obj_2.Var1,obj_2.Var2);
void'(obj_2.randomize());
$display(" 2 : obj_1.Var1 : %0d, obj_1.Var2 : %0d, obj_2.Var1 : %0d, obj_2.Var2 :
%0d",obj_1.Var1,obj_1.Var2,obj_2.Var1,obj_2.Var2);
end
end
endprogram

//Output:
// 1 : obj_1.Var1 : x, obj_1.Var2 : -902462825, obj_2.Var1 : x, obj_2.Var2 : x
// 2 : obj_1.Var1 : x, obj_1.Var2 : -902462825, obj_2.Var1 : x, obj_2.Var2 : x
// 1 : obj_1.Var1 : x, obj_1.Var2 : -1241023056, obj_2.Var1 : x, obj_2.Var2 : x
// 2 : obj_1.Var1 : x, obj_1.Var2 : -1241023056, obj_2.Var1 : x, obj_2.Var2 : x
view raw rand_mode_4.sv hosted with by GitHub
---------------------------------------------------------------------

constraint_mode

SystemVerilog supports to change the status of constraint block dynamically.


The constraint_mode() method can be used to active/inactive constraint. By default all the
constraint blocks are active. When a constraint is inactive, it is not considered by the randomize()
method.

It can be used as task or function.


When called as a task, the argument to the constraint_mode task method determines the
operation to be performed.
When called as a function, constraint_mode() returns the current active state of the specified
constraint block. It returns 1 if the constraint is active (ON) and 0 if the constraint is inactive
(OFF).

---------------------------------------------------------------------
// object_name.constraint_mode
class rand_mo;
rand integer Var1;
rand integer Var2;
constraint Var_1 { Var1 == 20;}
constraint Var_2 { Var2 == 10;}
endclass

program rand_mo_p_38;
rand_mo obj = new();
initial begin
//By default all constraints are active.
void'(obj.randomize());
$display(" 1 : Var1 : %0d, Var2 : %0d ",obj.Var1, obj.Var2);

//Both constraints Var_1 and Var_2 are turned off.


obj.constraint_mode(0);
void'(obj.randomize());
$display(" 2 : Var1 : %0d, Var2 : %0d ",obj.Var1, obj.Var2);

//Both constraints Var_1 and Var_2 are turned on.


obj.constraint_mode(1);
void'(obj.randomize());
$display(" 3 : Var1 : %0d, Var2 : %0d ",obj.Var1, obj.Var2);
end
endprogram

//Output:
// 1 : Var1 : 20, Var2 : 10
// 2 : Var1 : -755415376, Var2 : -334455186
// 3 : Var1 : 20, Var2 : 10
view raw constraint_mode_1.sv hosted with by GitHub
---------------------------------------------------------------------
---------------------------------------------------------------------
// object_name.constraint_name.constraint_mode
class rand_mo;
rand integer Var1;
rand integer Var2;
constraint Var_1 { Var1 == 20;}
constraint Var_2 { Var2 == 10;}
endclass

program rand_mo_p_38;
rand_mo obj = new();
initial begin
void'(obj.randomize());
$display(" Var1 : %0d, Var2 : %0d ",obj.Var1, obj.Var2);

obj.Var_1.constraint_mode(0);
void'(obj.randomize());
$display(" Var1 : %0d, Var2 : %0d ",obj.Var1, obj.Var2);

obj.Var_1.constraint_mode(1);
void'(obj.randomize());
$display(" Var1 : %0d, Var2 : %0d ",obj.Var1, obj.Var2);
end
endprogram

//Output:
// Var1 : 20, Var2 : 10
// Var1 : -755415376, Var2 : 10
// Var1 : 20, Var2 : 10
view raw constraint_mode_2.sv hosted with by GitHub
---------------------------------------------------------------------
---------------------------------------------------------------------
// Used as Function
class rand_mo;
rand integer Var1;
rand integer Var2;
constraint Var_1 { Var1 == 20;}
constraint Var_2 { Var2 == 10;}
endclass

program rand_mo_p_38;
rand_mo obj = new();
initial begin
//By default all constraints are active.
void'(obj.randomize());
$display(" 1 : Var1 : %0d, Var2 : %0d",obj.Var1, obj.Var2);

//Both constraint Var_1 is are turned off.


obj.Var_1.constraint_mode(0);
void'(obj.randomize());
$display(" 2 : Var1 : %0d, Var2 : %0d",obj.Var1, obj.Var2);

if (obj.Var_1.constraint_mode())
$display(" 3a : Var_1 constraint si active");
else
$display(" 3b : Var_1 constraint si inactive");

if (obj.Var_2.constraint_mode())
$display(" 4a : Var_2 constraint si active");
else
$display(" 4b : Var_2 constraint si inactive");

void'(obj.randomize());
$display(" 5 : Var1 : %0d, Var2 : %0d ",obj.Var1, obj.Var2);
end
endprogram

//Output:
// 1 : Var1 : 20, Var2 : 10
// 2 : Var1 : -755415376, Var2 : 10
// 3b : Var_1 constraint si inactive
// 4a : Var_2 constraint si active
// 5 : Var1 : -334455186, Var2 : 10
view raw constraint_mode_3.sv hosted with by GitHub
---------------------------------------------------------------------

Tuesday, 29 December 2015


Callback in SystemVerilog

One of the main guidelines of this book is to create a single verifi cation environment
that you can use for all tests with no changes. The key requirement is that this
testbench must provide a hook where the test program can inject new code without
modifying the original classes.

Your driver may want to do the following:


Inject errors
Drop the transaction
Delay the transaction
Put the transaction in the scoreboard
Gather functional coverage data

Rather than try to anticipate every possible error, delay, or disturbance in the flow of
transactions, the driver just needs to call back a method that is defined in the top-level
test.
The beauty of this technique is that the callback method can be defined differently in
every test. As a result, the test can add new functionality to the driver using callbacks,
without editing the Driver class.
For some drastic behaviors such as dropping a transaction, you need to code this in the
class ahead of time, but this is a known pattern. The reason why the transaction is
dropped is left to the callback.

As shown in "Developer code" the Driver::run task loops forever with a call to a transmit
task. Before sending the transaction, run calls the pre-transmit callback, if any. After
sending the transaction, it calls the post-callback task, if any. By default, there are no
callbacks, so run just calls transmit.

//-------------------------------------------------------------------
// Developer Code
//-------------------------------------------------------------------
// Transaction class
class Transaction;
rand bit [7:0] addr;
rand logic [7:0] data;

constraint addr_range_cn {
addr inside {[10:20]};
}
constraint data_range_cn {
data inside {[100:200]};
}
function string sprint();
sprint = $sformatf("addr = %0d, data = %0d", addr, data);
endfunction : sprint
endclass : Transaction

// Generator class
class Generator;
mailbox gen_drv;

function new(input mailbox gen_drv);


this.gen_drv = gen_drv;
endfunction : new

task run();
Transaction tr;
forever begin
tr = new();
if (!tr.randomize()) begin
$fatal("time=%0t,Randomization Failed in Generator", $time);
end
else begin
gen_drv.put(tr);
$display("time=%0t, Generator : after randomization tr put in maibox = %s", $time, tr.sprint());
end
end
endtask : run
endclass : Generator

// Driver_cbs class
virtual class Driver_cbs; // Driver callbacks
virtual task pre_tx(ref Transaction tr, ref bit drop);
// By default, callback does nothing
endtask : pre_tx
virtual task post_tx(ref Transaction tr);
// By default, callback does nothing
endtask : post_tx
endclass : Driver_cbs

// Driver class
class Driver;
mailbox gen_drv;
Driver_cbs cbs;

function new(input mailbox gen_drv);


this.gen_drv = gen_drv;
endfunction : new

task run();
bit drop;
Transaction tr;
forever begin
#1;
drop = 0;
// Get Transaction from Generator
gen_drv.peek(tr);
// pre_tx hook of callback
cbs.pre_tx(tr, drop);
if (drop == 1) begin
gen_drv.get(tr); // Remove tr from mailbox
$display("time=%0t, Driver : run : tr dropped, dropped tr = %s", $time, tr.sprint());
continue;
end
// Actual transmit logic
transmit(tr);
// post_tx hook of callback
cbs.post_tx(tr);
end
endtask : run
task transmit(ref Transaction tr);
$display("time=%0t, Driver : transmit : get tr from Generator = %s", $time, tr.sprint());
#5; // Actual logic to drive value on interface
gen_drv.get(tr);
//$display("time=%0t, Driver : transmit : Value driven in interface", $time);
endtask : transmit
endclass : Driver

//Agent class
class Agent;
mailbox gen_drv; //generator to driver mailbox
Generator Gen;
Driver Drv;

function void build();


gen_drv = new(1);
Gen = new(gen_drv);
Drv = new(gen_drv);
endfunction : build

task run();
fork
begin
Gen.run();
end
begin
Drv.run();
end
join_none
endtask : run
endclass : Agent
view raw sv_callback1.sv hosted with by GitHub
You could make Driver::run a virtual method and then override its behavior in an
extended class, perhaps MyDriver::run. The drawback to this is that you might have to
duplicate all the original methods code in the new method if you are injecting new
behavior. Now if you made a change in the base class, you would have to remember to
propagate it to all the extended classes. Additionally, you can inject a callback without
modifying the code that constructed the original object.

A callback task is created in the top-level test and called from the driver, the lowest level
of the environment. However, the driver does not have to have any knowledge of the
test it just has to use a generic class that the test can extend.

//------------------------------------------------------------------
// End User Code 1
//------------------------------------------------------------------
// User defined extended callback class
class Driver_cbs_drop extends Driver_cbs;
virtual task pre_tx(ref Transaction tr, ref bit drop);
bit _drop;
// Randomly drop 1 out of every 5 transactions
void'(std :: randomize(_drop) with {_drop inside {[0:4]};});
drop = (_drop == 0);
endtask : pre_tx
endclass : Driver_cbs_drop

// Test class
class Test1;
Agent Agt;
Driver_cbs_drop cb;

function void build();


Agt = new();
Agt.build();
cb = new();
Agt.Drv.cbs = this.cb;
endfunction : build

task run();
fork
Agt.run();
join_none
endtask:run
endclass : Test1

//Top module
module top1();
Test1 test;

initial begin
test = new();
test.build();
test.run();

#40 $finish;
end
endmodule : top1

//Output:
// time=0, Generator : after randomization tr put in maibox = addr = 19, data = 189
// time=1, Driver : run : tr dropped, dropped tr = addr = 19, data = 189
// time=1, Generator : after randomization tr put in maibox = addr = 14, data = 112
// time=2, Driver : transmit : get tr from Generator = addr = 14, data = 112
// time=7, Generator : after randomization tr put in maibox = addr = 13, data = 115
// time=8, Driver : transmit : get tr from Generator = addr = 13, data = 115
// time=13, Generator : after randomization tr put in maibox = addr = 19, data = 135
// time=14, Driver : transmit : get tr from Generator = addr = 19, data = 135
// time=19, Generator : after randomization tr put in maibox = addr = 19, data = 138
// time=20, Driver : run : tr dropped, dropped tr = addr = 19, data = 138
// time=20, Generator : after randomization tr put in maibox = addr = 13, data = 133
// time=21, Driver : run : tr dropped, dropped tr = addr = 13, data = 133
// time=21, Generator : after randomization tr put in maibox = addr = 15, data = 136
// time=22, Driver : run : tr dropped, dropped tr = addr = 15, data = 136
// time=22, Generator : after randomization tr put in maibox = addr = 13, data = 127
// time=23, Driver : run : tr dropped, dropped tr = addr = 13, data = 127
// time=23, Generator : after randomization tr put in maibox = addr = 12, data = 200
// time=24, Driver : transmit : get tr from Generator = addr = 12, data = 200
// time=29, Generator : after randomization tr put in maibox = addr = 15, data = 104
// time=30, Driver : transmit : get tr from Generator = addr = 15, data = 104
// time=35, Generator : after randomization tr put in maibox = addr = 12, data = 176
// time=36, Driver : transmit : get tr from Generator = addr = 12, data = 176
view raw sv_callback2.sv hosted with by GitHub

//------------------------------------------------------------------
// End User Code 2
//------------------------------------------------------------------
// User defined extended callback class
class Driver_cbs_modify extends Driver_cbs;
virtual task pre_tx(ref Transaction tr, ref bit drop);
bit _modify;
// Randomly drop 1 out of every 5 transactions
void'(std :: randomize(_modify) with {_modify inside {[0:4]};});
if (_modify == 0) begin
tr.addr = tr.addr + 10;
tr.data = tr.data + 10;
$display("time=%0t, Driver_cbs_modify : modified tr = %s", $time, tr.sprint());
end
endtask : pre_tx
endclass : Driver_cbs_modify
// Test class
class Test2;
Agent Agt;
Driver_cbs_modify cb;

function void build();


Agt = new();
Agt.build();
cb = new();
Agt.Drv.cbs = this.cb;
endfunction : build

task run();
fork
Agt.run();
join_none
endtask:run
endclass : Test2

// Top module
module top2();
Test2 test;

initial begin
test = new();
test.build();
test.run();

#40 $finish;
end
endmodule : top2

//Output:
// time=0, Generator : after randomization tr put in maibox = addr = 19, data = 189
// time=1, Driver_cbs_modify : modified tr = addr = 29, data = 199
// time=1, Driver : transmit : get tr from Generator = addr = 29, data = 199
// time=6, Generator : after randomization tr put in maibox = addr = 14, data = 112
// time=7, Driver : transmit : get tr from Generator = addr = 14, data = 112
// time=12, Generator : after randomization tr put in maibox = addr = 13, data = 115
// time=13, Driver : transmit : get tr from Generator = addr = 13, data = 115
// time=18, Generator : after randomization tr put in maibox = addr = 19, data = 135
// time=19, Driver : transmit : get tr from Generator = addr = 19, data = 135
// time=24, Generator : after randomization tr put in maibox = addr = 19, data = 138
// time=25, Driver_cbs_modify : modified tr = addr = 29, data = 148
// time=25, Driver : transmit : get tr from Generator = addr = 29, data = 148
// time=30, Generator : after randomization tr put in maibox = addr = 13, data = 133
// time=31, Driver_cbs_modify : modified tr = addr = 23, data = 143
// time=31, Driver : transmit : get tr from Generator = addr = 23, data = 143
// time=36, Generator : after randomization tr put in maibox = addr = 15, data = 136
// time=37, Driver_cbs_modify : modified tr = addr = 25, data = 146
// time=37, Driver : transmit : get tr from Generator = addr = 25, data = 146
view raw sv_callback3.sv hosted with by GitHub

Limitations of SystemVerilog callback (w.r.t. uvm_callback).

You cannot control particular nth number of transaction. Callback affects all the
transaction or in random manner if you use randomization in extended callback
as I had used in above both examples. For example you want initial some (n)
transcation to drive without any modification, then for particular (n+1) transaction
you want to modified its content. Then again for rest of all transaction you don't
want any modification. This is not possible with SystemVerilog callback.
You cannot Add or Delete callback runtime.

Posted by Sagar Shah No comments:


Email ThisBlogThis!Share to TwitterShare to FacebookShare to Pinterest
Labels: ASIC, callback, systemverilog, verification

Monday, 28 December 2015


Difference between Variable and Signal in VHDL
Scope wise:
SIGNAL has scope to whole architecture. It can be access from any place in
architecture of enitity.
VARIABLE is local t procedure defined in the architecture.

Behavior wise:
Variable assignment is evaluated and assigned in a single step:
1) Execution flow within the procedure is blocked until the Execution flow within the
procedure is blocked until the
assignment is completed.
Variable assignment is same as Blocking assignment in Verilog.

Signal assignment is Evaluated and assigned in two steps:


1) The right The right-hand side is evaluated immediately.
2) The assignment to the left-hand side is postponed until other evaluations in the
current time step are completed other evaluations in the current time step are
completed.
Execution flow within the procedure continues until a timing control is encountered (flow
is not blocked)
Signal assignment is same as Non-Blocking assignment in Verilog.
If several values are assigned to a given signal in one process, only the last assignment
is effective.

Synthesis wise:
SIGNAL inter a FLOP during synthesis.
VARIABLE infer just a WIRE during synthesis.

Example:

Signal assignment:
library IEEE;
use IEEE.std_logic_1164.all;

entity xor_sig is
port (
A, B, C: in STD_LOGIC;
X, Y: out STD_LOGIC
);
end xor_sig;

architecture SIG_ARCH of xor_sig is


signal D: STD_LOGIC;
signal E: STD_LOGIC;
signal F: STD_LOGIC;
begin
SIG:process (A,B,C)
begin
D <= A; -- ignored !!
E <= D xor F; -- OLD value of D is taken for right-hand side evaluation.
F <= B xor D; -- OLD value of D is taken for right-hand side evaluation.
X <= C xor E; -- OLD value of E is taken for right-hand side evaluation.
D <= B; -- overrides !! After this timestamp value of D is equal to B.
Y <= D xor F; -- OLD value of both D and F is taken for right-hand side evaluation.
-- (During this assignment D don't has value of A or B)
end process;
end SIG_ARCH;
view raw vhdl_signal_vs_variable_1.vhd hosted with by GitHub

Variable assignment:
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_unsigned.all;
entity xor_var is
port (
A, B, C: in STD_LOGIC;
X, Y: out STD_LOGIC
);
end xor_var;

architecture VAR_ARCH of xor_var is


begin
VAR:process (A,B,C)
variable D: STD_LOGIC;
variable E: STD_LOGIC;
variable F: STD_LOGIC;
variable P: STD_LOGIC;
variable Q: STD_LOGIC;
begin
D := A; -- D is assigned with value of A.
E := D xor F; -- NEW value of D is taken for right-hand side evaluation. (D has value of A)
F := B xor D; -- NEW value of D is taken for right-hand side evaluation. (D has value of A)
P := C xor E; -- NEW value of E is taken for right-hand side evaluation.
D := B; -- Again value of D is changed. D is assigned with value of B.
Q := D xor F; -- NEW value of both D and F is taken for right-hand side evaluation.
-- (D has value of B, F has value of (B xor D(=A)))
X <= P;
Y <= Q;
end process;
end VAR_ARCH;
view raw vhdl_signal_vs_variable_2.vhd hosted with by GitHub
Posted by Sagar Shah No comments:
Email ThisBlogThis!Share to TwitterShare to FacebookShare to Pinterest
Labels: ASIC, interview_question, signal, variable, verification, VHDL

UVM_ERROR demoter code

/*!
* \brief report_catcher_err_info_demoter_c
* UVM_ERROT to UVM_INFO Demoter, demote UVM_ERROR based on ID or MESSAGE
of UVM_ERROR.
*/
class report_catcher_err_info_demoter_c #(int no_of_err_msg = 1,int no_of_err_id = 0) extends
uvm_report_catcher;
`uvm_object_utils(report_catcher_err_info_demoter_c)

int unsigned no_of_err_msg_demoted[]; /*! \param */


int unsigned no_of_err_id_demoted[]; /*! \param */
string exp_err[]; /*! \param */
string exp_id[]; /*! \param */
int unsigned string_offset; /*! \param */
//If we want that error should exactly the same as given, than make this bit 1
bit exact_match_msg[]; /*! \param */

/*!
* \brief Constructor
* Create a new transaction instance
* \parameter: name - Instance name of the transaction
*/
extern function new(string name = "report_catcher_err_info_demoter_c");

/*!
* \brief Function pattern_match_f
* Function used to match two string given as input arguments.
* If string matches it will return 1 else return 0.
* It is used to compare a message or ID of an error with
* expected error message or ID.
*/
extern function bit pattern_match_f(
input string str1, /*! \param string Output of get_message() or get_id() */
input string str2, /*! \param string Actual string which is demoted */
input bit ext_match, /*! \param bit used to represent exact_match_msg on/off */
input int unsigned err_num, /*! \param int used to represent Err num */
input bit msg_or_id /*! \param bit used to represent string is message or id, 1->msg, 0->id */
);

/*!
* \brief Function catch
* If severity is UVM_ERROR then change it to UVM_INFO.
*/
extern function action_e catch();

endclass : report_catcher_err_info_demoter_c
view raw uvm_demoter1.sv hosted with by GitHub

---------------------------------------------------------------------------------------------------------------------
----------

function report_catcher_err_info_demoter_c::new(string name =


"report_catcher_err_info_demoter_c");
super.new(name);
//dynamic array of size no_of_err_msg(no of error messages to be converted in to uvm_info)
exp_err = new[no_of_err_msg];
//dynamic array of size no_of_err_id(no of error messages to be converted in to uvm_info with
help of error id)
exp_id = new[no_of_err_id];

no_of_err_msg_demoted = new[no_of_err_msg];
no_of_err_id_demoted = new[no_of_err_id];
exact_match_msg = new[no_of_err_msg];
string_offset = 0;
endfunction : new

function bit report_catcher_err_info_demoter_c::pattern_match_f(


input string str1,
input string str2,
input bit ext_match,
input int unsigned err_num,
input bit msg_or_id
);

int unsigned length_of_str1;


int unsigned length_of_str2;
bit match;
length_of_str1 = str1.len();
length_of_str2 = str2.len();
`uvm_info(get_name(), $sformatf("length of str1=%0d, length of str2=%0d", length_of_str1,
length_of_str2), UVM_HIGH)

// Length comparision
if (length_of_str2 == 0) // compare with null
begin
if (msg_or_id == 1'b1)
begin
`uvm_info(get_name(), $sformatf("Length of Expected Err message is ZERO, Doing nothing for
err num %0d of err msg"), UVM_LOW)
end
else
begin
`uvm_info(get_name(), $sformatf("Length of Expected Err message is ZERO, Doing nothing for
err num %0d of err id"), UVM_LOW)
end
return 0;
end
else if(ext_match == 0)
begin
//lenght of expected error message can be same or less than actual error message
if(length_of_str2 > length_of_str1)
begin
return 0;
end
end
else
begin
//length of expected error message and actual message should same
if(length_of_str2 != length_of_str1)
begin
return 0;
end
end

//for(int i = string_offset; i < length_of_str2 ; i++)


for(int i = string_offset; i < (string_offset + length_of_str1 - length_of_str2 + 1) ; i++)
begin
if(str1.substr(i,i + length_of_str2 - 1) == str2)
begin
match = 1'b1;
return 1;
end
end

if (match == 1'b0)
begin
return 0;
end
endfunction : pattern_match_f
view raw uvm_demoter2.sv hosted with by GitHub

---------------------------------------------------------------------------------------------------------------------
----------
function action_e report_catcher_err_info_demoter_c::catch();
//if(get_severity() == UVM_ERROR || get_severity() == UVM_INFO)
if(get_severity() == UVM_ERROR)
begin
if(no_of_err_msg > 0)
begin
for(int i=0; i < no_of_err_msg; i++)
begin
if(pattern_match_f(.str1(get_message()), .str2(exp_err[i]), .ext_match(exact_match_msg[i]),
.err_num(i), .msg_or_id(1))
begin
set_severity(UVM_INFO);
set_action(UVM_NO_ACTION);
set_verbosity(UVM_HIGH);
no_of_err_msg_demoted[i] ++;
end
end
end

if(no_of_err_id > 0)
begin
for(int i=0; i < no_of_err_id; i++)
begin
if(pattern_match_f(.str1(get_id()), .str2(exp_id[i]), .ext_match(0), .err_num(i), .msg_or_id(0))
begin
set_severity(UVM_INFO);
set_action(UVM_NO_ACTION);
set_verbosity(UVM_HIGH);
no_of_err_id_demoted[i] ++;
end
end
end
end
return THROW;
endfunction
view raw uvm_demoter3.sv hosted with by GitHub
Posted by Sagar Shah No comments:
Email ThisBlogThis!Share to TwitterShare to FacebookShare to Pinterest
Labels: ASIC, demoter, systemverilog, UVM, verification

Package in SystemVerilog
First Example:
---------------------------------------------------------------------------------------------------------------------
-----------
package my_pkg1;
int unsigned a = 1;
endpackage : my_pkg1

module top1();
import my_pkg1 :: *;
initial begin
$display("my_pkg1::a = %0d", a);
end
endmodule : top1

//Output:
// my_pkg1::a = 1
view raw sv_pkg1.sv hosted with by GitHub

---------------------------------------------------------------------------------------------------------------------
-----------

Second Example:
---------------------------------------------------------------------------------------------------------------------
-----------
package my_pkg1;
int unsigned a = 1;
endpackage : my_pkg1

package my_pkg2;
import my_pkg1 :: *;
int unsigned b = 2;
endpackage : my_pkg2

module top2();
//import my_pkg1 :: *;
import my_pkg2 :: *;
initial begin
$display("top : my_pkg1::a = %0d, my_pkg2::b = %0d", a, b);
end
endmodule : top2

//Output:
// Identifier 'a' has not been declared yet. If this error is not expected, please check if you have set
`default_nettype to none.
view raw sv_pkg2.sv hosted with by GitHub

---------------------------------------------------------------------------------------------------------------------
-----------

Third Example:
---------------------------------------------------------------------------------------------------------------------
-----------
package my_pkg1;
int unsigned a = 1;
endpackage : my_pkg1

package my_pkg2;
import my_pkg1 :: *;
int unsigned b = 2;
endpackage : my_pkg2

module top3();
import my_pkg1 :: *;
import my_pkg2 :: *;
initial begin
$display("top : my_pkg1::a = %0d, my_pkg2::b = %0d", a, b);
end
endmodule : top3

//Output:
// top : my_pkg1::a = 1, my_pkg2::b = 2
view raw sv_pkg3.sv hosted with by GitHub
---------------------------------------------------------------------------------------------------------------------
-----------

Fourth Example:
---------------------------------------------------------------------------------------------------------------------
-----------
package my_pkg1;
int unsigned a = 1;
endpackage : my_pkg1

package my_pkg2;
import my_pkg1 :: *;
int unsigned b = 2;

function void pkg2_print();


$display("my_pkg2 : pkg2_print : my_pkg1::a = %0d, my_pkg2::b = %0d", a, b);
endfunction : pkg2_print
endpackage : my_pkg2

module top4();
import my_pkg2 :: *;
initial begin
void '(pkg2_print());
end
endmodule : top4

//Output:
// my_pkg2 : pkg2_print : my_pkg1::a = 1, my_pkg2::b = 2
view raw sv_pkg4.sv hosted with by GitHub

---------------------------------------------------------------------------------------------------------------------
-----------

Fifth Example:
---------------------------------------------------------------------------------------------------------------------
-----------
package my_pkg1;
int unsigned a = 1;
endpackage : my_pkg1

package my_pkg2;
import my_pkg1 :: *;
int unsigned b = 2;

function void pkg2_print();


$display("my_pkg2 : pkg2_print : my_pkg1::a = %0d, my_pkg2::b = %0d", a, b);
endfunction : pkg2_print
endpackage : my_pkg2

package my_pkg3;
//import my_pkg1 :: *;
import my_pkg2 :: *;
int unsigned c = 3;

function void pkg3_print();


$display("my_pkg3 : pkg3_print : my_pkg1::a = %0d, my_pkg2::b = %0d, my_pkg3::c = %0d",
a, b, c);
endfunction : pkg3_print
endpackage : my_pkg3

module top5();
import my_pkg3 :: *;
initial begin
void '(pkg3_print());
end
endmodule : top5

//Output:
// Identifier 'a' has not been declared yet. If this error is not expected, please check if you have set
`default_nettype to none
view raw sv_pkg5.sv hosted with by GitHub

---------------------------------------------------------------------------------------------------------------------
-----------

Sixth Example:
---------------------------------------------------------------------------------------------------------------------
-----------
package my_pkg1;
int unsigned a = 1;
endpackage : my_pkg1

package my_pkg2;
import my_pkg1 :: *;
int unsigned b = 2;

function void pkg2_print();


$display("my_pkg2 : pkg2_print : my_pkg1::a = %0d, my_pkg2::b = %0d", a, b);
endfunction : pkg2_print
endpackage : my_pkg2

package my_pkg3;
import my_pkg1 :: *;
import my_pkg2 :: *;
int unsigned c = 3;

function void pkg3_print();


$display("my_pkg3 : pkg3_print : my_pkg1::a = %0d, my_pkg2::b = %0d, my_pkg3::c = %0d",
a, b, c);
endfunction : pkg3_print
endpackage : my_pkg3

module top6();
import my_pkg3 :: *;
initial begin
void '(pkg3_print());
end
endmodule : top6
//Output:
// my_pkg3 : pkg3_print : my_pkg1::a = 1, my_pkg2::b = 2, my_pkg3::c = 3
view raw sv_pkg6.sv hosted with by GitHub

---------------------------------------------------------------------------------------------------------------------
-----------

Seventh Example:
---------------------------------------------------------------------------------------------------------------------
-----------
package my_pkg1;
int unsigned a = 1;
endpackage : my_pkg1

package my_pkg2;
import my_pkg1 :: *;
int unsigned b = 2;

function void pkg2_print();


$display("my_pkg2 : pkg2_print : my_pkg1::a = %0d, my_pkg2::b = %0d", a, b);
endfunction : pkg2_print
endpackage : my_pkg2

package my_pkg3;
//import my_pkg1 :: *;
import my_pkg2 :: *;
int unsigned c = 3;

function void pkg3_print();


$display("my_pkg3 : pkg3_print : my_pkg3::c = %0d", c);
$display("calling my_pkg2 :: pkg2_print");
pkg2_print();
endfunction : pkg3_print
endpackage : my_pkg3

module top7();
import my_pkg3 :: *;
initial begin
void '(pkg3_print());
end
endmodule : top7

//Output:
// my_pkg3 : pkg3_print : my_pkg3::c = 3
// calling my_pkg2 :: pkg2_print
// my_pkg2 : pkg2_print : my_pkg1::a = 1, my_pkg2::b = 2
view raw sv_pkg7.sv hosted with by GitHub

---------------------------------------------------------------------------------------------------------------------
-----------
Eighth Example: (package and module having variable with same name)
---------------------------------------------------------------------------------------------------------------------
-----------
package my_pkg1;
int unsigned a = 1;
endpackage : my_pkg1

module top();
int unsigned a = 2;
import my_pkg1 :: *;

initial begin
$display ("a=%0d", a);
$display ("my_pkg1::a=%0d", my_pkg1::a);
end
endmodule : top

//Output:
// a=2
// my_pkg1::a=1
view raw sv_pkg8.sv hosted with by GitHub
---------------------------------------------------------------------------------------------------------------------
-----------
Ninth Example: (package and module having variable with same name)
---------------------------------------------------------------------------------------------------------------------
-----------
package my_pkg1;
int unsigned a = 1;
endpackage : my_pkg1

module top();
// Not importing my_pkg1 here
int unsigned a = 2;

initial begin
$display ("a=%0d", a);
$display ("my_pkg1::a=%0d", my_pkg1::a);
end
endmodule : top

//Output:
// a=2
// my_pkg1::a=1
view raw sv_pkg9.sv hosted with by GitHub

---------------------------------------------------------------------------------------------------------------------
-----------
Posted by Sagar Shah No comments:
Email ThisBlogThis!Share to TwitterShare to FacebookShare to Pinterest
Labels: ASIC, package, systemverilog, verification

Friday, 18 December 2015


Semaphore in SystemVerilog

A semaphore allows you to control access to a resource.


Conceptually, a semaphore is a bucket. When a semaphore is allocated, a bucket that
contains a fixed number of keys is created. Processes using semaphores must first
procure a key from the bucket before they can continue to execute. If a specific process
requires a key, only a fixed number of occurrences of that process can be in progress
simultaneously. All others must wait until a sufficient number of keys are returned to the
bucket.

Semaphores are typically used for mutual exclusion, access control to shared
resources, and basic synchronization.

Imagine that you and your spouse share a car. Obviously, only one person can drive it
at a time. You can manage this situation by agreeing that whoever has the key can
drive it. When you are done with the car, you give up the car so that the other person
can use it. The key is the semaphore that makes sure only one person has access to
the car.

In operating system terminology, this is known as mutually exclusive access, so a


semaphore is known as a mutex and is used to control access to a resource.

Semaphores can be used in a testbench when you have a resource, such as a bus, that
may have multiple requestors from inside the testbench but, as part of the physical
design, can only have one driver.

In SystemVerilog, a thread that requests a key when it is not available always blocks the
execution of that particular thread. Multiple blocking threads are queued in FIFO order.

Semaphore is a built-in class that provides the following methods:


Create a semaphore with a specified number of keys: new()
Obtain one or more keys from the bucket: get()
Return one or more keys into the bucket: put()
Try to obtain one or more keys without blocking: try_get()

The default value for keyCount is 0.


If the specified number of keys is not available, the get() method blocks process until
the keys become available.
If the specified number of keys is not available, the try_get() method returns 0.

module top();
semaphore sema = new(1); // Create semaphore with 1 key.

initial begin
repeat(3) begin
fork
////////// PROCESS 1 ////////////////
begin
$display("1: Waiting for key, time=%0t", $time);
sema.get(1);
$display("1: Got the Key, time=%0t", $time);
#(10);// Do some work
sema.put(1);
$display("1: Returning back key, time=%0t", $time);
#(10);
end
////////// PROCESS 2 ////////////////
begin
#1;
$display("2: Waiting for Key, time=%0t", $time);
sema.get(1);
$display("2: Got the Key, time=%0t", $time);
#(10);//Do some work
sema.put(1);
$display("2: Returning back key, time=%0t", $time);
#(10);
end
join
$display();
end
#1000;
end
endmodule : top
view raw semaphore.sv hosted with by GitHub
//Output:
// 1: Waiting for key, time=0
// 1: Got the Key, time=0
// 2: Waiting for Key, time=1
// 1: Returning back key, time=10
// 2: Got the Key, time=10
// 2: Returning back key, time=20
//
// 1: Waiting for key, time=30
// 1: Got the Key, time=30
// 2: Waiting for Key, time=31
// 1: Returning back key, time=40
// 2: Got the Key, time=40
// 2: Returning back key, time=50
//
// 1: Waiting for key, time=60
// 1: Got the Key, time=60
// 2: Waiting for Key, time=61
// 1: Returning back key, time=70
// 2: Got the Key, time=70
// 2: Returning back key, time=80
view raw semaphore_output.sv hosted with by GitHub

Semaphores with Multiple Keys:


You can put more keys back than you took out. Suddenly you may have two keys but
only one car!

Be careful if your testbench needs to get and put multiple keys. Perhaps you have one
key left, and a thread requests two, causing it to block. Now a second thread requests a
single semaphore what should happen? In SystemVerilog the second request, get(1) ,
sneaks ahead of the earlier get(2) , bypassing the FIFO ordering.
Posted by Sagar Shah No comments:
Email ThisBlogThis!Share to TwitterShare to FacebookShare to Pinterest
Labels: ASIC, semaphore, systemverilog, verification

Thursday, 17 December 2015


Mailbox in SystemVerilog

How do you pass information between two threads? Perhaps your generator needs to
create many transactions and pass them to a driver. You might be tempted to just have
the generator thread call a task in the driver. If you do that, the generator needs to know
the hierarchical path to the driver task, making your code less reusable. Additionally,
this style forces the generator to run at the same speed as the driver, which can cause
synchronization problems if one generator needs to control multiple drivers. The
channel must allow its driver and receiver to operate asynchronously. You may be
tempted to just use a shared array or queue, but it can be difficult to create threads that
read, write, and blocks safely.

The solution is a SystemVerilog mailbox. From a hardware point of view, the easiest
way to think about a mailbox is that it is just a FIFO, with a source and sink. The source
puts data into the mailbox, and the sink gets values from the mailbox.

A mailbox is a communication mechanism that allows messages to be exchanged


between processes. Data can be sent to a mailbox by one process and retrieved by
another.

Conceptually, mailboxes behave like real mailboxes. When a letter is delivered and put
into the mailbox, a person can retrieve the letter (and any data stored within). However,
if the letter has not been delivered when the mailbox is checked, the person must
choose whether to wait for the letter or to retrieve the letter on a subsequent trip to the
mailbox. Similarly, SystemVerilogs mailboxes provide processes to transfer and
retrieve data in a controlled manner. Mailboxes are created as having either a bounded
or unbounded queue size. A bounded mailbox becomes full when it contains the
bounded number of messages. A process that attempts to place a message into a full
mailbox shall be suspended until enough room becomes available in the mailbox queue.
Unbounded mailboxes never suspend a thread in a send operation.

Mailbox is a built-in class that provides the following methods:


Create a mailbox: new()
Place a message in a mailbox: put()
Try to place a message in a mailbox without blocking: try_put()
Retrieve a message from a mailbox: get() or peek()
Try to retrieve a message from a mailbox without blocking: try_get() or try_peek()
Retrieve the number of messages in the mailbox: num()

A put() blocks if the mailbox is full, and get() blocks if the mailbox is empty.
Use try_put() if you want to see if the mailbox is full. And try_get() to see if it is empty.
Both are non-blocking methods.
If they are successful, they return a nonzero value; otherwise, they return 0. In other
words,
If the mailbox is full, the method try_put() returns 0.
If the mailbox is empty, then the method try_get() or try_peek() returns 0.

These are more reliable than the num() function, as the number of entries can change
between when you measure it and when you next access the mailbox.
The peek() task gets a copy of the data in the mailbox but does not remove it.
The data is a single value, such as an integer, or logic of any size or a handle. A
mailbox never contains objects, only references to them.

The default mailbox is typeless, that is, a single mailbox can send and receive any type
of data. This is a very powerful mechanism, which, unfortunately, can also result in run-
time errors due to type mismatches (types not equivalent) between a message and the
type of the variable used to retrieve the message. Frequently, a mailbox is used to
transfer a particular message type, and, in that case, it is useful to detect type
mismatches at compile time.

mailbox #(transaction) mb_tr; // Parameterized : Recommended


mailbox mb_untyped; // Unspecialized : Not recommended (avoid)
view raw mailbox1.sv hosted with by GitHub

A classic mailbox bug:


A loop that randomizes objects and puts them in a mailbox, but the object is only
constructed once, outside the loop. Since there is only one object, it is randomized over
and over.
Below figure shows all the handles pointing to a single object. A mailbox only holds
handles, not objects, so you end up with a mailbox containing multiple handles that all
point to the single object. The code that gets the handles from the mailbox just sees the
last set of random values.

class transaction;
rand bit [7:0] data;
rand bit [7:0] addr;
endclass : transaction

class generator;
task transmit_bad(input int unsigned n,
input mailbox #(transaction) mb);
transaction tr;
tr = new();
repeat (n) begin
if (!tr.randomize()) begin
$error("randomization failed");
end
else begin
$display("GEN: transmit_bad: after randomization tr.addr=%0h, tr.data=%0h", tr.addr, tr.data);
end
mb.put(tr);
end
endtask : transmit_bad
endclass : generator

class driver;
task receive_bad(input mailbox #(transaction) mb);
transaction tr;
forever begin
#5ns;
mb.get(tr);
// drive tranaction to DUT
$display("DRV: receive_bad: Received tr.addr=%0h, tr.data=%0h", tr.addr, tr.data);
end
endtask : receive_bad
endclass : driver

module top();
generator gen;
driver drv;
mailbox #(transaction) mb;

initial begin
mb = new();
gen = new();
drv = new();

// Run producer and Consumer in parallel


fork
begin
gen.transmit_bad (5, mb);
end
begin
drv.receive_bad(mb);
end
join
end
endmodule : top
view raw mailbox_bug.sv hosted with by GitHub
//Output:
// GEN: transmit_bad: after randomization tr.addr=26, tr.data=3
// GEN: transmit_bad: after randomization tr.addr=f6, tr.data=e3
// GEN: transmit_bad: after randomization tr.addr=0, tr.data=9e
// GEN: transmit_bad: after randomization tr.addr=7a, tr.data=dd
// GEN: transmit_bad: after randomization tr.addr=6f, tr.data=c2
// DRV: receive_bad: Received tr.addr=6f, tr.data=c2
// DRV: receive_bad: Received tr.addr=6f, tr.data=c2
// DRV: receive_bad: Received tr.addr=6f, tr.data=c2
// DRV: receive_bad: Received tr.addr=6f, tr.data=c2
// DRV: receive_bad: Received tr.addr=6f, tr.data=c2
view raw mailbox_bug_output.sv hosted with by GitHub
The overcome this bug; make sure your loop has all three steps,
1) constructing the object,
2) randomizing it,
3) putting it in the mailbox
The result, shown in below figure, is that every handle points to a unique object. This
type of generator is known as the Blueprint Pattern.

class transaction;
rand bit [7:0] data;
rand bit [7:0] addr;
endclass : transaction

class generator;
task transmit_good(input int unsigned n,
input mailbox #(transaction) mb);
transaction tr;
repeat (n) begin
// constructing the object
tr = new();
// randomizing object
if (!tr.randomize()) begin
$error("randomization failed");
end
else begin
$display("GEN: transmit_good: after randomization tr.addr=%0h, tr.data=%0h", tr.addr, tr.data);
end
// putting object in the mailbox
mb.put(tr);
end
endtask : transmit_good
endclass : generator

class driver;
task receive_good(input mailbox #(transaction) mb);
transaction tr;
forever begin
#5ns;
mb.get(tr);
// drive tranaction to DUT
$display("DRV: receive: Received tr.addr=%0h, tr.data=%0h", tr.addr, tr.data);
end
endtask : receive_good
endclass : driver

module top();
generator gen;
driver drv;
mailbox #(transaction) mb;

initial begin
mb = new();
gen = new();
drv = new();

// Run producer and Consumer in parallel


fork
begin
gen.transmit_good (5, mb);
end
begin
drv.receive_good(mb);
end
join
end
endmodule : top
view raw mailbox_good.sv hosted with by GitHub
//Output:
// GEN: transmit_good: after randomization tr.addr=26, tr.data=3
// GEN: transmit_good: after randomization tr.addr=5c, tr.data=76
// GEN: transmit_good: after randomization tr.addr=27, tr.data=40
// GEN: transmit_good: after randomization tr.addr=3f, tr.data=c9
// GEN: transmit_good: after randomization tr.addr=eb, tr.data=99
// DRV: receive: Received tr.addr=26, tr.data=3
// DRV: receive: Received tr.addr=5c, tr.data=76
// DRV: receive: Received tr.addr=27, tr.data=40
// DRV: receive: Received tr.addr=3f, tr.data=c9
// DRV: receive: Received tr.addr=eb, tr.data=99
view raw mailbox_good_output.sv hosted with by GitHub

Bounded Mailboxes:
By default, mailboxes are similar to an unlimited FIFO a producer can put any
number of objects into a mailbox before the consumer gets the objects out. However,
you may want the two threads to operate in lockstep so that the producer blocks until
the consumer is done with the object.

You can specify a maximum size for the mailbox when you construct it. The default
mailbox size is 0 which creates an unbounded mailbox. Any size greater than 0 creates
a bounded mailbox. If you attempt to put more objects than this limit, put() blocks until
you get an object from the mailbox, creating a vacancy.

Synchronized Threads Using a Bounded Mailbox and


a Peek:
In many cases, two threads that are connected by a mailbox should run in lockstep, so
that the producer does not get ahead of the consumer. The benefit of this approach is
that your entire chain of stimulus generation now runs in lock step.

To synchronize two threads, the Producer creates and puts a transaction into a mailbox,
then blocks until the
Consumer finishes with it. This is done by having the Consumer remove the transaction
from the mailbox only when it is finally done with it, not when the transaction is first
detected.

Below example shows the first attempt to synchronize two threads, this time with a
bounded mailbox. The Consumer uses the built-in mailbox method peek() to look at the
data in the mailbox without removing. When the Consumer is done processing the data,
it removes the data with get() . This frees up the Producer to generate a new value. If
the Consumer loop started with a get() instead of the peek() , the transaction would be
immediately removed from the mailbox, so the Producer could wake up before the
Consumer finished with the transaction.

class transaction;
rand bit [7:0] data;
rand bit [7:0] addr;
endclass : transaction

class generator;
task transmit(input int unsigned n,
input mailbox #(transaction) mb);
transaction tr;
repeat (n) begin
// constructing the object
tr = new();
// randomizing object
if (!tr.randomize()) begin
$error("randomization failed");
end
else begin
$display("GEN: transmit: after randomization tr.addr=%0h, tr.data=%0h", tr.addr, tr.data);
end
// putting object in the mailbox
mb.put(tr);
end
endtask : transmit
endclass : generator

class driver;
task receive(input mailbox #(transaction) mb);
transaction tr;
forever begin
mb.peek(tr); // peek object from mailbox
#5ns;
$display("DRV: receiver: Received tr.addr=%0h, tr.data=%0h", tr.addr, tr.data);
// drive tranaction to DUT
mb.get(tr); // Remove object from mailbox
end
endtask : receive
endclass : driver

module top();
generator gen;
driver drv;
mailbox #(transaction) mb;

initial begin
mb = new(1); // Bounded mailbox - limit=1
gen = new();
drv = new();

// Run producer and Consumer in parallel


fork
begin
gen.transmit (5, mb);
end
begin
drv.receive(mb);
end
join
end
endmodule : top
view raw mailbox_sync.sv hosted with by GitHub
//Output:
// GEN: transmit: after randomization tr.addr=26, tr.data=3
// GEN: transmit: after randomization tr.addr=5c, tr.data=76
// DRV: receiver: Received tr.addr=26, tr.data=3
// GEN: transmit: after randomization tr.addr=27, tr.data=40
// DRV: receiver: Received tr.addr=5c, tr.data=76
// GEN: transmit: after randomization tr.addr=3f, tr.data=c9
// DRV: receiver: Received tr.addr=27, tr.data=40
// GEN: transmit: after randomization tr.addr=eb, tr.data=99
// DRV: receiver: Received tr.addr=3f, tr.data=c9
// DRV: receiver: Received tr.addr=eb, tr.data=99
view raw mailbox_sync_output.sv hosted with by GitHub

You can see that the Producer and Consumer are in lockstep, but the Producer is still
one transaction ahead of the Consumer. This is because a bounded mailbox with
size=1 only blocks when you try to do a put of the second transaction.

Posted by Sagar Shah 2 comments:


Email ThisBlogThis!Share to TwitterShare to FacebookShare to Pinterest
Labels: ASIC, mailbox, systemverilog, verification

Wednesday, 16 December 2015


Randsequence in SystemVerilog

The random sequence generator is useful for randomly generating structured


sequences of stimulus such as instructions or network traffic patterns.
By randomizing a packet, it will generate most unlikely scenarios which are not
interested. These type of sequence of scenarios can be generated using randsequence.

randsequence is composed of one or more productions.


Each production contains a name and one or more production_list.
Production_list contains one or more production_item.
Production_items of production_list are further classified into terminals and non-
terminals.
Non-terminals are defined in terms of terminals and other non-terminals.
A terminal is an indivisible item that needs no further definition than its associated code
block.
Ultimately, every non-terminal is decomposed into its terminals.

module rand_sequence1();
initial begin
repeat(5) begin
randsequence( main )
main : one two three ;
one : {$write("one");};
two : {$write(" two");};
three: {$display(" three");};
endsequence
end
end
endmodule : rand_sequence1

// Here production is "main".


// production "main" contain only one production_list with 3 production_items named "one",
"two", "three".
// production_items "one", "two", "three" are terminals.
// When the "main" is chosen, it will select the sequence "one", "two" and "three" in order.

//Output:
// one two three
// one two three
// one two three
// one two three
// one two three
view raw rand_sequence1.sv hosted with by GitHub

A single production can contain multiple production lists.


multiple production lists are separated by the | symbol.
Production lists separated by a | imply a set of choices, which the generator will make at
random.

module rand_sequence2();
initial begin
repeat(8) begin
randsequence( main )
main : one | two | three ;
one : {$display("one");};
two : {$display("two");};
three: {$display("three");};
endsequence
end
end
endmodule : rand_sequence2

// Here "main" is production,


// "main" has 3 production_list, each production_list consist 1 production_item,
// 1st production_list has a production_item called "one",
// 2nd production_list has a production_item called "two",
// 3rd production_list has a production_item called "three",
// production_items "one", "two", "three" all are terminals.

//Output:
// three
// three
// one
// two
// three
// two
// two
// one

//Results show that one, two and three are selected randomly.
view raw rand_sequence2.sv hosted with by GitHub

By default procution_list is generated randomly, you can give probability for a


production_list generation.
The probability that a production list is generated can be changed by assigning weights
to production lists.
The probability that a particular production list is generated is proportional to its
specified weight.
The := operator assigns the weight specified by the weight_specification to its
production list.
A weight_specification must evaluate to an integral non-negative value.
Weight expressions are evaluated when their enclosing production is selected, thus
allowing weights to change dynamically.

module rand_sequence3();
integer one_1,two_2,three_3;
initial begin
one_1 = 0;
two_2 = 0;
three_3 = 0;
repeat(6000) begin
randsequence( main )
main : one := 1 | two := 2 | three := 3;
one : {one_1++;};
two : {two_2++;};
three: {three_3++;};
endsequence
end
$display(" one %0d \n two %0d \n three %0d",one_1,two_2,three_3);
end
endmodule : rand_sequence3

//Output:
// one 1044
// two 1970
// three 2986
view raw rand_sequence3.sv hosted with by GitHub

A production can be made conditional by means of an if..else production statement.


The expression can be any expression that evaluates to a boolean value. If the
expression evaluates to true, the production following the expression is generated,
otherwise the production following the optional else statement is generated.

module rand_sequence4();
integer one_1,two_2,three_3;
reg on;
initial begin
on = 0;
one_1 = 0;
two_2 = 0;
three_3 = 0;
repeat(2500) begin
randsequence( main )
main : one three;
one : {if(on) one_1++; else two_2 ++; };
three: {three_3++;};
endsequence
end
$display(" one %0d \n two %0d \n three %0d",one_1,two_2,three_3);
end
endmodule : rand_sequence4

//Output:
// one 0
// two 2500
// three 2500
view raw rand_sequence4.sv hosted with by GitHub

module rand_sequence4a();
integer one_1,two_2,three_3;
reg on;
initial begin
on = 0;
one_1 = 0;
two_2 = 0;
three_3 = 0;
repeat(2500) begin
randsequence( main )
main : one three;
one : if(on) incr_one else incr_two;
incr_one : {one_1 += 2; one_1--;};
incr_two : {two_2 += 2; two_2--;};
three: {three_3++;};
endsequence
end
$display(" one %0d \n two %0d \n three %0d",one_1,two_2,three_3);
end
endmodule : rand_sequence4a
//Output:
// one 0
// two 2500
// three 2500
view raw rand_sequence4a.sv hosted with by GitHub

A production can be selected from a set of alternatives using a case production


statement.
The case expression is evaluated, and its value is compared against the value of each
case-item expression, which are evaluated and compared in the order in which they are
given.
The production associated with the first case-item expression that matches the case
expression is generated.
If no matching case-item expression is found then the production associated with the
optional default item is generated, or nothing if there no default item.
Case-item expressions separated by commas allow multiple expressions to share the
production.

module rand_sequence5();
integer one_1,two_2,three_3;
initial begin
for(int i = 0 ;i < 10 ;i++)
begin
randsequence( main )
main : case(i%3)
0 : zero;
1, 2 : non_zero;
default : def;
endcase;
zero : {$display("zero");};
non_zero : {$display("non_zero");};
def : {$display("default");};
endsequence
end
end
endmodule : rand_sequence5

//Output:
// zero
// non_zero
// non_zero
// zero
// non_zero
// non_zero
// zero
// non_zero
// non_zero
// zero
view raw rand_sequence5.sv hosted with by GitHub

The repeat production statement is used to iterate a production over a specified number
of times.

module rand_sequence6();
integer one_1,two_2,three_3;
initial begin
one_1 = 0;
two_2 = 0;
three_3 = 0;
repeat(6000) begin
randsequence( main )
main : one | repeat(2) two | repeat(3) three ;
one : {one_1 ++; };
two : {two_2 ++; };
three: {three_3 ++; };
endsequence
end
$display(" one %d \n two %d \n three %d",one_1,two_2,three_3);
end
endmodule : rand_sequence6

//Output:
// one 2059
// two 4072
// three 5715
view raw rand_sequence6.sv hosted with by GitHub
Posted by Sagar Shah 8 comments:
Email ThisBlogThis!Share to TwitterShare to FacebookShare to Pinterest
Labels: ASIC, randomization, systemverilog, verification

Randcase in SystemVerilog

randcase is a case statement that randomly selects one of its branches.


Randcase can be used in class or modules.
The randcase item expressions are non-negative integral values that constitute the
branch weights.
An item weight divided by the sum of all weights gives the probability of taking that
branch.

For example:
randcase
3 : x = 1;
1 : x = 2;
4 : x = 3;
endcase
view raw randcase1.sv hosted with by GitHub

The sum of all weights is 8; therefore, the probability of taking the first branch is
(3/8)0.375, the probability

of taking the second is (1/8)0.125, and the probability of taking the third is (4/8)0.5.
If a branch specifies a zero weight, then that branch is not taken.
If all randcase_items specify zero weights, then no branch is taken and a warning can
be issued.

The randcase weights can be arbitrary expressions, not just constants.

For example:
byte a, b;
randcase
a + b : x = 1;
a - b : x = 2;
a ^ ~b : x = 3;
12'b800 : x = 4;
endcase
view raw randcase2.sv hosted with by GitHub

In the preceding example, the first three weight expressions are computed using 8-bit
precision, and the fourth

expression is computed using 12-bit precision.


The resulting weights are added as unsigned values using 12-bit precision. The weight
selection then uses unsigned

12-bit comparison.

Each call to randcae statement will return a random number in the range from 0 to
SUM.
$urandom_range(0,SUM) is used to generate a random number.

module rand_case;
integer x;
integer cnt_1, cnt_2, cnt_3;

initial begin
cnt_1 = 0;
cnt_2 = 0;
cnt_3 = 0;
repeat(100000) begin
randcase
3 : x = 1;
1 : x = 2;
4 : x = 3;
endcase
if(x == 1) begin
cnt_1++;
end
else if(x == 2) begin
cnt_2++;
end
else if(x ==3) begin
cnt_3++;
end
end
$display("count_1 = %0d, count_2 = %0d, count_3 = %0d", cnt_1, cnt_2, cnt_3);
$display("Probability of count_1 = %0f, count_2 = %0f, count_3 = %0f", (cnt_1/100000.0),
(cnt_2/100000.0), (cnt_3/100000.0));
end
endmodule : rand_case

//Output:
// count_1 = 37378, count_2 = 12480, count_3 = 50142
// Probability of count_1 = 0.373780, count_2 = 0.124800, count_3 = 0.501420
view raw randcase3.sv hosted with by GitHub

You might also like