SystemVerilog
Language Guidelines
1.1 Rule: Check
that $cast() has succeeded
|
If you are going to
use the result of the cast operation, then you should check the status returned
by the $cast call and deal with it gracefully, otherwise the simulation may crash
with a null pointer.
Note that it is not
enough to check the result of the cast method, you should also check that the
handle to which the cast is made is not null. A cast operation will succeed if
the handle from which the cast is being done is null.
// How to check that a $cast has worked correctly
function my_object get_a_clone(uvm_object to_be_cloned);
my_object t;
if(!$cast(t, to_be_cloned.clone()) begin
`uvm_error("get_a_clone", "$cast failed for to_be_cloned")
end
if(t == null) begin
`uvm_fatal("get_a_clone", "$cast operation resulted in a null handle, check to_be_cloned handle")
end
return t;
endfunction: get_a_clone
|
1.2 Rule: Check
that randomize() has succeeded
|
If no check is made
the randomization may be failing, meaning that the stimulus generation is not
working correctly.
// Using if() to check randomization result
if(!seq_item.randomize() with {address inside {[o:32'hF000_FC00]};}) begin
`uvm_error("seq_name", "randomization failure, please check constraints")
end
|
1.3 Rule: Use
if rather than assert to check the status of method calls
|
Assert results in the
code check appearing in the coverage database, which is undesired. Incorrectly
turning off the action blocks of assertions may also produce undesired results.
Constructs to be Avoided
The SystemVerilog
language has been a collaborative effort with a long history of constructs borrowed from other languages. Some constructs
have been improved upon with newer constructs, but the old constructs remain
for backward compatibility and should be avoided. Other constructs were added
before being proven out and in practice cause more problems than they solve.
1.4 Rule: Do
not place any code in $unit, place it in a package
|
The compilation unit,
$unit, is the scope outside of a design element (package, module, interface,
program). There are a number of problems with timescales, visibility, and
re-usability when you place code in $unit. Always place this code in a package.
1.5 Guideline: Do
not use associative arrays with a wildcard index[*]
|
A wildcard index on an
associative array is an un-sized integral index. SystemVerilog places severe
restrictions on other constructs that cannot be used with associative arrays
having a wildcard index. In most cases, an index type of [int] is sufficient.
For example, a foreach loop requires a fixed type to declare its iterator
variable.
string names[*]; // cannot be used with foreach, find_index, ...
string names[int];
...
foreach (names[i])
$display("element %0d: %s",i,names[i]);
|
1.6 Guideline: Do
not use #0 procedural delays
|
Using a #0 procedural
delay, sometimes called a delta delay, is a sure sign that you have coded
incorrectly. Adding a #0 just to get your code working usually avoids one race
condition and creates another one later.Often, using a non-blocking assignment
( <= ) solves this class of problem.
Coding Patterns
Some pieces of code
fall into well recognized patterns that are know to cause problems
1.7 Rule: Do
not rely on static variable initialization order, initialize on first
instance.
|
The ordering of static
variable initialization is undefined. If one static variable initialization
requires the non-default initialized value of another static variable, this is
a race condition. This can be avoided by creating a static function that
initializes the variable on the first reference, then returns the value of the
static variable, instead of directly referencing the variable.
typedef class A;
typedef class B;
A a_top=A::get_a();
B b_top=B::get_b();
class A;
static function A get_a();
if (a_top == null) a_top =new();
return a_h;
endfunction
endclass : A
class B;
A a_h;
protected function new;
a_h = get_a();
endfunction
static function B get_b();
if (b_top == null) b_top =new();
return b_top;
endfunction
endclass : B
|
Covergroups
1.8 Guideline: Create
covergroups within wrapper classes
|
Covergroups have to be
constructed within the constructor of a class. In order to make the inclusion
of a covergroup within a testbench conditional, it should be wrapped within a
wrapper class.
1.9 Guideline: Covergroup
sampling should be conditional
|
Build your covergroups
so that their sample can be turned on or off. For example use the 'iff' clause
of covergroups.
// Wrapped covergroup with sample control:
class cg_wrapper extends uvm_component;
logic[31:0] address;
bit coverage_enabled
covergroup detail_group;
ADDRESS: coverpoint addr iff(coverage_enabled) {
bins low_range = {[0:32'h0000_FFFF]};
bins med_range = {[32'h0001_0000:32'h0200_FFFF]};
bins high_range = {[32'h0201_0000:32'h0220_FFFF]};
}
// ....
endgroup: detail_group
function new(string name = "cg_wrapper", uvm_component parent = null);
super.new(name, parent);
// Construct covergroup and enable sampling
detail_group = new();
coverage_enabled = 1;
endfunction
// Set coverage enable bit - allowing coverage to be enabled/disabled
function void set_coverage_enabled(bit enable);
coverage_enabled = enable;
endfunction: set_coverage_enabled
// Get current state of coverage enabled bit
function bit get_coverage_enabled();
return coverage_enabled;
endfunction: get_coverage_enabled
// Sample the coverage group:
function void sample(logic[31:0] new_address);
address = new_address;
detail_group.sample();
endfunction: sample
|
Coverpoint sampling
may not be valid in certain situations, for instance during reset.
// Using iff to turn off unnecessary sampling:
// Only sample if reset is not active
coverpoint data iff(reset_n != 0) {
// Only interested in high_end values if high pass is enabled:
bins high_end = {[10000:20000]} iff(high_pass);
bins low_end = {[1:300]};
}
|
Collecting Coverage
1.10 Guideline: Use
the covergroup sample() method to collect coverage
|
Sample a covergroup by
calling the sample routine, this allows precise control on when the sampling
takes place.
1.11 Rule: Label
coverpoints and crosses
|
Labelling coverpoints
allows them to be referenced in crosses and easily identified in reports and
viewers.
payload_size_cvpt: coverpoint ...
|
Labelling crosses
allows them to be easily identified
payload_size_X_parity: cross payload_size_cvpt, parity;
|
1.12 Guideline: Name
your bins
|
Name your bins, do not
rely on auto-naming.
1.13 Guideline: Minimize
the size of the sample
|
It is very easy to
specify large numbers of bins in covergroups through autogeneration without
realising it. You can minimise the impact of a covergroup on simulation
performance by thinking carefully about the number and size of the bins
required, and by reducing the cross bins to only those required.