函数function
函数的目的是返回一个要在表达式中使用的值。一个函数定义总是以关键字function开始,后面是返回类型、名称和用括弧括起来的端口列表。当Verilog找到endfunction关键字时,就知道一个函数定义结束了。注意,一个函数至少要声明一个输入,如果函数没有返回任何东西,则返回类型为void。
语法
function [automatic] [return_type] name ([port_list]);
[statements]
endfunction
关键字automatic将使函数重入,在任务中声明的项目被动态分配,而不是在任务的不同调用之间共享。这对于递归函数,以及当同一个函数在分叉时被N个进程并发执行时,将非常有用。
函数声明
有两种方式来声明函数的输入。
function [7:0] sum;
input [7:0] a, b;
begin
sum = a + b;
end
endfunction
function [7:0] sum (input [7:0] a, b);
begin
sum = a + b;
end
endfunction
函数返回值
函数定义将隐含地创建一个与函数同名的内部变量。因此,在函数的作用域内声明另一个同名的变量是非法的。返回值是通过将函数结果赋值给内部变量来初始化的。sum就是被赋予的值就是函数的返回值。
sum = a + b;
函数的调用
函数调用是一个带有表达式的操作数,其语法如下图所示。
reg [7:0] result;
reg [7:0] a, b;
initial begin
a = 4;
b = 5;
#10 result = sum (a, b);
end
函数使用规则
- 函数不能包含任何时间控制的语句,如#, @, wait, posedge, negedge
- 函数不能调用任务,因为它可能会消耗仿真时间,但可以调用其他函数。
- 函数应该至少有一个输入
- 函数不能有非阻塞性的赋值或force…release或assign…deassign。
- 函数不能有任何触发器
- 函数不能有output或者inout
任务task
函数的作用是对输入进行一些处理,并返回一个单一的值,而任务则更为通用,它可以计算出多个结果值,并使用output和inout类型的参数返回。任务可以包含@、posedge等仿真耗时元素。任务有两种写法,我们接下来会看到。
task [name];
input [port_list];
inout [port_list];
output [port_list];
begin
[statements]
end
endtask
task [name] (input [port_list], inout [port_list], output [port_list]);
begin
[statements]
end
endtask
关键字automatic将使任务重入,否则它将默认为静态的。如果一个任务是静态的,那么它的所有成员变量将在同一任务的不同调用中被共享,该任务已被启动为并发运行。注意,auomatic任务项不能通过层次引用来访问。
任务的调用
如果任务不需要任何参数,那么可以避免使用参数列表。如果任务需要参数,则可以在调用任务时在同一条语句中提供参数。
task sum (input [7:0] a, b, output [7:0] c);
begin
c = a + b;
end
endtask
// or
task sum;
input [7:0] a, b;
output [7:0] c;
begin
c = a + b;
end
endtask
initial begin
reg [7:0] x, y , z;
sum (x, y, z);
end
全局任务
task display();
$display("Hello World !");
endtask
module des;
initial begin
display();
end
endmodule
函数与任务的区别
函数function | 任务task |
---|---|
不能有时间控制语句/延迟,因此在同一仿真时间单位内执行。 | 可包含时间控制声明/延迟,且只能在其他时间完成。 |
无法启用任务 | 可以实现其他任务和功能 |
至少要有一个输入,函数不能有output或者inout。 | 可以有零个或多个任何类型的参数。 |
只能返回一个值 | 不能返回一个值,但可以使用输出参数达到同样的效果。 |