Quick Start
- 安装Vivado:下载并安装Vivado 2024.2或更高版本(推荐2025.1或2026.1预览版),确保包含Vivado Simulator和Vivado Synthesis。
- 创建工程:启动Vivado,选择“RTL Project”,目标器件设为Xilinx Artix-7 XC7A35T(如Nexys A7或Basys 3开发板)。添加一个Verilog顶层模块,命名为
top.v。 - 编写计数器代码:实现一个4位计数器,包含时钟(clk)、异步复位(rst_n,低有效)和使能(en)输入,输出到4个LED(led[3:0])。具体代码见下文。
- 编写Testbench并仿真:创建测试模块,实例化计数器,提供100 MHz时钟(周期10 ns)和复位序列。运行行为仿真(Simulation → Run Behavioral Simulation),观察计数波形从0到15循环。
- 综合与实现:点击“Run Synthesis”,成功后点击“Run Implementation”。查看时序报告(Report Timing Summary),确认最差负时序余量(WNS)≥ 0,无setup/hold违规。
- 生成比特流并下载:点击“Generate Bitstream”,成功后打开硬件管理器(Open Target → Auto Connect),选择比特文件并点击“Program”。观察板载LED按二进制递增闪烁,频率约1 Hz(若使用100 MHz时钟经2^28分频)。
前置条件与环境
| 项目 | 推荐值/说明 | 替代方案 |
|---|---|---|
| 器件/板卡 | Xilinx Artix-7 XC7A35T(如Nexys A7或Basys 3) | Intel Cyclone V(Quartus Prime)或Lattice iCE40(iCEcube2) |
| EDA版本 | Vivado 2024.2 或 2025.1 | Vivado 2023.x(部分IP核不兼容) |
| 仿真器 | Vivado Simulator(xsim) | ModelSim/Questa、Verilator(仅仿真) |
| 时钟/复位 | 板载100 MHz差分或单端时钟;异步低有效复位 | 外部晶振+PLL生成 |
| 接口依赖 | 至少4个LED输出,1个按键复位 | 可用串口或PMOD扩展 |
| 约束文件 | XDC约束:时钟周期、I/O引脚分配、false path | SDC(Intel)或LDC(Lattice) |
| 操作系统 | Windows 10/11 64位 或 Ubuntu 20.04/22.04 | CentOS 7(需额外库) |
目标与验收标准
- 功能点:实现一个带同步使能和异步复位的4位计数器,输出到4个LED。每2^28个时钟周期进位一次(约1 Hz闪烁)。
- 性能指标:在100 MHz时钟下,时序收敛(WNS ≥ 0),无setup/hold违规。
- 资源占用:FF ≤ 10,LUT ≤ 20(典型值,依分频器位宽而定)。
- 验收方式:
实施步骤
阶段1:工程结构与顶层模块
创建Vivado工程,选择RTL Project,添加源文件top.v和约束文件top.xdc。顶层模块定义如下:
module top (
input clk,
input rst_n,
input en,
output reg [3:0] led
);
// 内部例化分频器和计数器(为简化,可将分频与计数合并)
endmodule阶段2:关键模块——计数器与分频器
module counter (
input clk,
input rst_n,
input en,
output reg [3:0] count
);
reg [27:0] div; // 28-bit分频器
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
div <= 0;
count <= 0;
end else if (en) begin
if (div == 28'd24999999) begin // 100MHz / 50M = 2Hz, 再二分频得1Hz
div <= 0;
count <= count + 1;
end else begin
div <= div + 1;
end
end
end
endmodule逐行说明
- 第1行:模块声明,端口包括时钟(clk)、异步复位(rst_n,低有效)、使能(en)和4位输出(count)。
- 第2行:分频寄存器div,位宽28位,用于从100 MHz产生约1 Hz使能脉冲。
- 第3行:敏感列表,上升沿时钟和下降沿复位(低有效)。
- 第4行:异步复位条件:当rst_n为低时,分频器和计数器清零。
- 第5-6行:复位赋值:div和count均置为0。
- 第7行:使能有效时(en为高),执行分频逻辑。
- 第8行:判断div是否达到24,999,999(50M-1),即50M个时钟周期(0.5秒),产生2 Hz脉冲。
- 第9-10行:达到条件时,div归零,count加1(每0.5秒变化一次,LED闪烁频率1 Hz)。
- 第11-12行:否则div递增。
- 注意:实际LED闪烁频率为count变化频率的一半(count每0.5秒翻转一次,LED亮灭周期1秒)。
阶段3:时序约束与CDC
# top.xdc
create_clock -period 10.000 -name sysclk [get_ports clk]
set_property PACKAGE_PIN W5 [get_ports clk]
set_property IOSTANDARD LVCMOS33 [get_ports clk]
set_property PACKAGE_PIN U18 [get_ports rst_n]
set_property IOSTANDARD LVCMOS33 [get_ports rst_n]
set_property PACKAGE_PIN V17 [get_ports {led[0]}]
...
set_false_path -from [get_ports rst_n] # 异步复位,不需时序检查逐行说明
- 第1行:定义主时钟周期10 ns(100 MHz),命名为sysclk。
- 第2-3行:指定时钟引脚位置(W5)和电平标准(LVCMOS33),以Nexys A7为例。
- 第4-5行:复位引脚约束:引脚U18,电平标准LVCMOS33。
- 第6行:LED引脚示例(实际需根据板卡原理图填写全部4个)。
- 第8行:设置false path,避免Vivado对异步复位信号进行时序分析(因复位与时钟域无关)。
阶段4:验证——Testbench与仿真
module tb_counter;
reg clk, rst_n, en;
wire [3:0] count;
counter uut (.clk(clk), .rst_n(rst_n), .en(en), .count(count));
initial begin
clk = 0;
forever #5 clk = ~clk; // 100 MHz
end
initial begin
rst_n = 0;
en = 0;
#20 rst_n = 1;
#10 en = 1;
#5000 $finish;
end
endmodule逐行说明
- 第1行:测试模块声明,名称为tb_counter。
- 第2行:声明激励信号clk、rst_n、en(reg类型)和输出count(wire类型)。
- 第3行:例化被测试模块counter,端口连接。
- 第4-6行:生成100 MHz时钟:初始值为0,每5 ns翻转一次。
- 第7-9行:复位序列:先复位20 ns(rst_n=0),释放后10 ns使能(en=1),然后运行5000 ns后结束仿真。
常见坑与排查
- 坑1:仿真无波形变化——检查Testbench中是否忘记释放复位(rst_n保持低)。
- 坑2:综合后时序违规——分频器位宽过大导致组合路径过长;可增加流水线或使用计数器分频。
- 坑3:上板LED不亮——检查XDC引脚分配是否正确;确认比特流已下载且板卡供电正常。
原理与设计说明
本设计采用同步使能+异步复位架构,这是FPGA设计的标准模式。异步复位确保上电瞬间电路进入已知状态,而同步使能避免毛刺。分频器使用计数器而非PLL,因为1 Hz频率对抖动不敏感,且节省PLL资源。关键trade-off在于分频器位宽:28位计数器在100 MHz下翻转一次需约2.68秒,但若直接输出到LED,LED闪烁频率为0.186 Hz(约5.4秒周期),不符合1 Hz要求。因此我们使用div == 24,999,999产生2 Hz脉冲,再经count二分频得到1 Hz。若追求更低资源,可使用PLL输出低频时钟,但需注意跨时钟域处理。
验证与结果
| 指标 | 测量条件 | 典型值 |
|---|---|---|
| Fmax | Vivado 2025.1, Artix-7 -1速度级 | ≥ 200 MHz(示例) |
| FF占用 | 28位分频器+4位计数器 | 32个FF(示例) |
| LUT占用 | 同上 | 18个LUT(示例) |
| LED闪烁频率 | 示波器测量或目测 | 1 Hz ± 1% |
| 时序余量(WNS) | 100 MHz约束 | ≥ 0.5 ns(示例) |
注意:以上数值为典型示例,实际以具体工程和数据手册为准。
故障排查(Troubleshooting)
- 现象:仿真中count不变化 → 原因:en一直为0或复位未释放 → 检查Testbench中en赋值和复位时序。
- 现象:综合报错“Unresolved reference” → 原因:模块名或端口不匹配 → 检查例化名称和参数。
- 现象:实现后时序违规 → 原因:分频器组合逻辑过长 → 增加流水线或使用专用计数器IP。
- 现象:上板后LED常亮或常灭 → 原因:复位信号未正确连接或电平反相 → 检查XDC中rst_n引脚和板卡原理图。
- 现象:比特流下载失败 → 原因:FPGA型号不匹配或JTAG驱动问题 → 确认器件型号,重新安装驱动。
- 现象:仿真波形出现毛刺 → 原因:组合逻辑输出未寄存 → 在always块中赋值给reg类型即可。
- 现象:Vivado卡在Synthesis → 原因:代码中有死循环或无限综合指令 → 检查generate语句或for循环边界。
- 现象:LED闪烁频率不对 → 原因:分频常数计算错误 → 重新计算div比较值(时钟频率/目标频率/2 - 1)。
扩展与下一步
- 参数化设计:使用parameter定义分频系数和计数器位宽,便于复用。
- 增加PLL:用MMCM生成精确时钟,减少分频器资源,但需处理跨时钟域。
- 加入UART输出:将计数值通过串口打印,便于调试。
- 形式验证:使用SymbiYosys或Vivado Formal验证计数器行为。
- 性能优化:将分频器改为二进制计数器+比较器,或使用LUT实现分频。
- 跨平台移植:将代码移植到Intel Quartus或Lattice iCEcube2,注意复位极性差异。
参考与信息来源
- Xilinx UG901: Vivado Design Suite User Guide (Synthesis)
- Xilinx UG903: Vivado Design Suite User Guide (Implementation)
- Xilinx UG949: Vivado Design Suite User Guide (Methodology)
- “Verilog HDL: A Guide to Digital Design and Synthesis” by Samir Palnitkar
- “FPGA Prototyping by Verilog Examples” by Pong P. Chu
技术附录
术语表
- WNS:Worst Negative Slack,最差负时序余量,≥0表示时序收敛。
- FF:Flip-Flop,触发器。
- LUT:Look-Up Table,查找表。
- CDC:Clock Domain Crossing,跨时钟域。
- XDC:Xilinx Design Constraints,Xilinx约束文件。
检查清单
- □ 代码无语法错误(综合通过)
- □ 仿真波形符合预期
- □ XDC约束完整(时钟、引脚、false path)
- □ 时序报告WNS ≥ 0
- □ 上板现象正确
关键约束速查
# 时钟约束
create_clock -period 10.000 -name sysclk [get_ports clk]
# 异步复位false path
set_false_path -from [get_ports rst_n]
# 输出延迟(可选)
set_output_delay -clock sysclk -max 4.0 [get_ports led*]以上内容基于2026年Q2主流工具链,适用于FPGA入门者从零开始构建第一个可上板的数字设计。建议结合官方文档和实验板卡进行实践。




