目录
1.概述
2.任务和函数的区别
3. 任务和函数中的参数传递(值传递和引用传递)
4.任务函数返回值
5、program块和module模块的区别
函数function | 任务task | |
执行与消耗 | 不会消耗仿真时间 ,不能含有控制仿真时间的语句 | 可能会消耗仿真时间,可以包含仿真时间控制语句,如#100,时钟周期@(),wait()以及事件event等语句 |
形参变量 | 函数中至少包含一个输入变量进行传参 | 任务中可以没有输入、输出变量 |
调用方式 | function无法调用task,只能调用function | 而task可以调用task,也可以调用function |
返回值 | 一个可以返回数据的function只能返回一个单一数值 | 而任务或者void function不会返回数值,一般通过output信号直接输出。 |
返回方式 | 函数的返回可以通过调用return语句实现,当不需要返回值时可以将函数定义为void类型 | 任务没有返回值,但是也可以用return来结束task |
如果调用具有返回值的函数,但是又不使用该返回值时,我们建议为其添加void'()进行转换。
void' (some_function() ;一个可以返回数据的function可以作为一个表达式中的操作数,而该操作数的值即function的返回值。
任务的定义可以指定参数,input、output、inout及ref皆可。inout在开始的时候复制,在结束的时候输出;ref传递引用(句柄或者指针);input: 在开始的时候复制值;output:在开始的时候复制值;
SV中,子程序中的begin…end语句是可选的,但是在Veriliog1995中,除了单个语句外,这是必须的。在SystemVerilog中多条语句可以在task和function中使用,这些语句是顺序的执行。
值传递:常见的向任务与函数传递值的方法是复制;需要关键字input、output,这种传递方式实际上是将实参内容复制到形参中,原来的实参与形参存放在不同的内存空间中。
引用传递(相当于指针):用到关键字ref(取代了原来的input/output),同时需要将任务和函数声明为automatic型。在通过引用传递的方式将实参传递给形参引用时,引用型的形参变量实际上相当于实参变量的句柄或指针,也就是变量的入口地址,两者具有相同的内存空间。
SystemVerilog通过值传递的方式来传递参数,实参将被整体复制,这将消耗一定的内存和操作时间。而使用引用传递(ref),只是获取实参的入口地址(句柄或者指针),操作速度快,减少内存的使用。除此之外,在子程序修改ref参数变量的时候,其变化对于外部是立即可见的,这一点很有用。
typedef struct{logic valid;
logic[7:0] check;
logic[63] data; //最后一个变量后也需加分号
}packet_t;
packet_t data_packet; //结构体变量
logic[7:0] raw_data[0:7];
always@(posedge clk)
if(data_ready)
fill_packet(.data_in(raw_data), .data_out(data_packet));
function automactic void fill_packet(ref logic[7:0] data_in[7:0],
ref packet_t data_out);
for(int i=0; i<=7; i++)begin
data_out.data[(8*i)+:8] = data_in[i];
end
endfunction
SystemVerilog中可以将函数声明为void类型,它没有返回值。这是相对于verilog的改进,其他函数同Verilog一样可以通过函数名赋值来返回一个值,或者使用return语句实现。
当返回值的个数为1个时,用return返回
;当返回值的个数为多个时,通过output返回各种数值;
function logic[15:0] func(input [7:0] x,y);
return x*y-1; //2. 通过函数名返回
endfunction
a = func(.x(5), .y(6)); // 名字映射
a = func(5, 6); // 位置映射
1. 函数或任务中通过return关键字返回时,为非void类型;
2. 函数或任务中通过output返回时(或无返回值),须将其定义为**void类型**
为什么在程序(program)中不能使用always块?
SV中,可以在程序中使用initial块,不能使用具有连续执行性质的always块。当程序中initial块结束时,仿真实际上也默认结束了,像执行了$finish,加了always永远不会结束,不得不用$exit结束。
SV中动态存储和静态存储的概念
automactic:自动存储(相当于局部变量) static:静态存储(相当于全局变量)
类class中定义的任务和函数总是自动automatic的。 自动任务中声明的所有项都为每次调用动态分配。 所有形式参数和局部变量都存储在堆栈上。
在module、interface、program、package中定义的任务和函数默认为静态static的,所有声明的变量都是静态分配的。 如果一个程序是静态的,那么所有的子程序只能共享一个内存空间。子程序的每次执行都会覆盖之前子程序运行产生的结果。
强烈建议:将program声明为automatic类型
1. 任务定义为自动存储automatic可以采用以下两种方式:
显式声明:使用关键字automatic作为任务和函数声明的一部分;
隐式声明:通过将任务和函数定义在被定义为automatic类型的module, interface, program, or package中;
2. Program的优势:
将Testbench与DUT分开;
program可用于执行测试案例(testcase); —module不可
program可用于封装与测试案例相关的数据变量; —module不可
3. Program的功能:
program可以在顶层文件中进行例化,以实现TB与DUT的连接;
可以像module一样使用interface和端口进行连接;
可以有initial、task、function代码块,但是不能存在always代码块;
program中的initial语句块执行到结束时,隐式执行$finish语句;
参考原文链接:https://blog.csdn.net/weixin_46022434/article/details/106869354