Verilog HDL中通过task和function关键字来声明任务和函数。利用任务和函数可以把一个很大的程序模块分解成许多较小的任务和函数便于理解和调试。
任务
Verilog HDL中通过task和endtask对任务进行声明。如果子程序满足以下任一条件,则公共子程序的描述必须使用任务而不能使用函数:
- 子程序中包含延迟、时序或者时间控制结构。
- 没有输出或者输出变量的数量大于1.
- 没有输入变量。
任务的定义
task <任务名>;
端口及数据类型声明语句;
局部变量声明语句
begin
语句1;
语句2;
.....
语句n;
end
endtask
说明:
- 任务定义在关键字task和endtask之间。任务名是所定义任务的名称。在任务名后面不能出现输入、输出端口列表。
- 端口和类型声明语句用于对任务各个端口的位宽和类型进行声明,其中使用由关键字input、output或inout对任务的端口进行声明。input类型和inout类型的变量从外部传递到任务中。任务完成后,output类型和inout类型的变量传回给任务调用语句中相应的变量。
- 局部变量声明语句用来对任务内用到的局部变量进行位宽和类型声明,该声明语句的语法与进行模块定义时的相应声明语句语法一致。
- 任务中有begin与end关键词界定的一系列语句指明了任务被调用时需要进行的操作,在任务被调用时这些语句将以串行方式得到执行。
任务定义时的注意事项:
- 在第一行task语句中不能列出端口名列表。
- 任务中可以有延迟语句、敏感事件控制语句等事件控制语句。
- 任务可以没有或可以有一个或多个输入、输出和双向端口。
- 任务可以没有返回值,也可以通过输出端口或双向端口返回一个或多个值。
- 任务可以调用其他任务或函数,也可以调用该任务本身。
- 任务定义结构内不允许出现过程块(initial或always过程块)。
- 任务定义结构内可以出现disable终止语句,这条语句的执行将中断正在执行的任务。在任务被中断后,程序流程将返回到调用任务的地方继续向下执行。
任务的调用
任务的调用是通过任务调用语句实现的。任务调用语句列出了传入任务和传出任务的参数值。任务的调用格式如下:
<任务名>(端口1, 端口2, ..., 端口n);
说明:
- 任务调用语句只能出现在过程块内,任务调用语句就像一条普通的行为语句得到处理。
- 当被调用的任务具有输入和输出端口时,任务调用语句必须包含端口名列表;并且端口名列表中各个端口名出现的顺序和类型必须与任务定义结构中端口说明部分的端口顺序和类型一致。
- 只有寄存器类型的变量才能与任务的输出端口相对应。
- 任务内还可以有自己的仿真时间单位。
函数
Verilog HDL中的函数通过关键字function和endfunction对函数进行声明。对于一个子程序来说,如果下面的所有条件全部成立,则可以使用函数来完成。
- 子程序内不含有延迟、时序或者时间控制结构。
- 子程序只有一个返回值。
- 至少有一个输入变量。
- 没有输出或双向变量。
- 不含有非阻塞赋值语句。
函数的定义
函数定义的语法格式如下:
function <返回值的类型或范围> <函数名>;
输入参量与类型声明语句;
局部变量声明语句;
begin
语句1;
语句2;
........
语句n;
end
endfunction
说明:
- 任务定义在关键字function和endfunction之间。函数名是所定义函数的名称。这个函数名还是函数内部的一个变量,函数调用后的返回值就是通过这个变量传递给调用语句的。
- 返回值类型和位宽是一个可选项,用来对函数调用后返回的数据类型和位宽进行说明;返回值的类型缺省情况下是reg类型;所以它可以被定义为一个多位的寄存器变量;除此之外,还可以定义为integre或real类型。
- 输入参量与类型声明语句是对函数各个输入端口的位宽和类型进行的声明。函数至少有一个输入端口声明,不能有输出端口声明。
函数定义时的注意事项:
- 函数定义结构只能出现在模块中,而不能出现在过程块内。
- 函数至少有一个输入端口。
- 函数不能有任何类型的输出和双向端口。
- 在函数定义结构中的行为语句内不能出现任何类型的时间控制描述,也不允许使用disable终止语句。
- 函数定义结构内不允许出现过程块(initial或always过程块)。
- 在一个函数内可以对其他函数进行调用,但是函数不能调用其他任务。
- 在function第一行不能出现端口名列表。
- 在函数声明的时候,系统默认在函数内部隐含的声明了一个域函数名相同的寄存器类型的变量,函数的输出结果将通过这个寄存器类型变量传递出来。
函数的调用
函数的调用格式如下:
<函数名>(<输入表达式1>, <输入表达式2>, ..., <输入表达式n>);
说明:
- 函数调用时输入表达式与函数定义结构中说明的输入端口一一对应。
- 函数的调用不能单独作为一条语句出现,它只能作为一个操作数出现在调用语句内。
- 函数即能出现在过程块中,也能出现在assign连续赋值语句中。
- 函数定义中声明的所有局部寄存器都是静态的,即函数中的局部寄存器在函数的多个调用之间保持它们的值。
任务与函数的区别
函数 | 任务 |
---|---|
函数内能调用另一个函数,但不能调用另一个任务 | 任务能调用另一个任务,也能调用另一个函数 |
函数总是在仿真0时刻就开始执行 | 任务可以在非0仿真时刻执行 |
函数一定不能包含任何延迟、时序或者事件控制声明语句 | 任务可以包含延迟、时序或者事件控制声明语句 |
函数至少有一个输入变量 | 任务可以没有或者有多个输入、输出和双向变量 |
函数只能有一个返回值,函数不能有输出或者双向输出变量 | 任务不返回任何值,任务可以通过输出或双向变量传递多个值 |
函数不能单独作为一条语句出现,它只能以语句的一部分的形式出现 | 任务调用是通过一条单独的任务调用语句实现的 |
函数调用可以出现在过程块或连续赋值语句中 | 任务调用只能出现在过程块中 |
函数执行不允许由disable语句进行中断 | 任务执行可以由disable语句进行中断 |