面向对象编程的高级技巧指南 | Systemverilog 笔记 7

Posted by Kion on January 22, 2020
为什么需要继承?

在面对一系列的设计时,有的类的功能需求是相近的,如果重写,加入一些新的属性方法,显然会增加工作量。因此使用继承就能够很好地发挥原本类的作用,同时拓展其功能。

如何继承类?

首先需要一个基类,然后定义派生类。

/*基类*/
class Transaction;
    rand bit[31:0] src,dst,data[8];
    bit[31:0] crc;
    
    virtual function void calc_crc;
        crc = src^dst^data.xor;
    endfunction
    /*定义虚拟方法,方便派生类扩展*/
    virtual function void display(input string prefix="");
        $display("%sTr:src=%h,dst=%h,crc=%h",prefix,src,dst,crc);
    endfunction
endclass
/*派生类*/
class BadTr extends Transaction;
    rand bit bad_crc;
    
    virtual function void calc_crc;
        /*调用基类方法*/
        super.calc_crc();
        if (bad_crc) crc=~crc;
    endfunction
    
    virtual function void display(input string prefix="");
        $write("%sBadTr:bad_crc=%b,",prefix,bad_crc);
        super.display();
    endfunction
endclass:BadTr
为什么需要蓝图模式?

可以方便地改变发生器创建的类型对象,扩展类的属性和方法,而又不需要修改发生器代码。原本情况下,立即构建并随机化对象后,后续想扩展类的属性和方法会非常困难。使用蓝图模式,相当于额外拷贝了一份对象,在这个对象上修改合适后,才将其传送出去。

/*这个旧发生器的问题在于,无法把new与randomize分开,导致扩展性及重用性很差*/
class Bad_Generator;
  AXI_TR tx;              
  task run();
    repeat(5) begin
      tx = new();         
      if (!tx.randomize()) $fatal(...);
      $display("%p", tx); 
    end
  endtask
endclass
/*使用蓝图模式,把一份拷贝放在发生器的new函数内,后面每次随机化tr前,复制一份拷贝,提高了扩展性。使用时,在test类中,为bluepoint赋上扩展类的对象,即可达到扩展的目的*/
class Generator;
  AXI_TR blueprint, tx;
 
  function new();
    blueprint = new();        
  endfunction
 
  task run();
    repeat(5) begin
      tx = blueprint.clone(); 
      if (!tx.randomize()) $fatal(1, "randomize() failed");
      $display("%p", tx);     
    end
  endtask
endclass

参考

基类与派生类间的转换

使用$cast可以将派生类指针转换成指向基类的指针;基类句柄可以直接被赋予派生类句柄;如果类的方法没有使用virtual修饰符,SystemVerilog会根据句柄类型,而不是对象类型调用方法。

为什么需要回调?

当想要在一个测试中注入新的错误时,往往需要给原始类加入新的代码。使用回调,则可以为原始类增加一个扩展类,而免去修改原始类。原始类中,回调方法一般没有内容,而在扩展类中在回调方法内编写新的代码,达到扩展功能的目的。所以回调其实就是预留了修改的位置。

参考

为什么需要参数化的类?

参数化的类可以定义一个类来处理多种数据类型。

class generator #(type T=BadTr);/*用T代替数据类型,默认BadTr类*/
    T blueprint;
    ...
endclass

program automatic test;
    initial begin
        generator #(transaction) gen;
        ...
    end
endprogram