Leave a comment

Protected vs Local

Protected is inheritable local

A member identified as local is available only to methods inside the class. Further, these local members

are not visible within subclasses. Of course, nonlocal methods that access local class properties or methods

can be inherited and work properly as methods of the subclass.

A protected class property or method has all of the characteristics of a local member, except that it can

be inherited; it is visible to subclasses.

Leave a comment


disable fork should disable all the forks/processes in the current scope

begin : isolating_thread
for(int index=0;index<14;index++)begin : for_loop

automatic int idx=index;
end : for_loop
wait fork;
end : isolating_thread

The wait fork suspends the parent sequence (or test) until all the child sequences (processes) have completed. There reason you can’t just use fork/join is because of the outer for_loop used to spawn each sequence (process) with a fork statement. If you used a fork/join, then each iteration of the loop would be blocked until the sequence completed, and the fork/join is not really doing anything different than a begin/end.

You are correct. There needs to be a separate idx variable for each invocation of the fork/join_none. I overlooked this since it was not the main point of the original question. I have edited the example.

From <https://verificationacademy.com/forums/systemverilog/fork-within-loop-join-all>

Leave a comment

Interface Classes

  1. Any interface class can only extend one or more interface classes
  2. An interface class shall not implement other interface classes
  3. A non interface class can be declared as implementing one or more interface classes
  4. An interface class can only contain
    1. Pure virtual methods
    2. Type declarations
    3. Parameter declarations
  5. An interface class cannot contain
    1. Covergroups
    2. Constraint blocks
    3. Nested classes
  6. When an interface class is implemented nothing is inherited
  7. Virtual classes that implement interface classes need not implement all the pure virtual methods of the interface class
  8. Following is illegal

class Fifo #(type T = PutImp) implements T;

virtual class Fifo #(type T = PutImp) implements T;

interface class Fifo #(type T = PutImp) extends T;

Leave a comment

Parameterized classes

  1. Static members of a parameterized class are not static across specializations of that class


Class A#(int size = 4)

Typedef A(5) B

Typedef A(6) C

B is a specialization of A

C is a specialization of A

If there is a static variable called my_static in class A, Classes B and C have a separate copy of my_static

If my_static is inteded to be static across classes B and C then it should be declared static in a non-parameterized class and class A should be extended from that class.

  1. What is the syntax when we define functions that belong to a parameterized class outside the class body

class C #(int p = 1, type T = int);

extern static function T f();


function C::T C::f();

return p + C::p;


class C #(int p = 1);

parameter int q = 5; // local parameter

static task t;

int p;

int x = C::p; // C::p disambiguates p

// C::p is not p in the default specialization



int x = C::p; // illegal; C:: is not permitted in this context

int y = C#()::p; // legal; refers to parameter p in the default

// specialization of C

typedef C T; // T is a default specialization, not an alias to

// the name “C”

int z = T::p; // legal; T::p refers to p in the default specialization

int v = C#(3)::p; // legal; parameter p in the specialization of C#(3)

int w = C#()::q; // legal; refers to the local parameter

T obj = new();

int u = obj.q; // legal; refers to the local parameter

bit arr[obj.q]; // illegal: local parameter is not a constant expression

  1. If you have a class definition like this:
    1. Class Env#(type T = int);
    2. Class Env1 extends Env#(bit)
    3. Case 1:
      1. Env#(bit) Envbit;
      2. Envbit = Env#(bit)::type_id::create(“Envbit”, this);
      3. Env1         env1;
      4. Envbit = Env1::type_id::create(“Env1”, this);
      5. Though seemingly the types of Envbit and Env1 are same they are still considered two different class types.
Leave a comment

SOLID software principles

  1. Single responsibility
  2. Open/Closed
    1. Visitor pattern is one way to follow open/closed principle

Moving operations into visitor classes is beneficial when

  • many unrelated operations on an object structure are required,
  • the classes that make up the object structure are known and not expected to change,
  • new operations need to be added frequently,
  • an algorithm involves several classes of the object structure, but it is desired to manage it in one single location,
  • an algorithm needs to work across several independent class hierarchies.

A drawback to this pattern, however, is that it makes extensions to the class hierarchy more difficult, as new classes typically require a new visit method to be added to each visitor.

  1. Open for extension and closed for modification
  2. Creating your own mechanisms outside of what is defined in OVM/UVM to serve the same or similar purpose is a direct violation of this OCP
  3. This principle has been used in two ways:
    1. Meyer’s OCP
    2. Polymorphic OCP – Robert C Martin
    3. Both methods use Inheritance
      1. Inheritance is used for both
        1. Class based programming – Inheritance
        2. Prototype based programming – Delegation
      2. Inheritance should not be confused with subtyping
      3. Inheritance
        1. only re-uses implementation and establishes a syntactic relationship not necessarily a semantic relationship
        2. Also known as implementation inheritance or code inheritance
      4. Sub-typing
        1. establishes a “is-a” relationship
        2. Interface inheritance
      5. Inheritance breaks encapsulation


  1. Liskov substitution
  2. Interface segregation
  3. Dependency Inversion


GRASP – General Responsibility Assignment Software Patterns

  1. Controller
  2. Creator
  3. High Cohesion
  4. Indirection
  5. Information expert
  6. Low coupling
  7. Polymorphism
  8. Protected Variations
  9. Pure fabrication
Leave a comment

