Thought Leadership

SystemVerilog: Class Member Visibility

Introduction

Farmer Ted wants to keep track of the animals on his property and asks you to write the code. Since you have access to Questa SIM, you decide to write the code in SystemVerilog. Start by creating a class for an Animal with a property (variable) to hold its weight. Here is a first start with your class and the first animal.

module farm;
class Animal;
  int weight; // In kg
endclass

  Animal dolly; // handle to an Animal object
  initial begin
    dolly = new();
    dolly.weight = 100;
    $display("dolly weighs %0d", dolly.weight);
  end
endmodule

A problem with this code is the units: is weight in pounds, kilograms, ounces, or grams? Yes, there is a comment, but who reads the documentation? By allowing the user to read and write the variable, you are exposing the implementation. If you ever decide to change the units from kilograms to grams, the above code will make a 100-gram animal. That’s a mighty small sheep!

Public Access

With most OOP languages, you are encouraged to limit direct access to class members, especially properties (variables), to prevent this sort of bug. The recommendation is to create set() and get() methods. In SystemVerilog, the default access is public, which means that other code can read and write properties and call all methods (routines). There is no keyword for this behavior.

Use Protection

When you want to limit access to members, there are three “trust” levels. The base class can always access to members that it defines.  An extended class is like family: you trust this child code, but you may want to limit access to the most sensitive information about the parent (base) class. Finally is code in unrelated classes, where you don’t want anyone to change the weight and possibly make an illegal value.

The first level of limiting access is to declare a member as protected. In the code below, since you are restricting who can see the weight property, you need to make public methods to read and write it. The derived class, Sheep, can access weight, but the farm module cannot.

The most restrictive level is local. The Animal class has a unique id value for every object and does not let anyone, not even the derived Sheep class, access this.

module farm;

class Animal;
  protected int weight; // In kg
  virtual function int get_weight_kg();
    return weight;
  endfunction

  virtual function void set_weight_kg(input int w);
    weight = w;
  endfunction

  local static int count=0;
  local int id;
  function new();
    id = count++;
  endfunction
endclass : Animal

class Sheep extends Animal;
  function new(input int w_kg);
    weight = w_kg; // Legal: derived class can access protected
  endfunction
endclass

  Sheep dolly;
  initial begin
    dolly = new(100);
    $display("dolly weighs %0d", dolly.weight);
  end
endmodule : farm

Experiment with visibility

Try the above code on your favorite simulator. In the farm module, can you set weight with the set*() method? Can you set the weight directly with the c handle? In the Sheep class, can you read or write the id? Create set_weight_gram() and get_weight_gram() methods in Animal.

Conclusion

Much of your code will be for testbenches: the components and stimulus. If you protect too many members, it will be hard to inject errors or randomize properties. However, if you are creating utilities or base classes (such as UVM), you might want to limit access to some of the internals to protect yourself against devious users.

Best Practices

There are several problems with the above examples. What if your 100kg sheep goes on a diet and loses 400kg? The weight is an int, which can be negative, which is not realistic. Physical values, such as weight or packet size, should be treated as unsigned values. Have checks in any set*() methods for these illegal values. Also, since weight represents a continuous value, it should be a real number. Finally, the best way to organize classes is to define them in a package and import it.

Learn More

You can learn more about these topics including Oriented Programming with Siemens SystemVerilog for Verification course. It is offered in instructor led format by our industry expert instructors, or in a self-paced on-demand format. It can also be tailored to address your specific design goals and show you how to set up an environment for reuse for additional designs.  Also, you can now earn a digital badge/level 1 certificate by taking our Advanced Topics Badging Exam. This will enable you to showcase your knowledge of this topic by displaying the badge in your social media and email signature.

Chris Spear

Chris brings over forty years of EDA expertise to Siemens customers. Holding a degree in electrical engineering from Cornell University, Chris has developed deep roots in the EDA industry, including as a Principal Application Consultant. Chris is also an industry author, writing the 2012 best-selling “SystemVerilog for Verification” and developing the IEEE standard for random seeding and File I/O PLI package that is part of SystemVerilog. Having taught thousands of engineers around the world, Chris is driven by a passion for learning new techniques and then helping others learn best practices for hardware verification. Outside of work, you may see Chris bicycling over 12,000-foot mountain passes.

More from this author

Leave a Reply

This article first appeared on the Siemens Digital Industries Software blog at https://blogs.stage.sw.siemens.com/verificationhorizons/2022/08/29/systemverilog-class-member-visibility/