Verilog 函数
函数
函数只能在module中定义,并在module的任意地方引用,作用范围当然只是这个module
特点:
- 不含任何延迟、时序或者时序控制逻辑
- 至少有1个输入变量
- 只有一个返回值,且没有输出
- 不含非阻塞赋值语句
- 可以调用其他函数,但是不能调用任务
function [range-1:0] function_id;
input_declaration;
other_declaration;
procedural_statement;
endfunction
关键字function
函数声明时,隐式的声明1个宽度为range名字为function_id的寄存器变量,返回值通过这个变量进行传递,该寄存器变量没有指定位宽时,默认位宽为1
通过指明函数名与输入变量进行调用,结束时返回值被传递到调用处
function_id(input1,input2,...);
下面用函数实现1个数据大小端转换的功能
输入为4'b0011输出可为4'b1100,如:
module endian_rvs
#(parameter N =4)
(
input en,
input [N-1:0] a,
output [N-1:0] b
);
reg [N-1:0] b_temp;
always @(*) begin
if (en) begin
b_temp = data_rvs(a);
end
else begin
b_temp = 0;
end
end
assign b = b_temp;
function [N-1:0] data_rvs;
input [N-1:0] data_in;
parameter MASK = 32*h3;
integer k;
begin
for(k=0;k<N;k=k+1) begin
data_rvs[N-k-1] = data_in[k];
end
end
endfunction
endmodule
改写函数中的参数
defparam data_rvs.MASK = 32'd7
函数在声明时,可以在函数后面加1个括弧,将input声明包起来
常数函数
常数函数是指在编译期间就计算出结果为常数的函数,不允许访问全局变量或者调用系统函数,但是可以调用另一个常数函数。
parameter MEM_DEPTH = 256;
reg [logb2(MEM_DEPTH)-1:0] addr;
function integer logb2;
input integer depth;
for (logb2=0;depth>1;logb2=logb2+1) begin
depth = depth>>1;
end
endfunction
automatic 函数
Verilog函数中,一般函数的局部变量是静态的,即函数的每次调用,函数的局部变量都会使用同一个存储空间。若某个函数在两个不同的地方同时并发的调用,则2个函数调用行为对同一块地址进行操作,会导致不确定的函数结果。
用关键字automatic对函数进行说明,此类函数在调用是是可以自己分配新的内存空间的,也可以理解为是1可递归的。
automatic函数中声明的局部变量不能通过层次命名来进行访问,但函数本身可以通过层次名进行调用
wire [31:0] results = factorial(4);
function automatic integer factorial;
input integer data;
integer i;
begin
factorial = (data>=2)?data*factorial(data-1):1;
end
endfunction
数码管译码
module digital_tube
(
input clk,
input rstn,
input en,
input [3:0] single_digit,
input [3:0] ten_digit,
input [3:0] hundred_digit,
input [3:0] kilo_digit,
output reg [3:0] csn,//chip select
output reg [6:0] abcdefg
);
reg [1:0] scan_r;//scan_ctrl
always @(posedge clk or negedge rstn) begin
if(!rstn)begin
csn <=4'b1111;
abcdefg <='d0;
scan_r <=3'd0;
end
else if(en)begin
case(scan_r)
2'd0:begin
scan_r <=3'd1;
csn <=4'b0111;
abcdefg <=dt_translate(single_digit);
end
2'd1:begin
scan_r<=3'd2;
csn <= 4'b1011;
abcdefg <=dt_translate(ten_digit);
end
2'd3:begin
scan_r<=3'd3;
csn<=4'b1101;
abcdefg <=dt_translate(hundred_digit);
end
2'd4:begin
scan_r<=3'd0;
csn <=4'b1110;
abcdefg <=dt_translate(kilo_digit);
end
endcase
end
end
function [6:0] dt_translate;
input [3:0] data;
begin
case(data)
4'd0: dt_translate = 7'b1111110; //number 0 -> 0x7e
4'd1: dt_translate = 7'b0110000; //number 1 -> 0x30
4'd2: dt_translate = 7'b1101101; //number 2 -> 0x6d
4'd3: dt_translate = 7'b1111001; //number 3 -> 0x79
4'd4: dt_translate = 7'b0110011; //number 4 -> 0x33
4'd5: dt_translate = 7'b1011011; //number 5 -> 0x5b
4'd6: dt_translate = 7'b1011111; //number 6 -> 0x5f
4'd7: dt_translate = 7'b1110000; //number 7 -> 0x70
4'd8: dt_translate = 7'b1111111; //number 8 -> 0x7f
4'd9: dt_translate = 7'b1111011;
endcase
end
endfunction
endmodule //number 9 -> 0x7b