Why should you use setters and getters

  1. When you realize you need to do more than just set and get the value, you don’t have to change every file in the codebase.
  2. You can perform validation here.
  3. You can change the value being set.
  4. You can hide the internal representation. getAddress() could actually be getting several fields for you.
  5. You’ve insulated your public interface from changes under the sheets.
  6. Some libraries expect this. Reflection, serialization, mock objects.
  7. Inheriting this class, you can override default functionality.
  8. You can have different access levels for getter and setter.
  9. Lazy loading.
  10. People can easily tell you didn’t use Python.
Leave a comment

Validation Completion Checklist

  1. Validation
    1. Coverage
      1. Functional coverage
        1. Register coverage
          1. Write to every register field is covered for all possible legal values
            1. Waivers reviewed
            2. Note that values used to write might be different from the values read out
          2. Read to every register field is covered with all possible legal values
            1. Waivers reviewed
          3. Todo:
            1. Classify the registers/fields based on the unique conditions to read/write
            2. Coverage plan to include
              1. Condition to read/ when can you read
              2. Condition to write/ when can you write
              3. When can the register coverage be sampled
        2. Interface coverage
          1. Every input and output signal is covered for all possible legal values
            1. Waivers reviewed
          2. Todo
            1. Stimulus must drive X/random values when corresponding valid signals are deasserted
        3. Feature coverage reviewed
          1. Feature coverage is mapped to register/interface coverage coverpoints/crosses
        4. Assertion coverage review
        5. Functional coverage code review
        6. TB Coverage
        7. Test coverage
      2. Code coverage
        1. DUT ports toggle coverage 100%
        2. FSM coverage 100%
          1. Waivers reviewed
    2. Constraints
      1. Reviewed – essentially to account for waivers in coverage and checks – ideally not necessary if a and c items have no waivers.
    3. Checks
      1. Coverage for checks
        1. Every check has coverage
      2. Every hardware variable register has a check
        1. Waivers reviewed
      3. Every output signal has a check
        1. Waivers reviewed
      4. Feature checks reviewed
    4. Regression pass rate 100%
      1. Waivers debugged and disposed
    5. Miscellaneous
      1. Review the list of unconnected register fields
      2. Review the dangles and tie offs of DUT ports
      3. Review the input clock frequencies
      4. Review Sequence hierarchy
      5. Review Scoreboard Architecture
      6. Review TB Architecture
    6. Tests/Sequences for different flows
      1. Minimal programming paradigms for all the different flows
        1. What is the least number of transactions required to setup the DUT to start functioning
      2. Incremental programming paradigms
        1. Add each step of complication/programming in an incremental fashion in the test
      3. This might also require a sequence that will write default values into registers of interest in the middle of the test
Leave a comment

Sudoku in System Verilog

The sudoku bug bit me very late in my life. I solved my first sudoku on a math night in my son’s school. Then again it reared its head in an interview. So here it is:

class sudoku;

parameter ROWS =9;
parameter COLS =9;

//mat is the final sudoku 9X9 matrix
rand int mat[ROWS][COLS];
//trans_mat is the transpose of the final sudoku
rand int trans_mat[COLS][ROWS];
// boxes has 9 rows. Each row has the elements of the 3X3 grid in sudoku
// that have unique numbers
rand int boxes[COLS][ROWS];

constraint sudoku {
//make the numbers in the 3X3 grid unique
unique {boxes[i]};
//Thsi effectively makes the cols in the sudoku unique
foreach( trans_mat[i]) {
unique {trans_mat[i]};
//make the rows in the sudoku unique
foreach( mat[i]) {
unique {mat[i]};
//This is essentially saying that the 3X3 boxes are rows in boxes array
foreach(mat[i,j]) {
boxes[(3*(i/3)) + (j/3)][(3*(i%3))+(j%3)] == mat[i][j];
//Constrain for the numbers to be used in the sudoku
foreach(mat[i,j]) {
mat[i][j] >0;
mat[i][j] <=9;
//Constrain for mat and trans_mat to be transpose of each other
foreach(mat[k,j]) {
mat[k][j] == trans_mat[j][k];

//Display each element of matrix
function string display_elem(int k);

//Display each row matrix
function string display_row(input int row[COLS]);
string disp_string;
disp_string = {disp_string, “\t”, display_elem(row[i])};
return disp_string;

//Display each matrix
function display_mat(ref int mat[ROWS][COLS]);
//Display all matrices for debug
function display_all_mats();

function display_sudoku();

module sudoku_tb();

sudoku sudoku_h;

sudoku_h = new();

Leave a comment

An alternative to generate statement in (system) verilog.

I know this doesn’t directly answer the question, but you can also declare several modules in this formation without using a generate block like so:

status whatever_status[10:0] (

This is equivalent to the generate block above assuming that a, b, and out being passed are declared as [10:0]. This syntax will work as long as they’re integer multiples of how they’re declared in the module; they’ll be spread evenly among each instance, otherwise synthesis will throw an error.

For example if a, b, and out are declared [21:0], then every 2 bits will be passed to each instance, and it is assumed they are declared as [1:0] within the module status.

Leave a comment

How to constrain a 16 bit vector with specific number of 1’s

void'( randomize(vector) with { $countones(vector) == cross_sum } );


bit temp_array[n];
bit [n-1:0] vector;
int cross_sum;
  void'(randomize(temp_array) with { (temp_array.sum(b) with (int'(b)) == cross_sum); } );
  vector = type(vector)'(temp_array);

In the second case the reason we need to cast the sum b to integer is because the sum is a 
reduction operator and the result would be of the same type as the array elements.