函数function | 任务task | |
---|---|---|
执行与消耗 | 在仿真0时刻就开始执行,不消耗仿真时间 | 在非0时刻(被调用)执行,消耗仿真时间 |
仿真控制语句 | 函数中不能含有控制仿真时间的语句 如时间延迟#100,阻塞语句@(posedge clk)等 | 任务中可以包含仿真时间控制语句 如延迟#100,时钟周期@(),wait()以及事件event等语句 |
返回形式 | 函数的返回可以通过调用return语句实现,当不需要返回值时 可以将函数定义为void类型 | 任务没有返回值,一般通过output信号直接输出,也不需要关键字void |
形参变量 | 函数中至少包含一个输入变量进行传参 | 任务中可以没有输入、输出变量 |
调用方式 | 函数的调用可以以语句的一部分出现 | 任务的调用通过一条**单独的语句实现 |
相互调用 | 函数中只能调用函数,不能调用任务 | 任务中可以调用任务,也可以调用函数 |
二、子程序参数
systenverilog对任务和函数做出了重大改进,子程序中的begin…end语句是可选的,但是在Veriliog1995中,除了单个语句外,这是必须的。在SystemVerilog中多条语句可以在task和function中使用,这些语句是顺序的执行。
在SystemVerilog中任务和函数的形式参数可以声明在其名字后的圆括号中(参数的默认方向是input,默认类型是logic)。每一个形式参数可选的方向属性如下:
- input: 在开始的时候复制值;
- output:在开始的时候复制值;
- inout:在开始的时候复制,在结束的时候输出;
- ref:传递引用(句柄或者指针);
SystemVerilog提供了两种方式来为函数和任务传递参数:值传递和引用传递。所谓引用传递(reference)就如C++的句柄或者指针,也就是变量的入口地址。此时参数的类型因定义为ref。
- 值传递:常见的向任务与函数传递值的方法是复制;需要关键字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
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
三、子程序返回
Verilog中函数必须有返回值,返回值通过函数名赋值来完成。
SystemVerilog中可以将函数声明为void类型,它没有返回值。这是相对于verilog的改进,其他函数同Verilog一样可以通过函数名赋值来返回一个值,或者使用return语句实现。
function logic[15:0] myfunc(input [7:0] x,y);
return x*y-1;
endfunction
- 1
- 2
- 3
void语句可以作为单个语句调用,其他情况下,函数都以表达式调用;
在一个语句中调用非void类型的函数会导致一个警告信息,仿真器会将函数返回值强制转换成void类型,效果如同:void`(some_function());
a = b + myfunc(c, d); //函数作为表达式调用
myprint(a); //函数作为一条语句调用
function void mypritn(int a);
…
endfunction
- 1
- 2
- 3
- 4
- 5
- 6
四、automactic与static
- automactic:自动存储(相当于局部变量)
- static:静态存储(相当于全局变量)
类class中定义的任务和函数总是自动automatic的。 自动任务中声明的所有项都为每次调用动态分配。 所有形式参数和局部变量都存储在堆栈上。
在module、interface、program、package中定义的任务和函数默认为静态static的,所有声明的变量都是静态分配的。 这些变量会在所有任务同时执行中被共享使用。
任务定义为自动存储automatic可以采用以下两种方式:
- 显式声明:使用关键字automatic作为任务和函数声明的一部分;
- 隐式声明:通过将任务和函数定义在被定义为automatic类型的module, interface, program, or package中;
</div><div data-report-view="{"mod":"1585297308_001","dest":"https://blog.csdn.net/weixin_46022434/article/details/106869354","extend1":"pc","ab":"new"}"><div></div></div>
<link href="https://csdnimg.cn/release/phoenix/mdeditor/markdown_views-ff98e99283.css" rel="stylesheet">
</div>