任务(Task)的使用与函数很类似,必须经过调用才能执行。但与函数不同的的是:
- 函数的参数列表中只有输入(input)没有输出(output),返回值是通过函数名带回的,而且只能有一个返回值。
- 任务(task)可以有输入/输出端口,也可以没有输入/输出端口。
任务(task)的结构定义如下:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
//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求最大值
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
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
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
`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:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
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习题库
对应视频: