-
SV的function与task
- 联系
- 参数列表均可以声明多个input、output、inout、ref。其中,input是从外部复制传入的形式参数;output是由被调用的方法产生复制传递给外部的形式参数;inout表示进入方法和退出方法分别复制;ref则类似指针。
- inout和ref都可以使形式参数在方法中被调用,区别在于inout在方法结束时传到外部;ref在方法执行时直接修改参数并且作用于可以调用该参数的所有地方,无需等到方法执行结束。
- 区别:
- task无法用return返回,只能用output、inout、ref。
- task可以内置耗时语句,function不可。常见的耗时语句:@event,#delay,wait(条件)。
- task可以调function,反过来不行
- 联系
-
automatic与static
- 前者在其作用域声明周期结束时候被销毁回收存储空间,static在仿真任何时刻都可以被共享,不会被销毁直到仿真结束。
- automatic方法中的变量默认也是automatic,随automatic方法生命周期建立和销毁。static方法中变量默认是static。但是也可以显示声明方法中的参数为不同于方法的属性。
- 在module、program、interface、task、function之外声明的变量有静态生命周期,存在于整个仿真阶段。
- 在module、program、interface内部,task、function外部声明的变量也是静态变量,作用于该module、program、interface。存在于整个仿真阶段。
- 在module、program、interface中定义的task、function默认静态,为了让task、function,以及在其中声明的变量有统一的生命周期,可以在定义module、program、interface时定 automatic、static(默认是static)。在task、function定义的变量作用域位于本task、function内。
- 若忘了声明某个变量,SV会到更高层的作用范围去寻找,直到找到匹配的变量声明。若两部分代码无意间共享使用了同名的变量,这一问题往往难以发现。原因在于忘了在最内层进行声明,从而限定作用域。全局变量声明和使用一定要谨慎。
-
在SV中析构函数被弱化,只看到new()来创建trans,每一个trans被创建、使用完毕之后自动被析构掉,因为他不是验证结构的一部分。
-
仿真的结构必须是从0时刻开始就有,伴随到仿真结束。比如Generator class、Driver class等。SV用类来构建验证结构。
-
在验证工作中经常使用"virtual"关键字,下面列举该关键字应用场景。
主要应用场景在virtual class,virtual interface 以及 virtual task/function。
OOP三大特性(封装,继承,多态)中的 多态 在SystemVerilog中一般通过 “virtual” 关键字实现。
通过virtual声明的类,接口,任务与函数,其本身自带一些方法或者函数。后续的例化或者扩展可以对原有的内容进行增加或者修改,从而实现同一函数不同方法的多种形态。- virtual interface
在interface定义时,如果不使用关键字 “virtual” 那么在多次调用该接口时,在其中的一个实例中对接口中某一信号的修改会影响其他实例接口;如果使用了 “virtual” 关键字,那么每个实例是独立的。
习惯上在声明类的interface时均添加 "virtual"关键字。 - virtual task/function
用于OOP思想的继承使用。当定义了virtual时,在子类中调用某task/function时,会先查找在子类中是否定义了该 task/function,如果子类没有定义,则在父类中查找。未定义virtual时,只在子类中查找,没有定义就是编译器报错。
如果某一class会被继承,则用户定义的task/function(除new(),randomized(),per_randomize(),pose_randomize()外),都应该加上virtual关键字,以备后续扩展。 - virtual class
抽象类一般用来定义类的格式、类的成员、类的参数等。抽象类不能被实例化,只能被扩展(重载)后实例化,用于在项目中定义一些标准的类。
抽象类中的方法通常使用关键字 " pure virtual " 纯虚方法。同时OOP规定,只要class中存在一个没有被实现的pure function,就不允许例化这个class。
- virtual interface
virtual class (抽象类):可以被扩展但是不能被直接例化,由抽象类扩展而来的类,只有在所以的虚拟方法都有实体的时候才能被例化。
pure virtual function(纯虚方法):没有实体的方法原型,相当于一个声明,只能在抽象类中定义。
- this的使用方法:
当使用一个变量名的时候,systemverilog将先在当前作用域内寻找,接着在上一级作用域内寻找,直到找到该变量为止。
function DriverBase::new(string name, virtual router_io.TB rtr_io); //接口均添加 "virtual"关键字
//TRACE_ON是一个 test program 的全局变量,可方便debug时控制打印信息
if (TRACE_ON) $display("[TRACE]%t %s:%m", $realtime, name);
this.name = name; //DriverBase类的 name = string name (子类 new 传来的)
this.rtr_io = rtr_io;
endfunction
- 防止class被多次编译
`ifndef INC_PACKET_SV
`define INC_PACKET_SV
......
`endif
- SV中复制现存对象给新对象:
Packet pkt = new this.pkt2send;
//1. new 创建新对象
//2. 拷贝 this 所指的对象给新对象,也就是调用gen() 方法所产生的随机化的对象给新对象
//3. 将 Packet pkt 句柄指向该新对象
- 在class外部写函数体的方法:
class Packet;
.......
extern function new(string name = "Packet");
endclass: Packet
function Packet::new(string name);
//Lab 4 - Task 5, Step 2
//
//Inside new() assign class property name with string passed via argument
//ToDo
this.name = name;
endfunction: new
- 全局变量是在所有函数体的外部定义的,程序的所在部分(甚至其它文件中的代码)都可以使用。全局变量不受作用域的影响(也就是说,全局变量的生命期一直到程序的结束)。如果在一个文件中使用 extern关键字来声明另一个文件中存在的全局变量,那么这个文件可以使用这个数据。
- 在全局变量前加一个 static,使该变量只在这个源文件中可用。