Verilog函数function

在 Verilog 中,**function**用于定义可重用的代码块,这些代码块执行计算并返回一个值。函数在仿真时间 0 时执行,不消耗仿真时间。

一、基本语法

复制代码
function [range] function_name;
    input declarations;
    other variable declarations;
    begin
        // 函数体
        function_name = expression;  // 返回值赋值
    end
endfunction

// 或者使用 ANSI C 风格
function [range] function_name (input declarations);
    other variable declarations;
    begin
        // 函数体
        function_name = expression;
    end
endfunction

二、使用示例

1. 基本函数定义和使用

复制代码
module math_operations;
    
    // 计算两个数的最大值
    function integer max;
        input integer a, b;
        begin
            if (a > b)
                max = a;
            else
                max = b;
        end
    endfunction
    
    // 计算阶乘
    function integer factorial;
        input integer n;
        integer i;
        begin
            factorial = 1;
            for (i = 2; i <= n; i = i + 1)
                factorial = factorial * i;
        end
    endfunction
    
    // 使用函数
    initial begin
        integer x = 10, y = 20;
        integer result;
        
        result = max(x, y);
        $display("Max of %0d and %0d is %0d", x, y, result);
        
        result = factorial(5);
        $display("5! = %0d", result);
    end

endmodule

2. 位向量操作函数

复制代码
module bit_operations;
    
    // 计算位向量中 1 的个数(人口计数)
    function integer pop_count;
        input [31:0] data;
        integer i;
        begin
            pop_count = 0;
            for (i = 0; i < 32; i = i + 1)
                if (data[i])
                    pop_count = pop_count + 1;
        end
    endfunction
    
    // 字节序转换(大端小端转换)
    function [31:0] endian_swap;
        input [31:0] data;
        begin
            endian_swap = {data[7:0], data[15:8], data[23:16], data[31:24]};
        end
    endfunction
    
    // 位反转
    function [31:0] bit_reverse;
        input [31:0] data;
        integer i;
        begin
            for (i = 0; i < 32; i = i + 1)
                bit_reverse[i] = data[31-i];
        end
    endfunction
    
    initial begin
        reg [31:0] test_data = 32'h12345678;
        
        $display("Original data: %h", test_data);
        $display("Population count: %0d", pop_count(test_data));
        $display("Endian swapped: %h", endian_swap(test_data));
        $display("Bit reversed: %h", bit_reverse(test_data));
    end

endmodule

三、函数特性

1. 返回值类型

复制代码
module function_types;
    
    // 返回位向量
    function [7:0] byte_to_ascii;
        input [3:0] nibble;
        begin
            if (nibble <= 4'h9)
                byte_to_ascii = "0" + nibble;
            else
                byte_to_ascii = "A" + (nibble - 4'hA);
        end
    endfunction
    
    // 返回实数
    function real celsius_to_fahrenheit;
        input real celsius;
        begin
            celsius_to_fahrenheit = (celsius * 9.0 / 5.0) + 32.0;
        end
    endfunction
    
    // 返回时间
    function time calculate_timeout;
        input integer cycles;
        input real clock_period;
        begin
            calculate_timeout = cycles * clock_period;
        end
    endfunction
    
    initial begin
        $display("ASCII of 4'hA: %s", byte_to_ascii(4'hA));
        $display("25°C = %0.1f°F", celsius_to_fahrenheit(25.0));
        $display("Timeout: %0t", calculate_timeout(100, 10.0));
    end

endmodule

2. 自动函数

复制代码
module automatic_functions;
    
    // 自动函数 - 每次调用都有独立的存储空间
    function automatic integer recursive_factorial;
        input integer n;
        begin
            if (n <= 1)
                recursive_factorial = 1;
            else
                recursive_factorial = n * recursive_factorial(n-1);
        end
    endfunction
    
    // 自动函数的局部变量
    function automatic [7:0] fibonacci;
        input integer n;
        integer i;
        reg [7:0] a, b, temp;
        begin
            if (n == 0)
                fibonacci = 0;
            else if (n == 1)
                fibonacci = 1;
            else begin
                a = 0;
                b = 1;
                for (i = 2; i <= n; i = i + 1) begin
                    temp = a + b;
                    a = b;
                    b = temp;
                end
                fibonacci = b;
            end
        end
    endfunction
    
    initial begin
        $display("5! = %0d", recursive_factorial(5));
        $display("Fibonacci(10) = %0d", fibonacci(10));
    end

endmodule

四、实际应用场景

1. 数据校验函数

复制代码
module data_checker;
    
    // 计算奇偶校验位
    function parity_bit;
        input [7:0] data;
        integer i;
        begin
            parity_bit = 0;
            for (i = 0; i < 8; i = i + 1)
                parity_bit = parity_bit ^ data[i];
        end
    endfunction
    
    // 计算简单的校验和
    function [7:0] checksum;
        input [7:0] data [];
        integer i;
        begin
            checksum = 0;
            for (i = 0; i < data.size(); i = i + 1)
                checksum = checksum + data[i];
        end
    endfunction
    
    // CRC 计算(简化版)
    function [15:0] crc16;
        input [7:0] data;
        input [15:0] current_crc;
        integer i;
        begin
            crc16 = current_crc;
            for (i = 0; i < 8; i = i + 1) begin
                crc16 = (crc16 << 1) ^ (((crc16 >> 15) ^ (data >> (7-i))) ? 16'h1021 : 0);
            end
        end
    endfunction

endmodule

2. 协议处理函数

复制代码
module protocol_processor;
    
    // 提取 IP 包头部字段
    function [3:0] get_ip_version;
        input [31:0] ip_header;
        begin
            get_ip_version = ip_header[31:28];
        end
    endfunction
    
    function [3:0] get_header_length;
        input [31:0] ip_header;
        begin
            get_header_length = ip_header[27:24];
        end
    endfunction
    
    function [15:0] get_total_length;
        input [31:0] ip_header;
        begin
            get_total_length = ip_header[15:0];
        end
    endfunction
    
    // 验证 IP 头校验和
    function is_valid_ip_header;
        input [319:0] ip_header;  // 假设 10 * 32bit IP 头
        integer i;
        reg [31:0] sum;
        begin
            sum = 0;
            for (i = 0; i < 10; i = i + 1) begin
                if (i != 5) begin  // 跳过校验和字段
                    sum = sum + ip_header[i*32+:16] + ip_header[i*32+16+:16];
                end
            end
            // 处理进位
            while (sum[31:16])
                sum = sum[31:16] + sum[15:0];
            is_valid_ip_header = (sum[15:0] == 16'hFFFF);
        end
    endfunction

endmodule

3. 数学运算函数

复制代码
module dsp_functions;
    
    // 定点数乘法
    function [31:0] fixed_point_mult;
        input [15:0] a, b;
        input [3:0] fractional_bits;
        begin
            fixed_point_mult = (a * b) >> fractional_bits;
        end
    endfunction
    
    // 饱和加法
    function [15:0] saturated_add;
        input [15:0] a, b;
        reg [16:0] temp;
        begin
            temp = a + b;
            if (temp[16])  // 溢出
                saturated_add = 16'hFFFF;
            else
                saturated_add = temp[15:0];
        end
    endfunction
    
    // 查找表插值
    function [15:0] linear_interpolate;
        input [15:0] x0, x1, y0, y1;
        input [15:0] x;
        real slope, result;
        begin
            if (x1 == x0) begin
                linear_interpolate = y0;
            end else begin
                slope = (y1 - y0) / (x1 - x0);
                result = y0 + slope * (x - x0);
                // 转换回定点数
                linear_interpolate = result;
            end
        end
    endfunction
    
    initial begin
        reg [15:0] a = 16'h1000, b = 16'h0800;  // Q12 格式
        reg [15:0] result;
        
        result = fixed_point_mult(a, b, 12);
        $display("Fixed point multiply: %h * %h = %h", a, b, result);
        
        result = saturated_add(16'hFFFF, 16'h0001);
        $display("Saturated add: FFFF + 0001 = %h", result);
    end

endmodule

五、高级用法

1. 函数重载

复制代码
module function_overloading;
    
    // 不同数据类型的绝对值函数
    function integer abs_int;
        input integer value;
        begin
            abs_int = (value < 0) ? -value : value;
        end
    endfunction
    
    function real abs_real;
        input real value;
        begin
            abs_real = (value < 0.0) ? -value : value;
        end
    endfunction
    
    function [31:0] abs_fixed;
        input [31:0] value;
        begin
            abs_fixed = value[31] ? (~value + 1) : value;
        end
    endfunction
    
    initial begin
        $display("abs_int(-5) = %0d", abs_int(-5));
        $display("abs_real(-3.14) = %0.2f", abs_real(-3.14));
        $display("abs_fixed(-10) = %0d", abs_fixed(-10));
    end

endmodule

2. 递归函数

复制代码
module recursive_functions;
    
    // 递归计算最大公约数
    function automatic integer gcd;
        input integer a, b;
        begin
            if (b == 0)
                gcd = a;
            else
                gcd = gcd(b, a % b);
        end
    endfunction
    
    // 递归计算幂运算
    function automatic real power;
        input real base;
        input integer exponent;
        begin
            if (exponent == 0)
                power = 1.0;
            else if (exponent < 0)
                power = 1.0 / power(base, -exponent);
            else
                power = base * power(base, exponent - 1);
        end
    endfunction
    
    initial begin
        $display("GCD of 48 and 18: %0d", gcd(48, 18));
        $display("2^8 = %0.0f", power(2.0, 8));
        $display("2^-3 = %0.3f", power(2.0, -3));
    end

endmodule

3. 数组处理函数

复制代码
module array_functions;
    
    // 查找数组中的最大值
    function integer find_max;
        input integer arr [];
        integer i;
        begin
            find_max = arr[0];
            for (i = 1; i < arr.size(); i = i + 1) begin
                if (arr[i] > find_max)
                    find_max = arr[i];
            end
        end
    endfunction
    
    // 数组求和
    function integer array_sum;
        input integer arr [];
        integer i;
        begin
            array_sum = 0;
            for (i = 0; i < arr.size(); i = i + 1)
                array_sum = array_sum + arr[i];
        end
    endfunction
    
    // 数组排序(冒泡排序)
    function automatic void bubble_sort;
        inout integer arr [];
        integer i, j, temp;
        begin
            for (i = 0; i < arr.size() - 1; i = i + 1) begin
                for (j = 0; j < arr.size() - i - 1; j = j + 1) begin
                    if (arr[j] > arr[j+1]) begin
                        temp = arr[j];
                        arr[j] = arr[j+1];
                        arr[j+1] = temp;
                    end
                end
            end
        end
    endfunction
    
    initial begin
        integer numbers [0:4] = '{5, 2, 8, 1, 9};
        
        $display("Original array: %p", numbers);
        $display("Max value: %0d", find_max(numbers));
        $display("Sum: %0d", array_sum(numbers));
        
        bubble_sort(numbers);
        $display("Sorted array: %p", numbers);
    end

endmodule

六、函数限制和最佳实践

1. 函数限制

复制代码
module function_limitations;
    
    // 函数不能包含时间控制 (#, @)
    function integer bad_function;
        input integer a;
        begin
            #10;  // 错误:函数中不能有时延
            bad_function = a;
        end
    endfunction
    
    // 函数不能调用任务
    function integer another_bad_function;
        input integer a;
        begin
            $display("Hello");  // 错误:函数不能调用系统任务
            another_bad_function = a;
        end
    endfunction
    
    // 正确的方式
    function integer good_function;
        input integer a;
        begin
            good_function = a * 2;
        end
    endfunction

endmodule

2. 最佳实践

复制代码
module best_practices;
    
    // 1. 使用有意义的函数名
    function calculate_circle_area;
        input real radius;
        begin
            calculate_circle_area = 3.14159 * radius * radius;
        end
    endfunction
    
    // 2. 添加输入验证
    function integer safe_divide;
        input integer a, b;
        begin
            if (b == 0) begin
                $warning("Division by zero attempted");
                safe_divide = 0;
            end else begin
                safe_divide = a / b;
            end
        end
    endfunction
    
    // 3. 文档注释
    // ================================
    // 函数: hamming_distance
    // 描述: 计算两个位向量之间的汉明距离
    // 输入: 
    //   a, b - 要比较的位向量
    // 返回: 汉明距离(不同的位数)
    // ================================
    function integer hamming_distance;
        input [31:0] a, b;
        integer i, distance;
        begin
            distance = 0;
            for (i = 0; i < 32; i = i + 1) begin
                if (a[i] !== b[i])
                    distance = distance + 1;
            end
            hamming_distance = distance;
        end
    endfunction
    
    // 4. 合理的返回值类型
    function [7:0] clamp_to_byte;
        input integer value;
        begin
            if (value < 0)
                clamp_to_byte = 0;
            else if (value > 255)
                clamp_to_byte = 255;
            else
                clamp_to_byte = value;
        end
    endfunction

endmodule

七、函数 vs 任务

特性 函数 (function) 任务 (task)
返回值 必须返回一个值 可以不返回值
时间控制 不允许 允许
调用任务 不允许 允许
执行时间 零时间 可以消耗时间
用途 计算 复杂操作

函数是 Verilog 中实现复杂计算和代码重用的重要工具,合理使用函数可以大大提高代码的可读性和可维护性。

相关推荐
weixin_4997715511 分钟前
C++中的组合模式
开发语言·c++·算法
初级代码游戏11 分钟前
套路化编程 C# winform 自适应缩放布局
开发语言·c#·winform·自动布局·自动缩放
_waylau15 分钟前
鸿蒙架构师修炼之道-架构师的职责是什么?
开发语言·华为·harmonyos·鸿蒙
2的n次方_26 分钟前
CANN Ascend C 编程语言深度解析:异构并行架构、显式存储层级与指令级精细化控制机制
c语言·开发语言·架构
java干货1 小时前
为什么 “File 10“ 排在 “File 2“ 前面?解决文件名排序的终极算法:自然排序
开发语言·python·算法
_F_y1 小时前
C语言重点知识总结(含KMP详细讲解)
c语言·开发语言
毕设源码-郭学长1 小时前
【开题答辩全过程】以 基于python的二手房数据分析与可视化为例,包含答辩的问题和答案
开发语言·python·数据分析
无小道1 小时前
Qt——常用控件
开发语言·qt
aini_lovee2 小时前
MATLAB基于小波技术的图像融合实现
开发语言·人工智能·matlab
R1nG8632 小时前
多线程安全设计 CANN Runtime关键数据结构的锁优化
开发语言·cann