模板模式
关键字
泛型, 参数化类, 模板类
问题
class proc_1;
string data;
static int counter;
endclass
class proc_2;
int data;
static int counter;
endclass
proc_1 u_proc_1 = new();
proc_2 u_proc_2 = new();
上述proc_1与proc_2类的代码基本一致,唯一的差异就在data的类型,proc_1的data类型是string,proc_2的data类型是int。
问题
仅仅为了data的类型编写了两个类,这两个类又高度相似,如果data的类型更多,如何处理?比如新增real, shortreal, bit, logic时,又需要增加编写对应的class?
思考
如何简化上述代码?如何能将变化的和不变的区分开来?
措施
参数化类(泛型类):
class proc #(type T=int);
T data;
static int counter;
endclass
typedef proc#(string) proc_1;
typedef proc#(int) proc_2;
proc_1 u_proc_1 = new();
proc_2 u_proc_2 = new();
说明
class proc #(type T=int)中井号(#)来定义泛型类。在引用泛型类时(proc#(string) proc_1),还可以使用井号来提供参数赋值或覆盖的列表。
注意
在class proc中,
proc#(string) ::counter与proc#(int)::counter是两个完全独立的计数器。
静态类属性将在时间0之前分配和初始化。
但是,一旦声明带有参数的泛型类,静态类属性就不再成立。
泛型类在specialization时才会分配和初始化静态属性,每个specialization都有一个唯一的实例及其静态属性的初始化。
应用场景
不同的类型,相同的操作
uvm工厂模式
类注册时为每个类套一个独一无二的wrapper,但个体类千差万别,利用泛型类屏蔽差异性。
UVM TLM
virtual class uvm_port_base #(type IF=uvm_void) extends IF;
typedef uvm_port_base #(IF) this_type;
...
endclass
说明: 在编写类时,若遇到在不同情况下,继承不同基类的的场景,可参考上述UVM源码的编码,将基类参数化(IF),能大幅度减少编码,提高复用性。
class uvm_blocking_put_imp #(type T=int, typeIMP=int) extends uvm_port_base #(uvm_tlm_if_base #(T,T));
`UVM_IMP_COMMON(`UVM_TLM_BLOCKING_PUT_MASK,"uvm_blocking_put_imp",IMP)
`UVM_BLOCKING_PUT_IMP (m_imp, T, t)
endclass
说明:这是一个继承自己模板类的模板类
限制
function int func_1(int data);
return data
endfunction
function string func_2(string data);
return data
endfunction
systemVerilog无法解决上述的问题,不过可以通过泛型类包起来,或者宏等方式解决重用问题。
参考
https://zhuanlan.zhihu.com/p/369969387