Sunday, 28 January 2018

Automatic/Static Variables and Function/Task with Automatic Lifetime in SystemVerilog

Before going into static and automatic variable let’s first go through 2 important terminology and then will go through automatic and static.

Scope:
Scope is the region or section of code where a variable can be accessed.
Variables declared inside a module, interface, program, or checker, but outside a task, process, or function, are local in scope.

Lifetime:
Lifetime is the time duration where an object/variable is in a valid state.
Variables declared outside a module, program, interface, checker, task, or function are local to the
compilation unit and have a static lifetime (exist for the whole simulation).
Variables declared inside a static task, function, or block are local in scope and default to a static lifetime.

Specific variables within a static task, function, or block can be explicitly declared as automatic. Such
variables have the lifetime of the call or block and are initialized on each entry to the call or block.
---------------------------------------------------------------------
module top();
// static int loop5;
int loop5; // same as above line, static keyword optional
// automatic int loop4; // illegal : All variables in module scope must have a static lifetime
// Automatic variable inside static function/task
function void print1();
automatic int loop1;
//loop1 = 0; // executes on every call of print1
for (int j=0; j<3; j++) begin
loop1 = loop1 + 1;
$write("%0d ", loop1);
end
$write("\t");
endfunction : print1
// Automatic variable inside block
function void print2();
for (int i=0; i<3; i++) begin
automatic int loop1 = 0; // executes on every iteration of i loop
for (int j=0; j<3; j++) begin
loop1 = loop1 + 1;
$write("%0d ", loop1);
end
$write("\t");
end
endfunction : print2
// Static variable inside static function/task
function void print3();
// static int loop2;
int loop2; // same as above line, static keyword optional
// loop2 = 0; // executes once before time 0
for (int j=0; j<3; j++) begin
loop2 = loop2 + 1;
$write("%0d ", loop2);
end
$write("\t");
endfunction : print3
// Static variable inside block
function void print4();
for (int i=0; i<3; i++) begin
int loop2 = 0; // executes once before time 0
for (int j=0; j<3; j++) begin
loop2 = loop2 + 1;
$write("%0d ", loop2);
end
$write("\t");
end
endfunction : print4
// Static variable inside module
function void print5();
for (int i=0; i<3; i++) begin
// loop5 = 0; // executes once before time 0
for (int j=0; j<3; j++) begin
loop5 = loop5 + 1;
$write("%0d ", loop5);
end
$write("\t");
end
endfunction : print5
initial begin
$display ("Automatic variable inside static function/task");
for (int i=0; i<3; i++) begin
print1();
end
$display();
$display ("Automatic variable inside block");
print2();
$display();
$display();
$display ("Static variable inside static function/task");
for (int i=0; i<3; i++) begin
print3();
end
$display();
$display ("Static variable inside block");
print4();
$display();
$display ("Static variable inside module");
print5();
$display();
end
endmodule : top
---------------------------------------------------------------------
Result:
---------------------------------------------------------------------
//Output:
// Automatic variable inside static function/task
// 1 2 3 1 2 3 1 2 3
// Automatic variable inside block
// 1 2 3 1 2 3 1 2 3
//
// Static variable inside static function/task
// 1 2 3 4 5 6 7 8 9
// Static variable inside block
// 1 2 3 4 5 6 7 8 9
// Static variable inside module
// 1 2 3 4 5 6 7 8 9
---------------------------------------------------------------------


Automatic Function/Task (Function/Task with Automatic Lifetime):
In Verilog default lifetime of all the task/function is static.
Tasks and functions may be declared as automatic. Variables declared in an automatic task, function, or block are local in scope, default to the lifetime of the call or block, and are initialized on each entry to the call or block.

In other word, Automatic task/function variables cannot be accessed by hierarchical references. Automatic variables are automatically destroyed once the scope (task, function, block) in which they are created ends and regenerated when again enters into scope (task, function, block).
---------------------------------------------------------------------
module top();
// Function with Static Lifetime
// By default lifetime of function/task is Static in Verilog/SV
function void print_s();
int a;
a = a + 1;
$write("%0d ", a);
endfunction : print_s
// Function with Automatic Lifetime
function automatic void print_a();
int a;
a = a + 1;
$write("%0d ", a);
endfunction : print_a
initial begin
$display("Static variable");
for (int i=0; i<4; i++) begin
print_s();
end
$display("\n");
$display("Automatic variable");
for (int i=0; i<4; i++) begin
print_a();
end
$display();
end
endmodule : top
//Output:
// Static variable
// 1 2 3 4
//
// Automatic variable
// 1 1 1 1
---------------------------------------------------------------------


