在 Verilog HDL 语言中,任务(task)和函数(function)可以把一个大的程序模块分解成许多小的任务和函数,以方便调试,使写出的程序结构更清晰。

       任务(task)定义格式如下:

       task <任务名>;                     //注意无端口列表

               端口及数据类型声明;

               其他语句;

        endtask

       函数(function)定义格式如下:

       function <返回值位宽或类型说明> 函数名;

             端口及数据类型声明;

             其他语句;

       endfunction

 <返回值位宽或类型说明> 是一个可选项,如果缺省,则返回一个一位寄存器类型的数据。

                                 任务与函数的区别

比较项目

任务(task)

函数(function)

输入与输出

可有任意个各种类型的参数

至少有一个输入,不能将inout类型作为输出

调用

任务只可在过程语句中调用,而不能在连续赋值语句中调用assign

函数可作为表达式中的一个操作数来调用,在过程赋值和连续赋值语句中均可调用

定时和事件控制(#,@和wait)

任务可以包含定时和事件控制语句

函数不能包含这些语句

调用其他任务和函数

任务可以调用其他任务和函数

函数可调用其他函数,但不可以调用其他任务

返回值

任务不向表达式返回值

函数向调用它的表达式返回一个值

下面通过一个例子来说明任务和函数如何使用。

module task_function(
           in1,
           in2,
           in3,
           in4,
           out1,
           out2
       );

input [7:0] in1,in2,in3,in4;
output reg [8:0] out1,out2;

//任务
task add1;										//注意无端口列表
    input [7:0] a,b;							//输入端口和数据类型声明
    output reg [8:0] out1;					//输出端口和数据类型声明
    out1 = a + b;								//a,b,out1名称的作用范围仅为task任务内部
endtask

//调用任务
always@(in1 or in2) begin
    add1(in1,in2,out1);						//调用任务,注意端口列表的顺序要和任务中定义的一致
end

//函数
function [8:0] add2;							//函数定义  函数会自动生成一个和函数名同名的内部变量,作为函数返回值所用的寄存器。
    input [7:0] c,d;							//输入端口声明  函数只有输入端口,输出端口为函数名本身。
    add2 = c + d;								//返回输出值  输出寄存器为和函数同名的内部寄存器
endfunction
//调用函数
always @(in3 or in4) begin
    out2 = add2(in3,in4);					//调用函数,注意端口列表的顺序要和函数中定义的一致
end

endmodule

分别在任务和函数中实现两个数相加的操作,在调用任务时,需要向任务中传递输入输出端口。在调用函数的时候,只需要传递输入信号,函数的返回值作为输出信号。

下面编写测试代码

`timescale 1ns/1ns
module task_function_tb;

	reg [7:0] in1,in2,in3,in4;
   wire [8:0] out1,out2;

task_function task_function(
           .in1	(in1),
           .in2	(in2),
           .in3	(in3),
           .in4	(in4),
           .out1	(out1),
           .out2	(out2)
       );

	integer i;
	initial begin
		for(i = 0;i < 100;i = i + 1) begin
			in1 = i;
			in2 = i;
			#5;
		end	
	end

	integer j;
	initial begin
		for(j = 100;j < 200;j = j + 1) begin
			in3 = j;
			in4 = j;
			#5;
		end
		
		#100;
		$stop;
	end
	
	initial $monitor($time,,,"in1=%d in2=%d ou1=%d   in3=%d in4=%d out2=%d",in1,in2,out1,in3,in4,out2);

endmodule

in1和in2的值从0增加到100,in3和in4的值从100增加到200。并将输入值和输出值打印出来。

打印结果如下

fpga clk模块testbench fpga task_函数

输出波形如下:

fpga clk模块testbench fpga task_Verilog_02

通过上面例子可以看出,任务和函数在使用的时候方法基本相同。唯一差别就是输出端口输出方式不一样,可以根据情况选择适合的方式。