task和function语句分别用来由用户定义任务和函数;
task和function往往是大的程序模块中不同地点多次用到相同的程序段;
利用task和function可将一个很大的程序模块分解为许多较小的task和function,便于理解和调试;
输入,输出和总线信号的值可以传入,传出任务和函数。
task语句
当希望能够对一些信号进行一些运算并输出多个结果(即有多个输出变量)时,宜采用任务结构;
常常利用任务来帮助实现结构化的模块设计,将批量的操作以任务的形式独立出来,使设计简单明了。
任务定义:
task<任务名>; //包含定时语句的任务是不可综合的
端口及数据类型声明语句;
其他语句;
endtask
任务调用:
<任务名>(端口1,端口2,......)
注1:任务的定义和调用必须在同一个module模块内;
注2:任务被调用时,需列出端口名列表,且必须与任务定义中的I/O变量一一对应;
注3:一个任务可以调用其他任务和函数;
例:任务的定义和调用:
任务定义:
task my_task;
input a,b;
inout c;
output d,e;
......
<语句> //执行任务工作相应的语句
.......
c = foo1;
d = foo2;
e = foo3; //对任务输出变量赋值
endtask
任务调用:
my_task(v,w,x,y,z);
当任务启动时,有v,w和x传入的变量赋值给a,b,c;
当任务完成时,输出通过c,d,e赋值给x,y,z。
例:通过任务调用完成4个4位二进制输入数据的冒泡排序。
module sort4(ra,rb,rc,rd,a,b,c,d);
output [3:0] ra,rb,rc,rd;
inout [3:0] a,b,c,d;
reg [3:0] ra,rb,rc,rd;
reg [3:0] va,vb,vc,vd; //中间变量
always@(*)
begin
{va,vb,vc,vd} = {a,b,c,d};
sort2(va,vc); //任务调用
sort2(vb,vd);
sort2(va,vb);
sort2(vc,vd);
sort2(vb,vc);
{ra,rb,rc,rd} = {va,vb,vc,vd};
end
task sort2; //定义任务
inout [3:0] x,y;
reg [3:0] tmp;
if(x>y)
begin
tmp = x;
x = y;
y =tmp;
end
endtask
endmodule
测试文件:
//测试文件
'timescale 1ns/1ps
'include "./sort4.v"
module task_top;
reg [3:0] a,b,c,d;
wire[3:0] ra,rb,rc,rd;
initial
begin
a = 0;
b = 0;
c = 0;
d = 0;
repeat(5)
begin
#100 a={$random}%15;
b={$random}%15;
c={$random}%15;
d={$random}%15;
end
#100 $stop; //暂停仿真
end
sort4 my_sort4(.ra(ra),
.rb(rb),
.rc(rc),
.rd(rd),
.a(a),
.b(b),
.c(c),
.d(d)
);
endmodule
$random为系统任务,返回一个32位的带符号的随机数;
一般用法为:$random %b;
其中b>0,它给出一个范围在-b+1——b-1之间的随机数;
{$random}%15通过位拼接操作,产生一个0-14之间的随机数。
function语句(可以综合)
函数的目的是通过返回一个用于某表达式的值,来响应输入信号。适用对不同变量采用同一运算的操作。
函数在模块内部定义,通常在本模块中调用,也能根据按模块层次分级命名的函数名从其他模块调用。而任务只能在同一模块内定义和调用。
函数定义:
function <返回值位宽或类型说明> 函数名;//返回值缺省值返回1位reg型数据
端口声明;
局部变量定义;
其他语句;
endfunction
函数调用:
<函数名>(<表达式><表达式>) //表达式与函数定义中的输入变量对应!
注1:函数的调用是通过将函数作为调用函数的表达式中操作数来实现的。
function [7:0] gefun; //函数的定义;
input [7:0] x;
.....
<语句> //进行运算
gefun = count; //赋值运算 gefun相当于一个内部寄存器
endfunction
assign number = gefun(rega); //对函数的调用
注2:函数在综合时被理解称为具有独立运算功能的电路,每调用一次函数,相当于改变此电路的输入,以得到相应的计算结果。
函数的使用规则:
1. 函数的定义不能包含任何时间控制语句——用延迟#,时间控制@或等待wait标示的语句。
2. 函数不能调用task;
3.定义函数时至少要有一个输入参数!且不能有任何输出或输入/输出双向变量;
4.在函数的定义中必须有一条赋值语句,该函数的一个内部寄存器赋以函数的结果值,该内部寄存器与函数同名。
例:利用函数对一个8位二进制数中为0的位进行计数。
module count0s_function(number,rega);
output [7:0] number;
input [7:0] rega;
function [7:0] gefun;
input [7:0] x; //只有输入变量
reg [7:0] count;
integer i;
begin
count = 0;
for(i=0;i<=7;i++)
if(x[i]==1'b0) count= count +1;
gefun = count; //内部寄存器
end
endfunction
assign number = gefun (rega); //对应函数的输入变量
endmodule
波形:
阶乘运算:
module tryfunct(result,clk,reset,n);
output [31:0] result;
input [3:0] n;
input reset,clk;
reg [31:0] result;
function [31:0] factorial;
input [3:0] op;
reg [3:0] ina;
begin
factorial = op?1:0;
for (ina=2;ina<=op;ina++)
factorial= ina*factorial; //factorial 内部寄存器
end
endfunction
always@(posedge clk) //clk 的上升沿触发同步运算
begin
if(!reset) reset<=0;
else result<=factorial(n); //函数的调用
end
endmodule
测试文件:
任务和函数的区别:
function 和 task的区别
任务 | 函数 | |
目的或用途 | 可计算多个结果值 | 通过返回一个值,来响应输入信号 |
输入与输出 | 可为各种类型 | 至少有一个变量输入,并不能有output 或 inout型变量 |
被调用 | 只可以在过程语句块中调用,不可以在连续赋值语句中调用 | 可作为表达式中的一个操作数来调用,在过程语句和连续赋值语句中都可以调用 |
调用其他任务和函数 | 任务可以调用其他任务和函数 | 函数可以调用其他函数,但不可以调用任务 |
返回值 | 不向表达式返回值 | 向调用它的表达式返回值 |