任务和函数
目录
Verilog中模块(module)作为主要层次分割方法,函数(function)和任务(task)提供附加的代码分割和封装方法。
任务和函数有以下特点:
①用于模块中需要重复书写的代码段,使用时只需进行调用;
②任务和函数必须在module内定义和调用,其作用域范围仅局限于定义它们的模块;
③任务和函数与命名快一样,包含在设计层次中,可通过层次名进行访问;
④在任务和函数中不能声明wire变量,任务、函数内定义的变量都是局部变量,不会与其他变量冲突,调用方便,所有输入/输出都是局部寄存器;
⑤任务和函数的定义只能使用行为级语句,但不能包含always和initial过程语句;
⑥任务/函数执行完成后才返回结果。
5.1、任务
任务是一段通过传递参数并由寄存器接收结果的可重用代码,通常用于调试或对硬件进行行为描述。任务可以包含各类时序控制事件(#延迟,@,wait)等语法结构,可以具有0个或多个输入(input)、输出(output)和双向(inout)变量。任务可以调用其他任务和函数。
对于一段满足下列任一情况的可重用代码,都可考虑使用任务:
①代码设计中包含时序控制事件;
②没有输出或输出变量的数目大于1;
③没有输入变量。
(1)任务的定义
Task task_identifier;//task_identifier 任务名 //定义端口,可选,默认为reg类型,不能定义、使用net型变量 Input 输入端口名 Output 输出端口名 Inout 双向端口名 //定义内部变量 <数据类型> 内部变量名; //局部变量,对调用模块不可见 Begin // 任务描述主体语句块 <语句1> ; // 允许使用延时和事件控制语句 <语句2> ; // 及其他行为级语句 …… End Endtask; |
(2)任务的调用
任务是按照任务中定义的端口顺序进行调用和变量传递的,在模块中的调用方式为:<任务名>端口1,端口2…,端口n);
注意:如果想使任务或函数具有更好的可重用性,能被另一个模块调用,则所有在任务或函数内部用到的变量都应该列在端口列表中。
(3)可重入任务
可重入任务就是对同意任务的不同调用时,系统会为不同的调用者分配独立的地址空间和变量,任务定义时在关键字task前加上automatic,这样声明的任务称为自动重入任务。
Task automatic task_identifier; Input … Output … … Endtask |
同时多次调用同一任务时,最好使用可重入任务。
5.2、函数
函数主要用于返回一个函数名表示的、用于表达式的值,一般作为Verilog表达式中的操作数来使用,即由连续赋值语句或过程赋值语句中的表达式调用。
使用函数比任务有更多的限制。对于一段可重用代码来说,如果下面的所有条件都成立,则可以使用函数来完成:
①不包含各种时序控制语句结构;
②只有一个返回值,其所分配到的内部寄存器的命名应与函数名相同;
③至少有一个输入变量,没有输出变量或双向变量;
④不含非阻塞赋值语句。
(1)函数的定义
函数使用关键字function……endfunction定义和封装。定义函数的同时隐式声明了与函数名同名的寄存器型变量,函数的输出结果将通过这个寄存器型变量被传递回来。
Function <返回值的类型或范围> function_identifier;//函数名为函数的返回值 <端口说明>;// 至少带有一个输入,但不可申明任何输出 <变量说明>;// 函数内的局部变量 Begin //函数描述主体,不能包含延时(#)和时间(@)语句 <语句1>: <语句2>;//语句中必须显式地对函数名寄存器变量赋值 …… endfunction |
其中<返回值的类型或范围>为可选项,缺省时返回的函数值为一位reg型变量。要返回一个向量值(多于1位)或其他寄存器型函数值,则需在函数定义时说明返回值的类型或范围。(函数通常用于描述各类算式或组合逻辑)
(2)函数的调用
函数的调用通过指明函数名和输入变量来进行,在函数执行结束时,返回值被传递到调用处,可直接用于表达式中。
函数调用时需注意:
①传送到函数的参数顺序和函数输入参数的说明顺序相同;
②函数不能调用任务;
③函数返回的值可以用于Verilog表达式;
④函数中可以对返回值的个别位进行赋值;
⑤函数值的位数、函数端口甚至函数功能都可以参数化。