Verilog基础语法——函数function、任务task与模块module
写在前面
在Verilog中,为了提升代码的复用度,一般会使用函数function与任务task对复用逻辑进行封装,但两者的用途、语法和可综合性有显著差异。
一、基本概念
1.1 function
函数function的定义格式如下:
function <函数返回值类型> <函数返回值位宽> <函数名>;
<函数输入端口声明>
<函数内部变量声明>
begin // 并行块语句
//...
//...
end
endfunction
其调用格式如下:
<函数名>(<输入端口>,<输出端口>);
1.2 task
任务task的定义格式如下:
task <任务名>;
<任务输入输出端口声明>
<任务内部变量声明>
begin // 并行块语句
//...
//...
end
endtask
其调用格式如下:
<任务名>(<输入端口>,<输出端口>);
1.3 function与task的异同
task与function的关系如下:
其中,task中可以调用task和function,而function只能调用function。而函数function与任务task的异同可以总结为下表:
function | task |
---|---|
内部允许调用function | 内部允许调用function |
内部不允许调用task | 内部允许调用task |
至少有一个输入变量 | 可以有多个或无输入变量 |
只有一个返回值,无输出变量(output) | 可以有多个或无输出变量(output),没有返回值 |
函数调用可以在过程块(begin-end)和连续赋值语句中进行 | 任务调用只能在过程快(begin-end)中进行 |
函数的内部不能使用任何时间控制语句(@、#、wait等) | 任务中可以使用时间控制语句 |
内部仅可适用阻塞赋值 | 内部可以适用阻塞赋值/非阻塞赋值 |
Q:什么时候使用任务task?什么时候使用函数function?
当需要实现简单的组合逻辑运算,并且在代码中多次复用时,建议使用函数function。比如实现一个简单的位宽计算行数,根据数据的最大值,计算数据位宽:
function integer clogb2 (input integer depth);
begin
for(clogb2=0; depth>0; clogb2=clogb2+1)
begin
depth = depth >> 1;
end
end
endfunction
注:对于Verilog-2005版本,有位宽计算系统函数$clog2,为什么还需要自己写位宽计算函数,这是由于不是所有版本的编译器都支持该函数,自己写的位宽计算函数可以方便代码跨平台移植。
当需要实现包含时序控制的代码时,建议使用任务task。特别应该注意的是:task一般在仿真验证中搭配@、#、wait等时间控制语句进行使用,在可综合设计中应慎用(尽量不用) ,因为task的可综合具有工具依赖性,即使不带时间控制语句且为纯组合逻辑,也并非所有综合工具都可综合。
写在后面
在本文中,我们学习了函数function与任务task的基本语法和区别,并对两者适用的场景进行说明。
🧐:以上为个人学习笔记,如有疑问,欢迎评论区交流探讨 !!!
