Thursday 16 August 2012

SystemVerilog Language Guidelines


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.
bin minimum_val = {min};
 

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.

No comments:

Post a Comment