SystemVerilog FAQ
SystemVerilog FAQ
SystemVerilog FAQ
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}
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
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
-----------------------------------------------------------------------------------------------
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;
}
//Output:
// R.str=zsyF_]D
view raw rand_string.sv hosted with by GitHub
-----------------------------------------------------------------------------------------------
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
-----------------------------------------------------------------------------------------------
int UniqVal[10];
foreach(UniqVal[i]) begin
UniqVal[i] = i;
end
UniqVal.shuffle();
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.
constraint cn_1 {
a >= 0; a < L;
}
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
-------------------------------------------------------------
constraint cn_1 {
a != b;
a >= 0; a < L;
b >= 0; b < L;
}
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
-------------------------------------------------------------
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
// Constraints
constraint cc {
// constraining size
data[0] > 5;
// All elements
foreach(data[i])
if(i > 0)
endclass : ABC
class test;
base B;
child C;
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
-------------------------------------------------------------
class test;
base B;
child C;
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
-------------------------------------------------------------
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.
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.
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.
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
What is "this"?
"this" pointer refers to current instance.
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.
initial begin
end
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.
if(!reset_) begin
end
end
fork
begin : reset_logic
@ (negedge reset_);
end : reset_logic
begin : clk_logic
@ (posedge clk);
end : clk_logic
join_any
disable fork
end
-------------------------------------------------------------------------------------
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;
// Declared as 'protected',
endfunction : new
// Make it static,
// To create instance of this class first time when this it is not create
single = new();
end
return single;
endfunction : create
endclass : singleton
module top();
initial begin
s1 = singleton :: create();
s1.var1 = 10;
s2 = singleton :: create();
s2.var1 = 20;
endmodule : top
//Output:
// 1 : s1.var1 = 0
// 2 : s1.var1 = 10
// 3 : s2.var1 = 10
// 4 : s2.var1 = 20
// 5 : s1.var1 = 20
---------------------------------------------------------------------
if(inst==null)
inst=new;
return inst;
endfunction // get
endclass
return uvm_root::m_uvm_get_root();
endfunction
endclass
// singleton handle
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
m_check_verbosity();
endfunction
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;
uvm_coreservice_t cs = uvm_coreservice_t::get();
return cs.get_root();
endfunction
endclass
---------------------------------------------------------------------
To understand difference between m_sequencer and p_sequencer, let's first go through couple of
classes from UVM library.
-------------------------------------------------------------------------------------
// Set the sequence and sequencer execution context for a sequence item
set_use_sequence_info(1);
reseed();
endfunction
// Sets the default sequencer for the sequence to sequencer. It will take
m_sequencer = sequencer;
m_set_p_sequencer();
endfunction
endclass
-------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------
//
// The ~sequencer~ argument specifies the sequencer on which to run this
set_item_context(parent_sequence, sequencer);
...
endtask
endclass
//
// specified by ~SEQUENCER~.
`define uvm_declare_p_sequencer(SEQUENCER) \
SEQUENCER 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
-------------------------------------------------------------------------------------
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.
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.
----------------------------------------------------
class rand_mo;
integer Var2;
endclass
program rand_mo_p_38;
initial begin
void'(obj.randomize(Var2));
void'(obj.randomize(Var1, Var2));
void'(obj.randomize(null));
end
endprogram
// Output:
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.
---------------------------------------------------------------------
class rand_mo;
endclass
program rand_mo_p_23;
initial begin
void'(obj.randomize());
void'(obj.randomize());
obj.rand_mode(1);
void'(obj.randomize());
end
endprogram
//Output:
---------------------------------------------------------------------
---------------------------------------------------------------------
class rand_mo;
endclass
program rand_mo_p_24;
initial begin
void'(obj.randomize());
obj.Var1.rand_mode(0);
void'(obj.randomize());
obj.Var2.rand_mode(0);
obj.Var1.rand_mode(1);
void'(obj.randomize());
endprogram
//Output:
// 1 : Var1 : -902462825 Var2 : -1241023056 // Botn Var1 and Var2 are 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)
---------------------------------------------------------------------
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;
endclass
program rand_mo_p_24;
void'(obj.randomize());
obj.Var1.rand_mode(0);
void'(obj.randomize());
if(obj.Var1.rand_mode()) begin
end
else begin
end
void'(obj.randomize());
end
endprogram
//Output:
// 3b : Var1 is nonrandom
---------------------------------------------------------------------
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.
---------------------------------------------------------------------
class A;
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());
void'(obj_2.randomize());
end
end
endprogram
//Output:
---------------------------------------------------------------------
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.
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;
endclass
program rand_mo_p_38;
initial begin
obj.constraint_mode(0);
void'(obj.randomize());
obj.constraint_mode(1);
void'(obj.randomize());
end
endprogram
//Output:
---------------------------------------------------------------------
---------------------------------------------------------------------
// object_name.constraint_name.constraint_mode
class rand_mo;
endclass
program rand_mo_p_38;
initial begin
void'(obj.randomize());
obj.Var_1.constraint_mode(0);
void'(obj.randomize());
obj.Var_1.constraint_mode(1);
void'(obj.randomize());
end
endprogram
//Output:
---------------------------------------------------------------------
---------------------------------------------------------------------
// Used as Function
class rand_mo;
endclass
program rand_mo_p_38;
initial begin
obj.Var_1.constraint_mode(0);
void'(obj.randomize());
if (obj.Var_1.constraint_mode())
else
if (obj.Var_2.constraint_mode())
else
void'(obj.randomize());
end
endprogram
//Output:
---------------------------------------------------------------------
SV provides build in methods to facilitate searching from array, array ordering and
reduction.
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.
initial begin
q = {9, 1, 8, 3, 4, 4};
$display("1. queue 'q' in decimal : %p", q);
//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
---------------------------------------------------------------------
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
---------------------------------------------------------------------
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
---------------------------------------------------------------------
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);
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);
//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
2) setting callbacks,
We can also add callbacks whenever an event is triggered. This is done by registering a
callback class with particular 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;
//-----------------------------------------------------------------------------
// 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
//-----------------------------------------------------------------------
// Sequencer Class
//-----------------------------------------------------------------------
typedef class my_agent;
class my_sequencer extends uvm_sequencer #(my_seq_item);
my_agent parent;
`uvm_component_utils (my_sequencer)
-------------------------------------------------------------------
//-----------------------------------------------------------------------
// 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)
//-----------------------------------------------------------------------
// 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
//-----------------------------------------------------------------------
// 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
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.
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
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);
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
// 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 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.
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;
//-----------------------------------------------------------------------------
// 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
//-----------------------------------------------------------------------------
// 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;
}
//-----------------------------------------------------------------------------
// 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
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
//-----------------------------------------------------------------------------
// 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
cfg.is_valid();
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)
task body();
endtask : body
endclass : my_base_sequence
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
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;
initial begin
run_test("my_test");
end
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
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"
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"
// 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
Advantages of Pointer:
Drawback of Pointer:
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
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/
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.
import uvm_pkg::*;
class test extends uvm_test;
`uvm_component_utils(test)
module top();
initial begin
run_test("test");
end
endmodule : top
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;
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
-------------------------------------------------
import uvm_pkg::*;
class test extends uvm_test;
`uvm_component_utils(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.
import uvm_pkg::*;
class test extends uvm_test;
`uvm_component_utils(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
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.
//-----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
//-----Sequencer-----
class my_sequencer extends uvm_sequencer #(my_seq_item);
`uvm_sequencer_utils(my_sequencer)
//-----Driver-----
class my_driver extends uvm_driver #(my_seq_item);
`uvm_component_utils(my_driver)
//-----Agent-----
class my_agent extends uvm_agent;
my_sequencer sqr;
my_driver drv;
`uvm_component_utils(my_agent)
//-----seq_a-----
class seq_a extends uvm_sequence #(my_seq_item);
my_seq_item req;
`uvm_object_utils(seq_a)
//-----seq_b-----
class seq_b extends uvm_sequence #(my_seq_item);
my_seq_item req;
`uvm_object_utils(seq_b)
//-----seq_c-----
class seq_c extends uvm_sequence #(my_seq_item);
my_seq_item req;
`uvm_object_utils(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)
//-----Test-----
class my_test extends uvm_test;
my_agent agent;
`uvm_component_utils(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::*;
//-----Sequencer-----
class my_sequencer extends uvm_sequencer #(my_seq_item);
`uvm_sequencer_utils(my_sequencer)
//-----Driver-----
class my_driver extends uvm_driver #(my_seq_item);
`uvm_component_utils(my_driver)
//-----Agent-----
class my_agent extends uvm_agent;
my_sequencer sqr;
my_driver drv;
`uvm_component_utils(my_agent)
//-----seq_a-----
class seq_a extends uvm_sequence #(my_seq_item);
my_seq_item req;
`uvm_object_utils(seq_a)
//-----seq_b-----
class seq_b extends uvm_sequence #(my_seq_item);
my_seq_item req;
`uvm_object_utils(seq_b)
//-----seq_c-----
class seq_c extends uvm_sequence #(my_seq_item);
my_seq_item req;
`uvm_object_utils(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)
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::*;
//-----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
//-----Sequencer-----
class my_sequencer extends uvm_sequencer #(my_seq_item);
`uvm_sequencer_utils(my_sequencer)
//-----Driver-----
class my_driver extends uvm_driver #(my_seq_item);
`uvm_component_utils(my_driver)
//-----Agent-----
class my_agent extends uvm_agent;
my_sequencer sqr;
my_driver drv;
`uvm_component_utils(my_agent)
//-----Virtual Sequencer-----
class my_virtual_sqr extends uvm_sequencer;
my_sequencer sqr1;
my_sequencer sqr2;
`uvm_component_utils(my_virtual_sqr)
endclass : my_virtual_sqr
//-----seq_a-----
class seq_a extends uvm_sequence #(my_seq_item);
my_seq_item req;
`uvm_object_utils(seq_a)
//-----seq_b-----
class seq_b extends uvm_sequence #(my_seq_item);
my_seq_item req;
`uvm_object_utils(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 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)
//-----Test-----
class my_test extends uvm_test;
my_agent agent1;
my_agent agent2;
my_virtual_sqr vsqr;
`uvm_component_utils(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
---------------------------------------------
//-----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
//-----Sequencer-----
class my_sequencer extends uvm_sequencer #(my_seq_item);
`uvm_sequencer_utils(my_sequencer)
//-----Agent-----
class my_agent extends uvm_agent;
my_sequencer sqr;
my_driver drv;
`uvm_component_utils(my_agent)
//-----Virtual Sequencer-----
class my_virtual_sqr extends uvm_sequencer;
my_sequencer sqr1;
my_sequencer sqr2;
`uvm_component_utils(my_virtual_sqr)
endclass : my_virtual_sqr
//-----seq_a-----
class seq_a extends uvm_sequence #(my_seq_item);
my_seq_item req;
`uvm_object_utils(seq_a)
//-----seq_b-----
class seq_b extends uvm_sequence #(my_seq_item);
my_seq_item req;
`uvm_object_utils(seq_b)
//-----seq_c-----
class seq_c extends uvm_sequence #(my_seq_item);
my_seq_item req;
`uvm_object_utils(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)
// 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::*;
//-----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
//-----Sequencer-----
class my_sequencer extends uvm_sequencer #(my_seq_item);
`uvm_sequencer_utils(my_sequencer)
//-----Driver-----
class my_driver extends uvm_driver #(my_seq_item);
`uvm_component_utils(my_driver)
//-----Agent-----
class my_agent extends uvm_agent;
my_sequencer sqr;
my_driver drv;
`uvm_component_utils(my_agent)
//-----Virtual Sequencer-----
class my_virtual_sqr extends uvm_sequencer;
my_sequencer sqr1;
my_sequencer sqr2;
`uvm_component_utils(my_virtual_sqr)
//-----seq_a-----
class seq_a extends uvm_sequence #(my_seq_item);
my_seq_item req;
`uvm_object_utils(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
//-----seq_c-----
class seq_c extends uvm_sequence #(my_seq_item);
my_seq_item req;
`uvm_object_utils(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)
//-----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)
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
---------------------------------------------
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;
-----------------------------------------------
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
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
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 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
-----------------------------------------------
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
------------------------------------------------------------------------------
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
------------------------------------------------------------------------------
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();
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
------------------------------------------------------------------------------
------------------------------------------------------------------------------
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
How to achieve this using SystemVerilog constructs, that we will understand through
an example.
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
-------------------------------------------------------------------------------------
After fork...join_none, I am waiting for semaphore to get at least two key ().
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.
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.
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
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
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 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 hello();
`uvm_info(get_full_name, $sformatf("HELLO from override class 'B_ovr'"), UVM_LOW);
endfunction : hello
endclass : B_ovr
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;
//-------------------test class--------------------------
class test extends uvm_test;
`uvm_component_utils(test)
environment env;
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 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
function hello();
`uvm_info(get_full_name, $sformatf("HELLO from override class 'B_ovr'"), UVM_LOW);
endfunction : hello
endclass : B_ovr
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;
//-------------------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
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)
//--------------------uvm_object------------------------------
class B extends uvm_object;
`uvm_object_utils(B)
//--------------------env class--------------------
class environment extends uvm_env;
`uvm_component_utils(environment)
A a1;
B b1, b2;
//-------------------test class--------------------------
class test extends uvm_test;
`uvm_component_utils(test)
environment env;
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
Type Overrides:
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)
//--------------------uvm_object------------------------------
class B extends uvm_object;
`uvm_object_utils(B)
//--------------------env class--------------------
class environment extends uvm_env;
`uvm_component_utils(environment)
A a1;
B b1, b2;
B_ovr b3;
//-------------------test class--------------------------
class test extends uvm_test;
`uvm_component_utils(test)
environment env;
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
Type Overrides:
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>
####
-------------------------------------------------------
-------------------------------------------------------
// 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)
//--------------------uvm_object------------------------------
class B extends uvm_object;
`uvm_object_utils(B)
//--------------------env class--------------------
class environment extends uvm_env;
`uvm_component_utils(environment)
A a1, a2, a3;
B b1, b2, b3;
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");
//-------------------test class--------------------------
class test extends uvm_test;
`uvm_component_utils(test)
environment env;
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
Instance Overrides:
Type Overrides:
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_object------------------------------
class B extends uvm_object;
`uvm_object_utils(B)
//--------------------env class--------------------
class environment extends uvm_env;
`uvm_component_utils(environment)
A a1, a2, a3;
B b1, b2, b3;
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");
//-------------------test class--------------------------
class test extends uvm_test;
`uvm_component_utils(test)
environment env;
module top();
initial begin
run_test("test");
end
endmodule : top
view raw override_by_cmd_line.sv hosted with by GitHub
-------------------------------------------------------
Instance Overrides:
Type Overrides:
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
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;
// 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_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
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.
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.
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
-------------------------------------------------------------------------------------
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.
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);
// 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:
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.
program rand_mo_p_23;
rand_mo obj = new();
initial begin
void'(obj.randomize());
$display(" 1 : Var1 : %d, Var2 : %d ",obj.Var1, obj.Var2);
//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
---------------------------------------------------------------------
program rand_mo_p_24;
rand_mo obj = new();
initial begin
void'(obj.randomize());
$display(" 1 : Var1 : %d Var2 : %d ",obj.Var1,obj.Var2);
//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.
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
---------------------------------------------------------------------
// 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);
//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);
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
---------------------------------------------------------------------
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.
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;
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;
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;
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;
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;
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
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.
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.
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;
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;
/*!
* \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)
/*!
* \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
---------------------------------------------------------------------------------------------------------------------
----------
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
// 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
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;
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;
package my_pkg3;
//import my_pkg1 :: *;
import my_pkg2 :: *;
int unsigned c = 3;
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;
package my_pkg3;
import my_pkg1 :: *;
import my_pkg2 :: *;
int unsigned c = 3;
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;
package my_pkg3;
//import my_pkg1 :: *;
import my_pkg2 :: *;
int unsigned c = 3;
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
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.
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.
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
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
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.
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.
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.
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();
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();
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.
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();
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.
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
//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
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
//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
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
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
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
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.
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
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