函数与任务是仿真中常用的语法,但合理使用也可以在设计中使用,可以综合。
很多时候我们会发现某些代码是重复的,在RTL中被多次调用。它们大多不消耗仿真时间,可能涉及复杂的计算,需要用不同的数据值来完成。在这种情况下,我们可以声明一个函数,将重复的代码放在函数里面,让它返回结果。这将大大减少RTL中的行数,因为现在你需要做的就是进行函数调用,并传递需要在其上进行计算的数据。事实上,这与C语言中的函数非常相似。
函数的目的是返回一个要在表达式中使用的值。一个函数定义总是以关键字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 = a + b;
函数调用是一个带有表达式的操作数,其语法如下图所示。
reg [7:0] result;
reg [7:0] a, b;
initial begin
a = 4;
b = 5;
#10 result = sum (a, b);
end
函数的作用是对输入进行一些处理,并返回一个单一的值,而任务则更为通用,它可以计算出多个结果值,并使用output和inout类型的参数返回。任务可以包含@、posedge等仿真耗时元素。任务有两种写法,我们接下来会看到。
// Style 1
task [name];
input [port_list];
inout [port_list];
output [port_list];
begin
[statements]
end
endtask
// Style 2
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
任务使能参数(x,y,z)对应于任务定义的参数(a,b,c)。由于a和b是输入,x和y的值将分别放在a和b中。由于c被声明为输出,并且在调用过程中与z连接,所以总和将自动从c传递到变量z中。
在所有模块之外声明的任务称为全局任务,因为它们具有全局范围,可以在任何模块中调用。
// This task is outside all modules
task display();
$display("Hello World !");
endtask
module des;
initial begin
display();
end
endmodule
仿真结果:
Hello World !
函数 | 任务 |
---|---|
不能有时间控制语句/延迟,因此在同一仿真时间单位内执行。 | 可包含时间控制声明/延迟,且只能在其他时间完成。 |
无法启用任务 | 可以实现其他任务和功能 |
至少要有一个输入,函数不能有output或者inout。 | 可以有零个或多个任何类型的参数。 |
只能返回一个值 | 不能返回一个值,但可以使用输出参数达到同样的效果。 |
Verilog初级教程(17)Verilog中的case语句
Verilog初级教程(16)Verilog中的控制块
Verilog初级教程(15)Verilog中的阻塞与非阻塞语句
Verilog初级教程(14)Verilog中的赋值语句
Verilog初级教程(13)Verilog中的块语句
Verilog初级教程(12)Verilog中的generate块
Verilog初级教程(11)Verilog中的initial块
Verilog初级教程(10)Verilog的always块
Verilog初级教程(9)Verilog的运算符
Verilog初级教程(8)Verilog中的assign语句
Verilog初级教程(7)Verilog模块例化以及悬空端口的处理
Verilog初级教程(6)Verilog模块与端口
Verilog初级教程(5)Verilog中的多维数组和存储器
Verilog初级教程(4)Verilog中的标量与向量
Verilog初级教程(3)Verilog 数据类型
Verilog初级教程(2)Verilog HDL的初级语法
Verilog初级教程(1)认识 Verilog HDL
芯片设计抽象层及其设计风格
Verilog以及VHDL所倡导的的代码准则
FPGA/ASIC初学者应该学习Verilog还是VHDL?
Verilog Functions
Verilog Task
个人微信公众号: FPGA LAB
交个朋友