声明:本内容来自于学习路科验证发布在B站上的免费视频课程后的笔记
一、函数function
1、目的是为运算表达式提供返回值,便于简化代码和维护大型代码。
2、void function不会返回数值,但会返回一个空类型null。
3、函数的参数可以声明方向input、output、inout和ref。
4、如下代码中的参数x和y并没有声明方向,那么默认方向为input。
myfunc1函数的返回值最终会返回给logic [15:0]
function logic [15:0] myfunc1(int x, int y);
...
endfunction
按照module的方式来声明参数的方向
function logic [15:0] myfunc2;
input int x;
input int y;
...
endfunction
5、函数的两种返回方式:
1)将返回数值赋给与函数同名的变量,然后继续执行后面的代码。
//返回值默认为16位的logic数据类型;x,y也默认为8位的logic数据类型
function [15:0] myfunc1 (input [7:0] x,y);
myfunc1 = x * y - 1;
endfunction
2)使用return立即返回数值。
//返回值默认为16位的logic数据类型;x,y也默认为8位的logic数据类型
function [15:0] myfunc2 (input [7:0] x,y);
return x * y - 1;
endfunction
如果调用具有返回值的函数,但又不使用该返回值时,可以用void'() 进行转换。
void'(some_function())
二、任务task
1、任务可以指定参数和参数的方向:input、output、inout及ref;
2、任务可能会消耗仿真时间;
3、任务可以调用其它任务或者函数。
4、它和函数一样,有两种声明方式:
1)按照通常的方式来声明参数及参数方向
task mytask1 (output int x, input logic y);
...
endtask
2)按照module的方式来声明参数及参数的方向
task mytask2;
output x;
input y;
int x;
logic y;
...
endtask
5、任务task可以加延时语句,如:#5ns
`timescale 1ns/1ps
module tb;
task mytask1(input [7:0] x,
input [7:0] y,
output [15:0] z);
#5ns
z = x*y + 1;
#5ns
endtask
byte unsigned a = 5;
byte unsigned b = 7;
byte unsigned c;
initial begin
mytask1(a, b, c);
$display("c = %0d", c);
end
initial begin
repeat(12) begin;
#1ns;
$display("@time %t c = %0d", @time, c);
end
end
endmodule
三、函数function和任务task的区别
1、function不会消耗仿真时间,task可能会消耗仿真时间;
2、function可以调用function,无法(不建议)调用task(如果是消耗仿真时间的task,function就不能调用);而task可以调用function和task;
3、function一定有返回数据,且只能返回一个单一数值;void function不会返回数值或者说返回一个空类型null;task不会返回数值。
4、一个可以返回数据的function可以作为一个表达式中的操作数,而该操作数的值即是function的返回值。
5、函数和任务的参数列表都可以为空。
6、函数和任务的参数值都可以有默认值。
四、函数和任务的参数传递
1、参数方向input在方法(函数或任务)调用时,属于值传递。即在传递的过程中,外部变量的值会经过拷贝,然后赋值于形式参数。
2、参数方向output和inout也会在传入或者传出的时候产生值传递的过程。
3、值传递的过程只发生在方法的调用时和返回时。
4、参数方向为ref的参数在传递时不会发生值拷贝,而是将变量“指定”传递到方法中,在方法内部对该参数的操作将会同时影响外部变量。
如果为了避免外部传入的ref参数会被方法修改,则可以添加const修饰符,它表示变量是只读变量。
5、带有参数默认值的方法被调用时,如果这些参数没有被传递值,那么编译器将会为这些参数传入对应的默认值。
注:这里的input表示参数的方向,但int表示的是数据类型。如果不声明数据类型,那么就会默认参数的数据类型为1bit位宽的logic,这样就得不到预期的结果(详见B站视频讲解)
task read(input int j = 7, input int k, input int data =10);
...
endtask
read(20,17,30);
read(,7);
read();//传空,编译会报错,因为参数k并没有默认值
read(30);//编译会报错,因为实参30将会传递给j,而参数k依然没有默认值
read(.k(17));//只给K传递了一个实参
6、SV中可以类似于模块的例化一样,可由参数的位置顺序在调用方法时传递参数,也可以由参数名字调用方式时绑定参数。
function int fun(int j = 1, string s = "no" );
...
endfunction
fun( .j(2), .s("yes"));
fun( , "yes");
fun(.s("yes"));
fun(.s(), .j());