Class methods has Automatic lifetime by default:
Because of backward compatibility reason, SystemVerilog could not change the default lifetime qualifier to ‘automatic’ but since class methods were new, it changed the lifetime of all methods to be automatic.
---------------------------------------------------------------------
class my_class;
// Function with Automatic Lifetime
// By default lifetime of function/task is Automatic in Class
function void print_a();
int a;
a = a + 1;
$write("%0d ", a);
endfunction : print_a
// Function with Static Lifetime
function static void print_s();
int a;
a = a + 1;
$write("%0d ", a);
endfunction : print_s
endclass : my_class
module top();
my_class c;
initial begin
c = new();
$display("Automatic variable");
for (int i=0; i<4; i++) begin
c.print_a();
end
$display("\n");
$display("Static variable");
for (int i=0; i<4; i++) begin
c.print_s();
end
$display();
end
endmodule : top
//Output:
// Automatic variable
// 1 1 1 1
//
// Static variable
// 1 2 3 4
---------------------------------------------------------------------


The keyword ‘static’ is overloaded. There is a semantic difference between the meaning of ‘static’ used to the left of a function/task keyword and ‘static’ used to the right of the function/task keyword.

When used to the left of the function or task, ‘static’ is a class qualifier and has the same as on any static method in C++/Java. It is a method of the class type, not of an instance of a class object. Other class qualifiers are ‘local’ and ‘protected’ and along with ‘static’ are only allowed in front of methods of a class. There is no corresponding ‘automatic’ class qualifier.

When used to the right of a function or task, ‘static’ is a lifetime qualifier, with ‘automatic’ being the corresponding qualifier.

For more details refer this link.

Friday, 26 January 2018

`define macro usage in SystemVerilog

It's not possible to use a `define macro within a string literal. According to the SystemVerilog LRM: Macro substitution and argument substitution shall not occur within string literals
Let’s go through below example to understand it in detail,
 ---------------------------------------------------------------------------
module top();
`define HI Hello
`define LO "`HI, world"
`define H(x) "Hello, x"
initial begin
$display("`HI, world");
$display(`LO);
$display(`H(world));
end
endmodule : top
//Output:
// `HI, world
// `HI, world
// Hello, x
 ---------------------------------------------------------------------------

However a string literal can be constructed by using a macro that takes an argument and including the quotes in the macro by using `".
According to SystemVerilog LRM: An `" overrides the usual lexical meaning of " and indicates that the expansion shall include the quotation mark, substitution of actual arguments, and expansions of embedded macros. This allows string literals to be constructed from macro arguments.
 ---------------------------------------------------------------------------
module top();
`define HI Hello
// macro substitution
`define LO `"`HI, world`"
// argument substitution
`define H(x) `"Hello, x`"
initial begin
$display(`LO);
$display(`H(world));
end
endmodule : top
//Output:
// Hello, world
// Hello, world
 ---------------------------------------------------------------------------

Now what if you want to add double quotes in string which is constructed using macro. SystemVerilog provides support for that.
A `\`" indicates that the expansion should include the escape sequence \".
Let’s go through example to see how it works,
 ---------------------------------------------------------------------------
module top();
`define msg(x,y) `"x: `\`"y`\`"`"
initial begin
$display(`msg(left side,right side));
// expands to
// $display("left side: \"right side\"");
end
endmodule : top
//Output:
// left side: "right side"
 ---------------------------------------------------------------------------

 SystemVerilog LRM also provides support to construct identifier from arguments using ``.
There are three places where we can substitute argument to construct identifier
1) Substitute argument in between something (neither at the end nor at the beginning of the identifier)
2) Prepend argument (at the beginning of the identifier)
2) Append argument (at the end of the identifier)
 ---------------------------------------------------------------------------
module top();
int unsigned pkt_tx_cnt;
int unsigned pkt_rx_cnt;
bit clock_master;
bit reset_master;
int unsigned count_a;
int unsigned count_b;
`define increment(dir) \
pkt_``dir``_cnt = pkt_``dir``_cnt + 1;
`define set(sig, value) \
sig``_master = value;
`define update_count(sel, value) \
count_``sel = value;
initial begin
$display("pkt_tx_cnt:%0d, pkt_rx_cnt:%0d", pkt_tx_cnt, pkt_rx_cnt);
$display("clock_master:%b, reset_master:%b", clock_master, reset_master);
$display("count_a:%0d, count_b:%0d", count_a, count_b);
$display();
`increment(tx)
`set(clock, 1)
`update_count(a, 5)
$display("pkt_tx_cnt:%0d, pkt_rx_cnt:%0d", pkt_tx_cnt, pkt_rx_cnt);
$display("clock_master:%b, reset_master:%b", clock_master, reset_master);
$display("count_a:%0d, count_b:%0d", count_a, count_b);
$display();
`increment(rx)
`set(reset, 1)
`update_count(b, 7)
$display("pkt_tx_cnt:%0d, pkt_rx_cnt:%0d", pkt_tx_cnt, pkt_rx_cnt);
$display("clock_master:%b, reset_master:%b", clock_master, reset_master);
$display("count_a:%0d, count_b:%0d", count_a, count_b);
end
endmodule : top
//Output:
// pkt_tx_cnt:0, pkt_rx_cnt:0
// clock_master:0, reset_master:0
// count_a:0, count_b:0
// pkt_tx_cnt:1, pkt_rx_cnt:0
// clock_master:1, reset_master:0
// count_a:5, count_b:0
// pkt_tx_cnt:1, pkt_rx_cnt:1
// clock_master:1, reset_master:1
// count_a:5, count_b:7
 ---------------------------------------------------------------------------

Reference:
1) SystemVerilog 2012 LRM

