TyL
TyL

Reputation: 84

How to mimic static constructor in SystemVerilog?

I have a parent class and a lot of child classes. And I want to instantiate all the child classes and cast them into a parent object array/queue so I can do something useful things using the parent array/queue.

The code is below:

class parent;
endclass

class child1 extends parent;
endclass

class child2 extends parent;
endclass

program top;

    child1  c1;
    child2  c2;
    parent p, p_arr[$];

    initial
    begin
      c1 = new;
      assert ($cast(p,c1)) else $fatal;
      p_arr.push_back(p);
      c2 = new;
      assert ($cast(p,c2)) else $fatal;
      p_arr.push_back(p);

      // Doing useful things with p_arr
      // .......
    end
endprogram

I wonder if there is a way make this more tidy. So I change my code into this:

    begin
      assert ($cast(p,child1::new())) else $fatal;   <---- QuestaSim compiler complained about "child1::new"
      p_arr.push_back(p);

      assert ($cast(p,child2.new())) else $fatal; <---- QuestaSim compiler complained about "child2.new"
      p_arr.push_back(p);
    end    

But the compiler complains about directly using static constructor "child1::new()" or "child1.new()". Does SystemVerilog support such a feature? (If it is a simulator incapability, can you state what simulator support it?) If not, is there is tidy way to do it? For example using macro?

The problem with macro is that I have to use two macros to do it. One macro declares the instance at the top of the function/program first:

child1  c1; 

And then another macro initializes the instance and put itinto array in the body of the function/program:

c1 = new;
assert ($cast(p,c1)) else $fatal;
p_arr.push_back(p);

Is there a way to use one macro to do this instead of two macro?

---------------------EDIT------------------------

Thank @Tudor and @dave_59 for the answer, the example worked for p = child1::new(). I realized my parent class is a parameterized class. And syntax work for them as well.

 p = child1_class #(.WIDTH(WIDTH))::new();   
 p_arr.push_back(p);
 p = child2_class #(.WIDTH(WIDTH))::new();
 p_arr.push_back(p);

Unfortunately for a new constructor, I have to explicitly specified what object the new is assigned to. And the following syntax does not work.

p_arr.push_back(child1::new());

Upvotes: 2

Views: 326

Answers (2)

dave_59
dave_59

Reputation: 42623

The SystemVerilog BNF requires that new() appear on the RHS of an assignment. But there's no need to use $cast when making an assignment from an extended class to a base class variable. So you can do:

module top;
    parent p, p_arr[$];
    initial
      begin
     p = child1::new();
     p_arr.push_back(p);
     p = child2::new();
     p_arr.push_back(p);

     // Doing useful things with p_arr
     // .......
    end
endmodule

You can also do things like

     p_arr = '{3{null}};
     p_arr[0] = child1::new();
     p_arr[1] = child2::new();
     p_arr[2] = child1::new();

Upvotes: 2

Tudor Timi
Tudor Timi

Reputation: 7573

The syntax described in the LRM for scoped constructor calls is:

child1::new();

If you're lucky, your simulator supports it.

What you don't need in your code, though, are the $cast(...) statements. Since you're down-casting (going from sub-class to parent class), the following would also be legal:

p = child1::new();

If you're even luckier, you can even shorten it to:

p_arr.push_back(child1::new());

but again, this depends on what your simulator supports.

Upvotes: 2

Related Questions