任务(Task)的使用与函数很类似,必须经过调用才能执行。但与函数不同的的是:
- 函数的参数列表中只有输入(input)没有输出(output),返回值是通过函数名带回的,而且只能有一个返回值。
- 任务(task)可以有输入/输出端口,也可以没有输入/输出端口。
任务(task)的结构定义如下:
//Verilog 1995 格式
task <task_name>; //任务名称
input <input_name>; //输入端口及名称
<more_inputs> //更多的输入端口及端口名称
output <output_name>; //输出端口及端口名称
<more_outputs> //更多的输出端口
begin
<statements>; //顺序语句
end
endtask
任务是由关键字task…endtask 括起来的结构。如果在task中没有不可综合的语句(如$display,$monitor 等)出现,task本身是可综合的。目前FPGA综合器在综合时一般会忽略$display,$monitor 等系统函数。
例1:利用task求最大值
module max_mod
#(parameter WIDTH = 4)
(
input [WIDTH-1:0] a, b, c, d,
output reg [WIDTH-1:0] res
);
reg [WIDTH-1:0] tmp_r0;
reg [WIDTH-1:0] tmp_r1;
task max_task;
input [WIDTH-1:0] a,b;
output [WIDTH-1:0] max;
if(a > b)
max = a;
else
max = b;
endtask
always@(*)
begin
max_task(a, b, tmp_r0);
max_task(tmp_r0, c, tmp_r1);
max_task(tmp_r1, d, res);
end
endmodule
从上面的例子中可以看出,在过程语句中执行task语句,虽然max是输出(没有明确指出是reg的类型),但是在调用task时,但系统默认max为reg类型。如果在task内部使用wire型变量并对其赋值,在modelsim仿真时会报语法错误。
仿真激励程序tb_test.v
`timescale 1 ns / 1 ps
module tb_test ();
parameter WIDTH = 4;
reg [WIDTH-1:0] a, b, c, d;
wire [WIDTH-1:0] max;
initial
begin
a = 0;
b = 0;
c = 0;
d = 0;
#10
a = 3;
b = 2;
c = 6;
d = 5;
#10
a = 12;
end
max_mod #(.WIDTH(WIDTH))
max_mod_inst
(
.a (a),
.b (b),
.c (c),
.d (d),
.res (max)
);
endmodule
仿真波形如图1:

图1:
从例1中task的使用可总结如下:
- 在Verilog 95中第一行“task”语句中不能列出端口名称;Verilog 2001语法中也可以直接将输入、输出紧跟task 名之后的括号中。如:task max_task(input [WIDTH-1:0] a, b, output [WIDTH-1:0] max);
- task的输入、输出端口数量不受限制,甚至可以没有输入、输出端口。如在仿真程序中的task只用来调用$time, $display,$monitor等函数或任务,不做其它行为时,可以省略task的参数列表。
- 在task中可以调用其他的task或function,也可以自身嵌套调用。注:自身嵌套时, 只能在仿真中使用。
- 在task定义内不能使用 initial和 always过程块。也不能使用时钟边沿驱动。可以理解为可综合的 task就是组合逻辑电路。
- 在任务定义中可以出现“disable 中止语句” ,将终止正在执行的任务,但该语句是不可综合的。当任务被中断后,程序流程将返回到调用任务的地方继续向下执行。
- task 调用只有位置对应,没有名字对应,因此参数传递时一定要注意先后顺序,一一对应。
- task只能在initial 或always过程块中调用,不能在并发过程中调用,如下面的调用就是错误的(例2)。
- task的输出是由output端口传出的,task 名(task name)本身没有返回值。
例2:
module max_mod
#(parameter WIDTH = 4)
(
input [WIDTH-1:0] a, b, c, d,
output [WIDTH-1:0] res
);
wire [WIDTH-1:0] tmp_r0;
wire [WIDTH-1:0] tmp_r1;
task max_task;
input [WIDTH-1:0] a,b;
output [WIDTH-1:0] max;
if(a > b)
max = a;
else
max = b;
endtask
//下面的task 调用出现在了并发过程的位置,是错误的。
max_task(a, b, tmp_r0);
max_task(tmp_r0, c, tmp_r1);
max_task(tmp_r1, d, res);
endmodule
作业题:利用task计算斐波那契数列,写出可综合的程序,并提供激励文件,用$display函数打印仿真结果。
见FPGA习题库
对应视频: