Verilog语法之函数function的讲解

2023-12-13 04:32:44

function讲解:

在verilog语言中,函数与任务是可综合的。

可以用function与task,将重复性的行为级设计(就是rtl描述)进行提取,并在多个地方调用,来避免重复代码的多次编写,可使代码更加的简洁易懂。

函数特点说明:

  1. 函数只能在模块内部,任意位置,定义与使用。作用范围也仅限于此模块;
  2. 不能有任何延迟,时序或者时序逻辑控制;
  3. 至少有一个输入变量;
  4. 只有一个返回值,没有输出;
  5. 不能含有非阻塞赋值语句;
  6. 函数可以调用其他函数,不能调用任务。

函数定义格式:

?

? // ?定义格式:

? ? function [range-1:0] ? ?function_id ? ? ? ? ; ? // 没有输出但是有一个返回值,就是这个函数名称(function_id),range 定义位宽。

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? // 函数的返回值通过这个变量进行传递。当该寄存器变量没有指定位宽时,默认位宽为 1。

? ? ? ? input ? ? ? ? ? ? ? input_declaration ? ; ? // 输入端口。可以有多个输入。

? ? ? ? ? ? ? ? ? ? ? ? ? ? other_declaration ? ; ? // 其他描述

? ? ? ? ? ? ? ? ? ? ? ? ? ? procedural_statement; ? // 工序过程要素

? ? endfunction

函数调用格式:


? ? // 函数调用格式:

? ? function_id(input_data1, input_data2);

下面用函数实现一个数据大小端转换的功能:

// 大小端转换,就是把低位变高位,高位变低位。

module endian_rvs #(parameter N = 4) (

? ? input ? ? ? wire ? ? ? ? ? ? ? ? ? ?en ?, ? //enable control

? ? input ? ? ? wire ? ?[N-1:0] ? ? ? ? a ? ,

? ? output ? ? ?wire ? ?[N-1:0] ? ? ? ? b

?);

? ? // reg signal descrioption

? ? 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 entity

? ? function ? ? ? ? ? ?[N-1:0] ? ? data_rvs ? ? ? ?;

? ? ? ? input ? ?wire ? ?[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 ;

函数声明还可以在函数名称后面加上括号,把输入端口包含进入:

function [N-1:0]???? data_rvs(

input???? [N-1:0] data_in

??? ......

) ;

常数函数:

什么是常数函数:

在仿真开始之前,在编译期间就计算出结果为常数的函数。常数函数不允许访问全局变量或者调用系统函数,但可以调用另一个常数函数。

parameter ? ?MEM_DEPTH = 256 ;

reg ?[logb2(MEM_DEPTH)-1: 0] addr ; //可得addr的宽度为8bit

?

? ? function integer ? ? logb2;

? ? input integer ? ? depth ;

? ? ? ? //256为9bit,我们最终数据应该是8,所以需depth=2时提前停止循环

? ? for(logb2=0; depth>1; logb2=logb2+1) begin

? ? ? ? depth = depth >> 1 ;

? ? end

endfunction

automatic 函数:

用得很少。

在 Verilog 中,一般函数的局部变量是静态的,即函数的每次调用,函数的局部变量都会使用同一个存储空间。若某个函数在两个不同的地方同时并发的调用,那么两个函数调用行为同时对同一块地址进行操作,会导致不确定的函数结果。

Verilog 用关键字 automatic 来对函数进行说明,此类函数在调用时是可以自动分配新的内存空间的,也可以理解为是可递归的。因此,automatic 函数中声明的局部变量不能通过层次命名进行访问,但是 automatic 函数本身可以通过层次名进行调用。

文章来源:https://blog.csdn.net/Meng_long2022/article/details/134959451
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。