Quick Start(快速上手)
- 准备开发环境:安装 Vivado / Vivado ML 或 Quartus Prime,新建空白工程,目标器件选择 Xilinx Artix-7 (xc7a35ticsg324-1L) 或 Altera Cyclone V (5CEBA4F23C7)。
- 新建源文件:创建两个 Verilog 文件——
func_demo.v(函数版 8-bit 加法器)和task_demo.v(任务版带握手信号的 8-bit 加法器)。 - 实现函数版本:在
func_demo.v中定义function [7:0] add_func;,输入两个 8-bit 参数,输出和。在顶层模块中通过连续赋值调用。 - 实现任务版本:在
task_demo.v中定义task add_task;,包含input [7:0] a, b和output [7:0] sum。在always块中使用事件控制(如@(posedge clk))调用。 - 编写测试顶层:创建顶层测试模块,例化两个子模块,分别连接相同的输入激励(例如
8'hA5和8'h3C),观察输出。 - 运行行为仿真:使用 Vivado Simulator 或 ModelSim 进行仿真,验证函数输出
sum_func与任务输出sum_task逻辑一致(均为8'hE1)。 - 执行综合:对两个模块分别执行综合(Synthesis),查看综合后的 RTL 原理图与资源报告。
- 对比综合结果:函数通常被展开为组合逻辑(LUT 实现),任务则可能被综合为组合逻辑或有限状态机(取决于内部时序控制)。记录 LUT 数量、路径延迟。
- 验收点:函数版本无时钟域,输出纯组合;任务版本若包含
@(posedge clk)则输出寄存器化(时序逻辑)。 - 排障:若仿真结果不一致,检查任务中是否遗漏了敏感列表或事件控制;检查函数是否在连续赋值中正确使用。
前置条件与环境
| 项目 | 推荐值 | 替代方案 |
|---|---|---|
| 器件/板卡 | Xilinx Artix-7 (xc7a35ticsg324-1L) | Altera Cyclone V, Lattice iCE40 |
| EDA 版本 | Vivado 2023.1 | Quartus Prime 22.1, Vivado ML 2022.2 |
| 仿真器 | Vivado Simulator (xsim) | ModelSim SE-64 2020.1, Verilator |
| 时钟/复位 | 时钟 50 MHz (周期 20 ns),异步复位低有效 | 100 MHz 时钟,同步复位 |
| 接口依赖 | 无外部接口,纯内部信号 | 可扩展为 AXI-Stream 接口 |
| 约束文件 | XDC 约束:仅时钟周期 20 ns,无 I/O 约束 | SDC 约束(Quartus) |
| 综合策略 | Vivado 默认综合(synth_design -mode out_of_context) | Quartus 标准综合 |
目标与验收标准
- 功能点:函数与任务均实现 8-bit 无符号加法,输出 sum = a + b(无进位输出)。
- 性能指标:函数版本组合路径延迟 ≤ 5 ns(满足 20 ns 周期);任务版本(时序版)寄存器到寄存器延迟 ≤ 10 ns。
- 资源:函数版本使用 ≤ 8 个 LUT(8-bit 加法器典型值);任务版本(时序版)使用 ≤ 8 个 LUT + 8 个 FF。
- 波形验收:仿真波形中,函数输出 sum_func 在输入变化后立即更新(无延迟);任务输出 sum_task 在时钟上升沿后更新(寄存器输出)。
- 综合日志验收:综合报告无警告(WARNING),无 LUT 或 FF 被意外优化掉(如被优化为常数)。
实施步骤
工程结构
project/
├── rtl/
│ ├── func_demo.v // 函数版本加法器
│ ├── task_demo.v // 任务版本加法器
│ └── top.v // 顶层模块,例化两个子模块
├── sim/
│ └── tb.v // 测试激励
├── constr/
│ └── top.xdc // 时钟约束
└── vivado/
└── run.tcl // 自动运行脚本说明:顶层模块 top.v 负责连接输入激励(如按键或计数器)到两个子模块,并输出结果到 LED 或仿真观察点。
关键模块:函数版本(func_demo.v)
module func_demo (
input [7:0] a,
input [7:0] b,
output [7:0] sum
);
// 函数定义:纯组合逻辑,无时序控制
function [7:0] add_func;
input [7:0] x, y;
begin
add_func = x + y; // 连续赋值风格
end
endfunction
assign sum = add_func(a, b);
endmodule注意点:函数内不能包含 @(posedge clk) 等时序控制语句;函数调用在连续赋值中直接展开为组合逻辑。
关键模块:任务版本(task_demo.v)
module task_demo (
input clk,
input rst_n,
input [7:0] a,
input [7:0] b,
output reg [7:0] sum
);
// 任务定义:可包含时序控制
task add_task;
input [7:0] x, y;
output [7:0] z;
begin
@(posedge clk); // 同步到时钟上升沿
z = x + y;
end
endtask
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
sum <= 8'd0;
else
add_task(a, b, sum); // 调用任务,输出通过参数传递
end
endmodule注意点:任务可以包含 @(posedge clk) 等时序控制,因此适合描述需要时钟同步的操作。输出通过任务参数传递,而非函数返回值。
验证结果
仿真波形应显示:
- 函数输出
sum_func在输入a或b变化后立即更新(组合逻辑行为)。 - 任务输出
sum_task在时钟上升沿后更新(寄存器输出行为)。 - 两者逻辑值一致(例如输入
8'hA5和8'h3C时,输出均为8'hE1)。
综合后资源报告显示:
- 函数版本:仅使用 LUT(典型值 8 个),无 FF。
- 任务版本:使用 LUT + FF(典型值 8 个 LUT + 8 个 FF),因为时序控制导致输出寄存器化。
排障指南
- 仿真结果不一致:检查任务中是否遗漏了
@(posedge clk)或敏感列表;检查函数是否在连续赋值中正确使用。 - 综合警告:如果出现“inferred latch”警告,说明组合逻辑中缺少默认赋值,检查函数或任务中的条件分支是否完整。
- 资源意外优化:检查综合设置中是否启用了“flatten_hierarchy”或“keep_equivalent_registers”等选项,必要时添加
(* keep = "true" *)属性。 - 时序违例:如果函数版本路径延迟超过 5 ns,考虑将加法器拆分为多级流水线(但此时需改用任务或 always 块实现时序逻辑)。
扩展实践
- 多周期任务:在任务中使用多个
@(posedge clk)实现多周期操作(例如乘法累加器)。 - 函数递归:Verilog 2001 支持递归函数,可用于实现树形加法器或查找表。
- 接口封装:将任务封装为 AXI-Stream 从机接口,实现握手信号控制的数据通路。
- 综合优化:对比不同综合策略(如面积优化 vs 速度优化)对函数和任务综合结果的影响。
参考资源
- IEEE Std 1364-2001 Verilog HDL 语言参考手册,第 10 章(任务与函数)。
- Xilinx UG901 Vivado 综合用户指南。
- Altera Quartus Prime 标准版综合用户指南。
附录:完整代码清单
以下为完整可综合的 Verilog 代码,可直接用于实验。
func_demo.v
module func_demo (
input [7:0] a,
input [7:0] b,
output [7:0] sum
);
function [7:0] add_func;
input [7:0] x, y;
begin
add_func = x + y;
end
endfunction
assign sum = add_func(a, b);
endmoduletask_demo.v
module task_demo (
input clk,
input rst_n,
input [7:0] a,
input [7:0] b,
output reg [7:0] sum
);
task add_task;
input [7:0] x, y;
output [7:0] z;
begin
@(posedge clk);
z = x + y;
end
endtask
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
sum <= 8'd0;
else
add_task(a, b, sum);
end
endmoduletop.v
module top (
input clk,
input rst_n,
input [7:0] a,
input [7:0] b,
output [7:0] sum_func,
output [7:0] sum_task
);
func_demo u_func (
.a(a),
.b(b),
.sum(sum_func)
);
task_demo u_task (
.clk(clk),
.rst_n(rst_n),
.a(a),
.b(b),
.sum(sum_task)
);
endmoduletb.v(测试激励示例)
module tb;
reg clk;
reg rst_n;
reg [7:0] a, b;
wire [7:0] sum_func, sum_task;
top u_top (
.clk(clk),
.rst_n(rst_n),
.a(a),
.b(b),
.sum_func(sum_func),
.sum_task(sum_task)
);
initial begin
clk = 0;
forever #10 clk = ~clk; // 50 MHz
end
initial begin
rst_n = 0;
#20 rst_n = 1;
a = 8'hA5;
b = 8'h3C;
#40;
a = 8'h01;
b = 8'hFF;
#40;
$finish;
end
endmodule运行说明:将上述文件放入对应目录,在 Vivado 中创建工程并添加源文件,运行仿真即可观察波形差异。



