1. verilog 函数
在 verilog 中,可以利用任务(关键字为 task)和函数(关键字为 function),将重复性的行为级设计进行提取,并在多个地方调用,来避免重复写代码。
2. 函数
函数只能在模块中定义,位置任意,并在模块的任何地方使用,作用范围仅限于此模块。
函数主要有以下特点:
- 不含有任何延迟,时序或时序控制逻辑
- 至少有一个输入变量
- 只有一个返回值,且没有输出
- 不含有非阻塞赋值语句
- 函数可以调用其它函数,但是不能调用任务
格式如下
verilog
function [range-1:0] function_id ;
input_declaration ;
other_declaration ;
procedural_statement ;
endfunction
函数在声明时,会隐式的声明一个宽度为 range
,名字为 function_id
的寄存器变量,函数的返回值通过这个变量进行传递。
当该寄存器变量没有指定位宽时,默认位宽为 1。
函数通过指明函数名与输入变量进行调用。函数结束时,返回值被传递到调用处。
函数调用
格式如下
verilog
function_id(input1, input2,... )
示例如下
verilog
module test(
input wire clk_i ,
input wire rst_n_i ,
input wire [3:0] n_i ,
output reg [31:0] result_o
);
always @(posedge clk_i or negedge rst_n_i) begin
if(!rst_n_i) begin
result_o <= 0 ;
end
else begin
result_o <= n*factorial(n)/((n*2)+1) ;
end
end
function [31:0] factorial ;
input [3:0] operand ;
reg [3:0] index ;
begin
factorial=operand ? 1 : 0 ;
for(index=2; index<=operand; index=index+1) begin
factorial=index*factorial ;
end
end
endfunction
endmodule
3. automatic 函数
function 可以被自己调用,实现递归操作(7*6*5*4*3*2*1)。
在 verilog 中,一般函数的局部变量是静态的,即函数的每次调用,函数的局部变量都会使用同一个存储空间。
若某个函数在两个不同的地方同时并发的调用,那么两个函数调用行为同时对同一块地址进行操作,会导致不确定的函数结果。
verilog 用关键字 automatic 来对函数进行说明,此类函数在调用时是可以自动分配新的内存空间的,即是递归的。
因此,automatic 函数中声明的局部变量不能通过层次命名进行访问,但是 automatic 本身可以通过层次名进行调用。
示例如下
verilog
wire [31:0] result = factorial(7) ;
function automatic integer factorial ;
input integer data ;
integer i ;
begin
factorial = (data>=2) ? data * factorial(data-1) : 1 ;
end
endfunction
/// 结果为7*6*5*4*3*2*1
tip
上面代码可以理解为
result=7*factorial(6)
factorial (6) = 6 * factorial (5)
...
...
...
factorial (1) = 1
即 7*6*5*4*3*2*1=5040
如果,不加 automatic,就会得到预期之外的结果。