FPGA基础 -- Verilog函数
Verilog 函数(function)
目标:让具备一般 RTL 经验的工程师,系统掌握 Verilog 函数的语法、约束、可综合写法以及在实际项目中的高效用法,为后续 SystemVerilog 及 HLS 设计奠定基础。
1 为什么要用函数?
设计痛点 | 函数带来的价值 |
---|---|
重复逻辑:CRC、Parity、优先编码等往往在多个模块出现 | 将共用运算封装为函数,避免复制粘贴,减少 Bug 概率 |
可读性差:长表达式嵌套写在连线或 always 块中 | 抽象为函数名,表达意图清晰 |
调试困难:一段组合逻辑难以单独仿真 | 函数可在 Testbench 中独立调用并加断言 |
2 语法与基本规则
function [宽度-1:0] fname;input [m-1:0] a, b; // 只能是 input 端口reg [宽度-1:0] tmp; // 必须声明内部寄存器
begintmp = a ^ b;fname = tmp; // 赋值给同名变量或用 return
end
endfunction
要点
-
单返回值:函数名本身是返回寄存器;SystemVerilog 可用
return
。 -
无时序控制:禁止
#
延时、@
事件,否则综合器会报错(仅仿真可用)。 -
端口方向:只能
input
,无output/inout
。 -
侧 射(Side Effect)禁止:函数内部不能写模块外部信号。
-
调用环境:
- 连续赋值:
assign y = myfunc(a,b);
- 过程块:
always @* begin result = myfunc(a,b); end
- 参数化:
parameter W=8; function [W-1:0] …
- 连续赋值:
3 与 task 的区别
维度 | function | task |
---|---|---|
返回值 | 必须且只有一个 | 可无返回,用端口输出 |
端口方向 | 仅 input | input/out/inout 均可 |
时序控制 | 禁止 #、@、wait | 允许 |
并行执行 | 无 fork/join | 可包含 |
适用场景 | 纯组合运算 | 时序操作、仿真刺激 |
4 自动(automatic)与静态(static)
-
默认 static:所有调用共享同一套局部变量,递归或并发调用会冲突。
-
automatic function
为 可重入/递归,每次调用独立栈帧。某些综合工具对递归支持有限,实际项目常用“尾递归 + 显式栈”改写。
5 SystemVerilog 扩展亮点
特性 | 价值 |
---|---|
完整数据类型:logic , bit , enum , struct , union | 写法更接近 C/C++,可编译时静态检查 |
默认自动:省去 static 纠结;支持 return 语句 | 代码可读性更佳 |
package 作用域:跨模块复用无需 include | 大型项目库化管理 |
内建 dpi_c/dpi_import | C-function 与 RTL 交互 |
6 可综合函数设计模式
6.1 组合运算模板
function automatic [7:0] parity8;input [7:0] data;
beginparity8 = ^data; // XOR 归约
end
endfunction
合成结果:1-级 XOR 逻辑;工具可再平衡以满足时序。
6.2 参数化优先编码器
function automatic [N-1:0] prio_enc;input [M-1:0] req; // M 为参数integer i;
beginprio_enc = '0;for (i=M-1; i>=0; i=i-1)if (req[i]) prio_enc = i[N-1:0];
end
endfunction
- for 循环被展开成优先链;结合流水线可提升频率。
N = $clog2(M);
使用 SystemVerilog 的$clog2
系统函数。
6.3 带符号定点乘法(避免乘法器爆发)
用函数统一封装小位宽 signed
乘加,可让综合器推断 DSP Slice。
7 调试与验证技巧
- 函数级仿真:在 TB 中直接
#0 $display("crc=%h", crc16(pkt));
。 - 覆盖率:UVM 中可为函数添加 covergroup 监测输入分布。
- ILA 观测:将函数输出打一拍寄存后接 ILA,确认硬件值。
- 断言:
assert (func_out == golden_model(in));
在线比对。
8 常见综合 Pitfall Checklist
问题 | 规避方案 |
---|---|
在函数内写外部 reg | 仅返回值,再在调用处赋外部 reg |
引入 #1 做仿真 delay | 用 ifdef SYNTH 宏分离仿真逻辑 |
使用 $display 、$random | 同上,或包在 synthesis off/on 区段 |
递归深度不定 | 改写成 for 循环 + 寄存器/堆栈 |
9 练习与进阶读物
-
练习
- 实现 CRC-32、Gray 编码转换、位反转函数,并用 QuestSim 仿真。
- 将一个 3×3 Sobel 算子的卷积核写成函数,约束综合后查看 LUT 利用率。
-
推荐书籍
书名 章节 Digital Design & Verilog HDL (Charles Roth) Ch5 Functions & Tasks SystemVerilog for Design (Suthar, Simpson) 3.10 Functional Constructs FPGA Prototyping by Verilog Examples (Pong P. Chu) Labs 4-7
10 培训路线图(6 小时工作坊示例)
时间 | 模块 | 目标 |
---|---|---|
1 h | 函数 vs Task,语法规则 | 能写出合法函数 |
1 h | 可综合写法、示例讲解 | 明确 prohibit 特性 |
1.5 h | SystemVerilog 扩展 | 掌握 package/return/logic |
0.5 h | 工具演示 (Vivado & ModelSim) | 从编辑到时序报告 |
1 h | 实战 Lab:优先编码器/CRC | 独立编码 + 波形分析 |
1 h | Q&A + 代码 Review | 固化最佳实践 |
结语
Verilog 函数看似简单,却是构建 可重用、易维护、高性能 RTL 库 的基础。掌握语法约束只是第一步,更重要的是在 抽象层次、综合友好度与可验证性 之间找到平衡。通过系统化训练与大量实战,你将能将函数运用到参数化 IP、算法流水线、甚至高层 HLS 模型中,显著提升 FPGA 开发效率与设计质量。