SystemVerilog Class Constructor(SystemVerilog类构造函数)

构造函数只是一种用于创建特定类数据类型的新对象的方法。

Constructors

C / C ++需要复杂的内存分配技术,并且不正确的取消分配可能导致内存泄漏和其他行为问题。 SystemVerilog虽然不是编程语言,但能够简单地构造对象并自动进行垃圾回收。

当明确定义类构造函数时

// 使用32位变量定义一个名为“ Packet”的类以存储地址
//在新函数(也称为构造函数)中将“ addr”初始化为32'hfade_cafe
class Packet;
  bit [31:0] addr;
 
  function new ();
    addr = 32'hfade_cafe;
  endfunction
endclass
 
module tb;
 
  // 创建一个名为“ pkt”的类句柄并实例化该类对象
  initial begin
    // 实例化对象时,将调用类的构造函数new()fn
    Packet pkt = new;   
 
    // 显示类变量-由于在实例化期间调用了构造函数,因此该变量的大小应为32'hfade_cafe
    $display ("addr=0x%0h", pkt.addr);
  end
endmodule


Simulation Log
ncsim> run
addr=0xfadecafe
ncsim: *W,RNQUIE: Simulation is complete.

在上面的示例中,变量声明创建了Packet类的对象,并将自动在该类中调用new()函数。 new()函数称为类构造函数,是一种使用一些值初始化类变量的方法。 请注意,它没有返回类型,并且是非阻塞的。

隐式调用类构造函数

如果该类没有显式的new()函数,则将自动提供一个隐式的new方法。 在这种情况下,addr初始化为零,因为它的类型为bit,其默认值为零。

// 用一个名为“ addr”的变量定义一个简单的类
// 请注意,此处未定义new()函数
class Packet;
  bit [31:0] addr;
endclass
 
module tb;
 
    // 当实例化类对象时,该工具将隐式定义构造函数并调用该构造函数。
  initial begin
    Packet pkt = new;   
    $display ("addr=0x%0h", pkt.addr);
  end
endmodule
 
Simulation Log
ncsim> run
addr=0x0
ncsim: *W,RNQUIE: Simulation is complete.

继承类的行为

派生类的new方法将首先使用super.new()调用其父类构造函数。 基类构造函数完成后,派生类中定义的每个属性都将初始化为默认值,然后将执行新方法中的其余代码。

// 定义一个简单的类,并在new()函数中初始化类成员“data”
class baseClass;
  bit [15:0] data;
 
  function new ();
    data = 16'hface;
  endfunction
endclass
 Pass a value as argument to the new function in this case and print
//定义从上述类扩展而来的子类,并增加成员
// 构造函数new()函数接受一个值作为参数,默认为2
class subClass extends baseClass;
  bit [3:0] id;
  bit [2:0] mode = 3;
 
  function new (int val = 2);
    // 子类中的new()函数使用“ super”关键字在基类中调用新函数
    super.new ();
 
    // 将通过参数获得的值分配给类成员
    id = val;
  endfunction
endclass
 
module tb;
  initial begin
    // 为子类创建两个句柄
    subClass  sc1, sc2;
 
    //实例化子类并显示成员变量值
    sc1 = new ();
    $display ("data=0x%0h id=%0d mode=%0d", sc1.data, sc1.id, sc1.mode);
 
    // 在这种情况下,将值作为参数传递给新函数并打印
    sc2 = new (4);
    $display ("data=0x%0h id=%0d mode=%0d", sc2.data, sc2.id, sc2.mode);
  end
endmodule

在上面的示例中,创建subClass对象时,它将首先调用subClass的new()函数。 当通过super关键字调用时,它从那里分支到baseClass的new()方法。 接下来将初始化数据,然后控件返回到子类。 id初始化为4后,将执行新方法。

Simulation Log
ncsim> run
data=0xface id=2 mode=3
data=0xface id=4 mode=3
ncsim: *W,RNQUIE: Simulation is complete.

新函数声明为静态或虚拟(new function is declared as static or virtual)

class ABC;
  string fruit;
 
  // 请注意,构造函数被定义为“virtual”,这是不允许的
  // 在SystemVerilog中。类构造函数也不能是“静态(static)”的
  virtual function new ();
    fruit = "Apple";
  endfunction
 
endclass
 
//实例化类对象并打印其内容
module tb;
    initial begin
      ABC abc = new();
      $display ("fruit = %s", abc.fruit);
    end
endmodule

 virtual function new ();
                     |
ncvlog: *E,BADQAL (testbench.sv,6|21): Lifetime or qualifier(s) 'virtual' not allowed before function new declaration.

类型化构造函数(Typed constructors)

此处的区别在于,您可以调用子类的new()函数,但可以在单个语句中将其分配给基类的句柄。 这是通过使用范围运算符::引用子类的new()函数来完成的,如下所示。

class C; 
endclass

class D extends C;
endclass

module tb;
   initial begin
      C c = D::new;
   end
endmodule

基类C的变量c引用了一个新构造的类型D的对象。这实现了与下面给出的代码相同的效果。

module tb;
	initial begin
		D d = new;
		C c = d;
	end
endmodule

参考文献:
【1】https://www.chipverify.com/systemverilog/systemverilog-class-constructor

发布了124 篇原创文章 · 获赞 8 · 访问量 6706

猜你喜欢

转载自blog.csdn.net/qq_43042339/article/details/104482002