一.作用

提高代码的复用性、简洁性,易于代码的阅读和维护。

二.任务(function)和函数(task)的区别

(1)function不可以执行需要消耗仿真时间的语句,task可以执行需要消耗仿真时间的语句(如**#10**,@(posedge … or negedge …),wait(条件表达式));
(2)function有返回值且只能返回一个单一数值,task没有返回值;
(3)function只能调用function,task既可以调用function也可以调用task;
(4)function的返回值可以作为一个表达式中的操作数;
(5)模块中的变量、任务和函数是静态的,任务和函数要同时并行调用时,要用动态关键字automatic修饰;
语法:

task automatic 任务名 参数列表;
	task内容;
endtask

三.函数(function)

1.语法

(1)函数的定义

function 返回值类型 函数名(参数列表);
	//函数主体
endfunction

(2)函数的调用

函数名作为返回值变量(参数);

2.注意点

(1)参数列表需要,声明参数的方向(input,output,inout,ref),和参数的类型(logic,bit,int),默认是input logic类型;
(2)参数可以指定默认值;
(3)函数可以没有返回值,没有返回值时,返回值类型为void;
(4)当函数具有返回值时,但是在调用函数时不适用返回值,建议添加void’(函数名());

3.例子

(1)乘法函数

代码:

module test_ft_tb;
    logic [7:0]     data1;
    logic [7:0]     data2;
    logic [15:0]    out;
    function logic [15:0] mult(input logic [7:0] a,input logic [7:0] b);
        mult = a*b;
    endfunction
    initial begin
        data1 = 0;
        data2 = 0;
        out = mult(data1,data2);
        $display("out is %d",out);
        data1 = 10;
        data2 = 2;
        out = mult(data1,data2);
        $display("out is %d",out);
    end
endmodule

结果:
在这里插入图片描述

四.任务(task)

1.语法

(1)任务的定义:

task 任务名(参数列表);
	//任务主体
endtask

(2)任务的调用

任务名(参数);

2.注意点

(1)参数列表需要,声明参数的方向(input,output,inout,ref),和参数的类型(logic,bit,int),默认是input logic类型;
(2)参数可以指定默认值(参数如果没有给默认值,那就必须传参);
(3)task没有返回值,也不需要void;
(4)任务需要执行完之后,才会输出,除非是ref类型;
(5)task中可以用return,执行到return会提前结束task;
(6)task执行完以后才会更新输出;

3.例子

代码:

module test_ft_tb;
	task mt(input logic [7:0] a,input logic [7:0] b,output logic [15:0] c);
		#5;		
		c = a*b;
		#5; 	
	endtask 

	logic [7:0] 	in1 = 3;
	logic [7:0] 	in2 = 4;	
	logic [15:0]	out = 0;
	initial begin
		repeat(15)begin
			#1;
			$display("@time %t: out is %d",$time,out);
		end		
	end
	initial begin
		mt(in1,in2,out);
		$display("@time %t: OUT is %d",$time,out);	
	end
    
endmodule

结果:
在这里插入图片描述

五.注意点

1.函数和任务可以定义在模块中,也可以定义在类中;
2.函数和任务可以有一个或者多个输入或输出,也可以没有输入和输出;
3.任务和函数需要调用后才会执行,而initial过程块不需要调用也会默认执行;
例子:

module test_ft_tb;
    task mut(input bit [7:0] a,input bit [7:0] b,output bit [15:0] mut_out);
        mut_out = a*b;
    endtask
    bit [7:0]   data1  = 3;
    bit [7:0]   data2 = 5;
    bit [15:0]  data_out = 0;
    initial begin
        mut(
            .a          (data1),
            .b          (data2),
            .mut_out    (data_out)
        );
        $display("output is %d",data_out);
    end
endmodule

结果:
在这里插入图片描述
4.在模块和类中定义的成员,在模块和类中都可以调用和赋值,如果希望在任务和函数中对该变量进行临时存取,就通过传参的方式,也可以在任务和函数中定义局部变量,但需要用static 或者 automatic声明;
例子:

    bit [7:0] data1 = 1;
    bit [7:0] data2 = 2;
    task mut(input bit [7:0] data2);
        static bit [7:0] data3 = 3; 
        $display("data1 = %d,data2 = %d,data3 = %d",data1,data2,data3);
        data1 = 7;
        data2 = 8;
    endtask
    initial begin
        mut(
            .data2  (data2)
        );
        $display("data1 = %d,data2 = %d",data1,data2);
    end
endmodule

结果:
在这里插入图片描述
5.函数和任务的参数的方向的区别(变量和句柄)
说明:
参数分为两类,变量和句柄(地址),传输变量只是传输了该变量瞬时的值,传输句柄表示传输变量本身(变量当时的值和后续的变化在函数内部都可以得到);
分类:
传输变量的是:input,output,inout
传输句柄的是:ref
默认传输句柄的是:类的实例化句柄,接口,事件(event)
例子:
例子1代码:

module tb;
    task automatic event_tri(input bit trig,string name);
        $display("@%0t: Start waiting event %s",$time,name);
        @trig;
        $display("@%0t: Finish waiting event %s",$time,name);
    endtask
    bit t1,t2,t3;
    initial begin
        fork
            event_tri(t1,"t1");
            event_tri(t2,"t2");
            event_tri(t3,"t3");
        join
    end
    initial begin
        fork
            begin #10 t1 = !t1; end
            begin #20 t2 = !t2; end
            begin #30 t3 = !t3; end
        join
    end
endmodule

例子1结果:
在这里插入图片描述
例子2代码:

module tb;
    task automatic event_tri(ref bit trig,input string name);
        $display("@%0t: Start waiting event %s",$time,name);
        @trig;
        $display("@%0t: Finish waiting event %s",$time,name);
    endtask
    bit t1,t2,t3;
    initial begin
        fork
            event_tri(t1,"t1");
            event_tri(t2,"t2");
            event_tri(t3,"t3");
        join
    end
    initial begin
        fork
            begin #10 t1 = !t1; end
            begin #20 t2 = !t2; end
            begin #30 t3 = !t3; end
        join
    end
endmodule

例子2结果:
在这里插入图片描述
6.函数和任务的参数的方向的指定
说明:
任务和函数的参数默认是input logic类型,当前面传入其他类型变量,后续变量如果与前面变量类型不同,必须要写明变量类型,即使是input logic类型;
例子:

odule tb;
    task automatic event_tri(ref bit trig,string name);
        $display("@%0t: Start waiting event %s",$time,name);
        @trig;
        $display("@%0t: Finish waiting event %s",$time,name);
    endtask
    bit t1,t2,t3;
    initial begin
        fork
            event_tri(t1,"t1");
            event_tri(t2,"t2");
            event_tri(t3,"t3");
        join
    end
    initial begin
        fork
            begin #10 t1 = !t1; end
            begin #20 t2 = !t2; end
            begin #30 t3 = !t3; end
        join
    end
endmodule

结果:报错
在这里插入图片描述
修改后代码:将event_tri任务第二个变量指定input方向:

module tb;
    task automatic event_tri(ref bit trig,input string name);
        $display("@%0t: Start waiting event %s",$time,name);
        @trig;
        $display("@%0t: Finish waiting event %s",$time,name);
    endtask
    bit t1,t2,t3;
    initial begin
        fork
            event_tri(t1,"t1");
            event_tri(t2,"t2");
            event_tri(t3,"t3");
        join
    end
    initial begin
        fork
            begin #10 t1 = !t1; end
            begin #20 t2 = !t2; end
            begin #30 t3 = !t3; end
        join
    end
endmodule

结果:
在这里插入图片描述

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