verilog中的function2
函数的定义
函数 定义不允许输出端口声明(包括输出和双向端口) ,但可以有多个输入端口。函数定义的语法如下:
function [range] function_id;
input_declaration
other_declarations
procedural_statement
endfunction
[range]参数指定函数返回值的类型或位宽,是一个可选项,若没有指定,默认缺省值为 1 比特的寄存器数据;function_id 为所定义函数的名称,对函数的调用也是通过函数名完成的,并在函数结构体内部代表一个内部变量,函数调用的返回值就是通过函数名变量传递给调用语句;input_declaration 用于对寒暑各个输入端口的位宽和类型进行说明,在函数定义中至少要有一个输入端口;
函数定义举例:
function[31:0]factorial;
input[3:0]operand;
reg[3:0]index;
begin
factorial = 1; // 0的阶乘为1, 1的阶乘也为1
for(index=2; index<=operand; index=index+1)
factorial = index * factorial;
end
endfunction
函数定义在函数内部会隐式定义一个寄存器变量, 该寄存器变量和函数同名并且位宽也一致。函数通过在函数定义中对该寄存器的显式赋值来返回函数计算结果。此外,还有下列
几点需要注意:
(1)函数定义只能在模块中完成,不能出现在过程块中;
(2)函数至少要有一个输入端口;不能包含输出端口和双向端口;
(3) 在函数结构中, 不能使用任何形式的时间控制语句 (#、 wait 等) , 也不能使用 disable
中止语句;
(4)函数定义结构体中不能出现过程块语句(always 语句) ;
(5)函数内部可以调用函数,但不能调用任务。(6)function内部声明的reg类型变量实际上综合出是wire类型(=号赋值)类似规定always块内只能用reg类型的变量,用alwasys(*)写组合逻辑时(这是龟腚)
(7)function,就是声明一个函数。与task的区别就是有参数。function的返回值就是函数名(可以设置位宽),输入值任意,均作为输入参数。代码块需符合verilog的语法规则。如放在assign块中的函数需要使用wire变量,always语句中的函数需要使用reg型的变量。不可在function内部加入赋值类型的标志
2.函数调用
func_id(expr1, expr2, …, exprN)
其中,func_id 是要调用的函数名,expr1, expr2, …exprN是传递给函数的输入参数列
表,该输入参数列表的顺序必须与函数定义时声明其输入的顺序相同。
参考夏闻宇老师书上阶乘函数的定义与调用的例子:(略做修改)
module tryfact;
function[31:0]factorial;
input[3:0]operand;
reg[3:0]index;
begin
factorial = 1; // 0的阶乘为1, 1的阶乘也为1
for(index=2; index<=operand; index=index+1)
factorial = index * factorial;
end
endfunction
reg[31:0]result;
reg[3:0]n;
initial
begin
result=1;
for(n=2;n<=9;n=n+1)
begin
result = factorial(n);
$display("正整数 n= %d的阶乘为 result= %d", n, result);
end
$display("Finalresult=%d",result);
end
endmodule // 模块结束
仿真结果:
在函数调用中,有下列几点需要注意:
(1)函数调用可以在过程块中完成,也可以在 assign 这样的连续赋值语句中出现。
(2)函数调用语句不能单独作为一条语句出现,只能作为赋值语句的右端操作数。
哈姆雷特,请保持前行!