在Verilog代码中,通过把代码分成小的模块或者使用任务(task)和函数(function),可把一项任务分成许多较小的、易于管理的部分,从而提高代码的可读性、可维护性和可重用性。函数和任务往往还是大的程序模块在不同地点多次用到的相同的程序段。
#
,@
,wait
),也可以包含input
, output
、inout
端口定义和参数。可以调用其他的任务或函数。任务可以包含时间控制,但加入时间控制后则该部分无法综合,所以任务常用于testbench测试模块。函数的目的是通过返回一个用于某表达式的值,来响应输入信号。适于对不同变量采取同一运算的操作。函数在模块内部定义,通常在本模块中调用,也能根据按模块层次分级命名的函数名从其他模块调用。函数的目的是返回一个用于表达式的值。
定义函数的语法
function < 返回值的类型或范围 > 函数名; // 返回值类型integer、范围 [15:0]等等
< 端口说明语句> // input xxx
< 变量类型说明语句 > // reg yyy
begin
<语句>
end
end function
// 返回值的类型或范围可以不定义,默认为一位寄存器类型数据
函数的使用规则
#
,@
,wait
来标识的语句 ),函数的实现只能是组合逻辑。always
)函数的使用注意点
disable
终止语句。output
端口)和双向端口(inout
端口)。例子
function [8:0] sum;
input [7:0] a;
input [7:0] b;
begin
sum = a + b;
end
endfunction
function 本身表述的是组合电路,但是可以赋值给某个触发器。
调用形式
functionName( param1, param2,...);
参数列表的顺序必须与函数定义声明时输入的顺序相同。
函数调用的注意点
assign
赋值语句中出现。always
或者initial
等reg
声明变量,但是声明后就不可综合了)real
或者time
等数据类型。函数支持多文件调用
// modulea.v
module modulea();
function [8:0] sum2num;
input [7:0] a;
input [7:0] b;
begin
sum2num = a + b;
end
endfunction
endmodule
// moduleb.v
module moduleb();
modulea modulea_inst();
// modulea_inst.sum2num(a,b);
endmodule
任务类似于一段程序,可以使设计者从设计描述的不同位置执行共同的代码段。用任务定义可以将这些共同的代码段编写成任务,从而能够在设计描述的不同位置通过任务名调用该任务。
任务完成以后控制就传回启动过程。如任务内部有定时控制,则启动的时间可以与控制返回的时间不同。 任务可以启动其它任务,其它任务又可以启动别的任务,可以启动的任务数是没有限制的,不管有多少任务启动,只有当所有的启动任务完成以后,控制才能返回。
任务的定义
task taskName(
input xxx ,
input yyy ,
output zzz
);
begin : label
reg aaaa ;
wire cccc ;
// statement
end
endtask
任务的使用注意点
任务可以带有时序控制或者等待某些特定的事件发生,直到任务退出时,赋给输出变量的值才传递给调用的参变量。
在任务或函数中,引用父模块中声明的变量时要特别注意(即注意变量的层次命名规则)。若想在其它模块中调用任务或函数,该任务和函数中所使用的变量必须全都包含在输入/输出口列表中。
不要在程序的不同部分同时调用同一个任务,这是因为任务只有一组本地变量,同一时刻调用两次相同的任务将会导致错误,这种情况常发生在使用定时控制的任务中。Verilog任务中所有声明的变量地址空间都是静态分配的,因此如果在一个模块中多次调用任务时,可能会造成地址空间的冲突。
任务可以被声明为automatic类型,其内部声明的所有局部变量在每次任务调用时都进行动态分配,即在任务调用中的局部变量不会对两个单独或者并发的任务调用产生影响。而在静态(非automatic)任务中,在每次任务调用中的局部变量都使用同一个存储空间。借助关键字automatic就可以把任务指定为automatic类型。
跟任务调用一样,在模块中如果调用多次函数,也会碰到地址冲突的问题,因此也引入automatic关键字来对函数可重用性声明。没有进行可重用性声明的函数不可以多次或者递归调用,进行了可重用性声明的函数可以递归调用。
function automatic [8:0] sum2num;
input [7:0] a;
input [7:0] b;
begin
sum2num = a + b;
end
endfunction
task automatic taskName(
input xxx ,
input yyy ,
output zzz
);
begin : label // 命名块结构
reg aaaa ;
wire cccc ;
// statement
end
endtask
使用关键词automatic修饰后,每一次调用都对不同的地址进行操作,因此可以多次并发调用时,也可得到正确的结果。
automatic修饰
)always
块和initial
块。