Weighted Distributions in SystemVerilog

In constrain random verification, it may take a long time for a particular corner case to be generated. Sometime even after running test-case for N number of time corner case may not be generated and you may see holes in functional coverage. To resolve this you can use a weighted distribution to drive stimulus in particular direction.

The dist keyword in systemverilog allows you to create weighted distributions so that some values are chosen more often than others. There are 2 different kind of distribution operators available in systemverilog.
The := operator assigns the specified weight to the item or, if the item is a range, to every value in the range. 
The :/ operator assigns the specified weight to the item or, if the item is a range, to the range as a whole. If there are n values in the range, the weight of each value is range_weight / n.

Limitation:
dist expressions cannot appear in other expressions.
dist operation shall not be applied to randc variables.

Let's go through below example to understand how it works,
----------------------------------------------------------------------------
class my_class;
rand bit [1:0] a;
rand bit [1:0] b;
constraint dist_a_cn {
a dist {0 := 40,
[1:3] := 60};
// a = 0, weight = 40/(40+60+60+60) = 40/220
// a = 1, weight = 60/220
// a = 2, weight = 60/220
// a = 3, weight = 60/220
}
constraint dist_b_cn {
b dist {0 :/ 40,
[1:3] :/ 60};
// b = 0, weight = 40/(40+60) = 40/100
// b = 1, weight = (60/3)/100 = 20/100
// b = 2, weight = (60/3)/100 = 20/100
// b = 3, weight = (60/3)/100 = 20/100
}
endclass : my_class
module top();
`define ITR 15000
my_class dist_c;
bit [1:0] a[`ITR];
bit [1:0] b[`ITR];
bit [1:0] temp_q[$];
initial begin
dist_c = new();
for (int i=0; i<`ITR ; i++) begin
if (!dist_c.randomize()) begin
$error("Randomization failed");
end
a[i] = dist_c.a;
b[i] = dist_c.b;
end
for(int i=0; i<4; i++) begin
temp_q = a.find with (item == i);
$display("for array a : number of elements with %0d : %0d, dist : %f",
i, temp_q.size(), (real'(temp_q.size())*220)/`ITR );
end
$display();
for(int i=0; i<4; i++) begin
temp_q = b.find with (item == i);
$display("for array b : number of elements with %0d : %0d, dist : %f",
i, temp_q.size(), (real'(temp_q.size())*100)/`ITR );
end
end
endmodule : top
//Output:
// for array a : number of elements with 0 : 2725, dist : 39.966667
// for array a : number of elements with 1 : 4069, dist : 59.678667
// for array a : number of elements with 2 : 4094, dist : 60.045333
// for array a : number of elements with 3 : 4112, dist : 60.309333
// for array b : number of elements with 0 : 6024, dist : 40.160000
// for array b : number of elements with 1 : 2935, dist : 19.566667
// for array b : number of elements with 2 : 3079, dist : 20.526667
// for array b : number of elements with 3 : 2962, dist : 19.746667
----------------------------------------------------------------------------

Reference:
1) SystemVerilog LRM 2012
2) SystemVerilog for Verification 3rd edition by Chris Spear