FPGA线上课程平台|最全栈的FPGA学习平台|FPGA工程师认证培训
登录
首页-技术文章/快讯-技术分享-正文

FPGA入门实践:从组合逻辑到时序逻辑的Verilog设计指南

二牛学FPGA二牛学FPGA
技术分享
12小时前
0
0
7

Quick Start

  • 步骤1:安装环境 下载并安装 Vivado 2025.2(或更高版本),确保包含仿真器(XSIM)。
  • 步骤2:创建工程 打开 Vivado → Quick Start → Create Project → 选择器件(如 xc7a35tcsg324-1)→ Finish。
  • 步骤3:编写组合逻辑模块 新建 Design Sources → 写一个 2 选 1 多路选择器(见下方代码)。
  • 步骤4:仿真验证组合逻辑 新建 Simulation Sources → 写 testbench → Run Simulation → 观察波形确认输出正确。
  • 步骤5:加入时序逻辑 在同一个模块中增加一个 D 触发器输出,形成“组合+时序”混合设计。
  • 步骤6:综合与实现 点击 Synthesis → Run Synthesis → 查看资源报告;再 Run Implementation → 查看时序报告(WNS ≥ 0)。
  • 步骤7:上板验证(可选) 生成 Bitstream → 下载到 FPGA 开发板,观察 LED 响应按键/拨码开关。

前置条件与环境

项目推荐值说明替代方案
FPGA 器件Xilinx Artix-7 (xc7a35tcsg324-1)其他 7 系列或 Spartan-7;Altera Cyclone V 也可(需对应 Quartus)
EDA 版本Vivado 2025.2(示例)Vivado 2024.x / 2026.x;Vitis 仅用于嵌入式,非必需
仿真器Vivado XSIM(内置)ModelSim / Questa / Verilator(需额外配置)
时钟/复位板载 50 MHz 有源晶振;低电平复位(按键)可改用 PLL 分频;高电平复位需调整逻辑
接口依赖至少 2 个拨码开关(输入)、1 个 LED(输出)无板卡时仅做仿真
约束文件XDC 文件:定义时钟周期(create_clock -period 20.0 [get_ports clk])无约束时综合仍可运行,但时序分析不准确

目标与验收标准

  • 功能点:实现一个 2 选 1 多路选择器(组合逻辑),其输出经过 D 触发器寄存(时序逻辑),最终驱动 LED。
  • 性能指标:系统时钟频率 ≥ 50 MHz(即周期 20 ns),建立时间余量(WNS)≥ 0。
  • 资源占用:LUT ≤ 4 个,FF ≤ 2 个(典型值;实际因综合策略略有差异)。
  • 仿真验收:testbench 中,输入变化后组合输出立即响应,时序输出在时钟上升沿后一个时钟周期才更新。
  • 上板验收:拨码开关改变输入,LED 在下一个时钟沿反映新值,无毛刺或闪烁。

实施步骤

阶段一:工程结构与顶层模块

在 Vivado 中创建工程,添加一个顶层模块 top_mux_dff,包含时钟 clk、复位 rst_n、两个输入 ab、选择信号 sel、输出 led。端口方向:clkrst_nabsel 为 input;led 为 output reg(因为时序逻辑赋值)。常见坑:忘记将 led 声明为 reg 类型会导致综合错误;时钟和复位必须显式连接到顶层端口。

阶段二:组合逻辑模块(多路选择器)

// 2-to-1 multiplexer (combinational)
module mux2to1 (
 input wire a,
 input wire b,
 input wire sel,
 output wire y
);
 assign y = sel ? b : a;
endmodule

逐行说明

  • 第 1 行:注释,说明模块功能为 2 选 1 多路选择器,纯组合逻辑。
  • 第 2 行:模块声明,名称为 mux2to1,与文件名建议一致。
  • 第 3–5 行:端口声明,全部为 input wire,因为组合逻辑输入不需要存储。
  • 第 6 行:输出 y 声明为 output wire,因为使用 assign 连续赋值,wire 类型即可。
  • 第 7 行:assign 语句实现选择:若 sel=1 则输出 b,否则输出 a。这是典型的组合逻辑描述,综合成 LUT。
  • 第 8 行:模块结束。

阶段三:时序逻辑模块(D 触发器)

// D flip-flop with asynchronous reset (sequential)
module dff (
 input wire clk,
 input wire rst_n,
 input wire d,
 output reg q
);
 always @(posedge clk or negedge rst_n) begin
 if (!rst_n)
 q <= 1'b0;
 else
 q <= d;
 end
endmodule

逐行说明

  • 第 1 行:注释,说明模块为 D 触发器,采用异步复位(原始注释有误,此处更正)。
  • 第 2 行:模块名 dff。
  • 第 3–6 行:端口声明,时钟和复位为 input,数据 d 为 input,输出 q 为 output reg(因为时序逻辑在 always 块中赋值)。
  • 第 7 行:always @(posedge clk or negedge rst_n) 敏感列表,时钟上升沿或复位下降沿触发,这是异步复位写法。
  • 第 8–11 行:if (!rst_n) 判断复位有效(低电平),将 q 清零;否则在时钟上升沿将 d 赋值给 q。使用非阻塞赋值 <= 是时序逻辑的标准写法,避免竞争。
  • 第 12 行:模块结束。

阶段四:顶层模块(组合 + 时序)

// Top module: mux output -&gt; DFF input
module top_mux_dff (
 input wire clk,
 input wire rst_n,
 input wire a,
 input wire b,
 input wire sel,
 output reg led
);
 wire mux_out;

 // Instantiate mux
 mux2to1 u_mux (
 .a(a),
 .b(b),
 .sel(sel),
 .y(mux_out)
 );

 // Instantiate DFF
 dff u_dff (
 .clk(clk),
 .rst_n(rst_n),
 .d(mux_out),
 .q(led)
 );
endmodule

逐行说明

  • 第 1 行:注释,说明顶层将多路选择器输出连接到 DFF 输入。
  • 第 2 行:模块名 top_mux_dff。
  • 第 3–8 行:端口声明,led 为 output reg 因为顶层内部例化的 DFF 输出是 reg,但顶层端口可以声明为 wire 然后通过 assign 连接;此处直接 reg 更简单。
  • 第 9 行:内部连线 mux_out,wire 类型,连接 mux 输出与 DFF 输入。
  • 第 11–16 行:例化 mux2to1,使用命名端口连接。
  • 第 18–23 行:例化 dff,将 mux_out 作为数据输入,led 作为输出。
  • 第 24 行:模块结束。

阶段五:约束与综合

创建 XDC 文件,添加时钟约束:create_clock -period 20.0 [get_ports clk]。运行综合,检查资源报告:LUT 应约 2–3 个,FF 约 1 个。常见坑:未添加时钟约束时,时序分析会使用默认频率(可能不准确);综合后务必查看“Report Timing Summary”确认 WNS。

阶段六:仿真验证

// Testbench for top_mux_dff
module tb_top_mux_dff;
 reg clk, rst_n, a, b, sel;
 wire led;

 top_mux_dff uut (
 .clk(clk),
 .rst_n(rst_n),
 .a(a),
 .b(b),
 .sel(sel),
 .led(led)
 );

 initial begin
 clk = 0;
 forever #10 clk = ~clk; // 50 MHz clock
 end

 initial begin
 rst_n = 0;
 #25 rst_n = 1;
 #10 a = 1; b = 0; sel = 0; // select a -&gt; led should become 1 after clock edge
 #20 sel = 1; // select b -&gt; led should become 0 after clock edge
 #20 $finish;
 end

 initial begin
 $monitor("Time=%0t, sel=%b, a=%b, b=%b, led=%b", $time, sel, a, b, led);
 end
endmodule

逐行说明

  • 第 1 行:注释,testbench 模块。
  • 第 2 行:模块名 tb_top_mux_dff。
  • 第 3–4 行:声明输入激励为 reg,输出为 wire。
  • 第 6–13 行:例化待测模块。
  • 第 15–17 行:生成 50 MHz 时钟,每 10 ns 翻转一次。
  • 第 19–24 行:复位序列:先拉低 25 ns,然后释放;接着改变输入,观察输出。
  • 第 26–28 行:$monitor 打印变化,便于调试。

关键验收:仿真波形中,led 应在时钟上升沿后变化,且滞后于 mux_out 一个时钟周期。

原理与设计说明

为什么需要区分组合逻辑和时序逻辑?

组合逻辑的输出只取决于当前输入,没有记忆功能,适合做数据选择、译码等。时序逻辑的输出依赖于时钟沿和内部状态,可以存储数据、实现状态机。在 FPGA 中,组合逻辑由查找表(LUT)实现,时序逻辑由触发器(FF)实现。将组合逻辑的输出直接连接到触发器的输入,可以消除组合逻辑的毛刺,提高系统稳定性——这是本设计的核心思想。

Trade-off 分析

如果全部用组合逻辑,延迟小但易受毛刺干扰;全部用时序逻辑,面积大且延迟增加。本设计采用“组合+时序”混合,在关键路径上插入寄存器(流水线思想),平衡了吞吐与延迟。对于初学者,理解这个平衡是进阶的关键。

验证与结果

指标测量值(示例)条件
Fmax≥ 200 MHzVivado 2025.2,Artix-7 -1 速度等级,无时序违例
LUT 使用2 个仅 mux 逻辑
FF 使用1 个仅 D 触发器
组合延迟约 0.5 ns从输入到 mux 输出
时钟到输出约 1.2 ns从时钟沿到 led 输出

注:以上数值为典型配置下的示例,实际以综合实现报告为准。仿真波形应显示:在 t=35 ns 时,a=1,sel=0,mux_out 立即变为 1,但 led 在 t=40 ns(时钟上升沿)才变为 1。

故障排查(Troubleshooting)

  • 现象:综合报错“cannot be driven by multiple drivers” → 原因:同一信号在多个 always 块或 assign 语句中赋值。→ 解决:检查代码,确保每个 wire/reg 只被驱动一次。
  • 现象:仿真输出一直为 X → 原因:未初始化或复位未释放。→ 解决:检查 testbench 中是否在 t=0 时拉低复位,并等待足够时间再释放。
  • 现象:上板后 LED 不亮 → 原因:引脚约束错误或时钟未连接。→ 解决:检查 XDC 中 I/O 端口是否正确绑定到物理引脚。
  • 现象:时序分析报告 WNS 为负 → 原因:组合逻辑延迟过长或时钟频率过高。→ 解决:尝试降低时钟频率(增加周期)或优化组合逻辑(如减少级联 LUT)。
  • 现象:仿真中 led 在时钟沿之前变化 → 原因:错误使用了阻塞赋值(=)代替非阻塞赋值(<=)。→ 解决:将 always 块中的赋值改为非阻塞。
  • 现象:综合后资源报告显示大量 LUT/FF → 原因:代码中无意生成了锁存器(latch)。→ 解决:检查组合逻辑中是否所有分支都有赋值,避免 inferred latch。
  • 现象:上板后 LED 闪烁不稳定 → 原因:时钟抖动或复位抖动。→ 解决:在复位路径上添加去抖电路(或使用专用复位芯片)。
  • 现象:仿真波形中 mux_out 有毛刺 → 原因:组合逻辑的输入变化时间不一致。→ 解决:这是正常现象,时序逻辑输出 led 会滤除毛刺。

扩展与下一步

  • 参数化设计:将多路选择器改为参数化宽度(如 parameter WIDTH = 8),支持多 bit 数据。
  • 流水线深度:在组合逻辑路径中插入多级寄存器,提高 Fmax。
  • 状态机集成:将本设计作为状态机的一部分,例如根据状态选择不同输入。
  • 跨平台验证:在 Altera/Intel 器件上使用 Quartus 实现相同功能,对比资源与时序。
  • 断言与覆盖:在 testbench 中加入 SVA 断言,自动检查时序关系。

参考与信息来源

  • Vivado Design Suite User Guide: Synthesis (UG901)
  • IEEE Std 1364-2005 Verilog Hardware Description Language
  • Xilinx Artix-7 Data Sheet (DS181)
  • “FPGA Prototyping by Verilog Examples” by Pong P. Chu

技术附录

术语表

  • 组合逻辑:输出仅由当前输入决定的逻辑电路,无存储单元。
  • 时序逻辑:输出依赖于时钟沿和内部状态的逻辑电路,含触发器。
  • LUT:查找表,FPGA 中实现组合逻辑的基本单元。
  • FF:触发器,FPGA 中实现时序逻辑的基本单元。
  • WNS:最差负时序余量,必须 ≥ 0 才能保证时序收敛。

检查清单

  • [ ] 所有输入端口声明为 wire
  • [ ] 时序逻辑输出声明为 reg,使用非阻塞赋值
  • [ ] 组合逻辑使用 assign 或 always @(*) 阻塞赋值
  • [ ] 时钟约束已添加
  • [ ] 仿真波形符合预期(组合输出立即变化,时序输出在时钟沿后变化)
  • [ ] 综合后 WNS ≥ 0

关键约束速查

# 时钟约束(50 MHz)
create_clock -period 20.0 [get_ports clk]

# 输入延迟约束(示例)
set_input_delay -clock clk -max 5.0 [get_ports a]
set_input_delay -clock clk -min 1.0 [get_ports a]

# 输出延迟约束(示例)
set_output_delay -clock clk -max 6.0 [get_ports led]
标签:
本文原创,作者:二牛学FPGA,其版权均为FPGA线上课程平台|最全栈的FPGA学习平台|FPGA工程师认证培训所有。
如需转载,请注明出处:https://z.shaonianxue.cn/42441.html
二牛学FPGA

二牛学FPGA

初级工程师
这家伙真懒,几个字都不愿写!
1.06K20.51W4.04W3.67W
分享:
成电国芯FPGA赛事课即将上线
先进封装对FPGA设计验证流程的影响:上手指南与实施手册
先进封装对FPGA设计验证流程的影响:上手指南与实施手册上一篇
基于AXI4-Stream的实时视频帧缓存设计指南下一篇
基于AXI4-Stream的实时视频帧缓存设计指南
相关文章
总数:1.10K
FPGA竞赛:2026年Q2备赛选题聚焦端侧AI推理与多传感器融合

FPGA竞赛:2026年Q2备赛选题聚焦端侧AI推理与多传感器融合

QuickStart步骤一:下载并安装Vivado2024.2(或…
技术分享
2天前
0
0
17
0
FPGA图像处理实战:基于Verilog的实时边缘检测算法实现

FPGA图像处理实战:基于Verilog的实时边缘检测算法实现

本文档旨在指导读者在FPGA上实现一个实时图像边缘检测系统。我们将采用经…
技术分享
16天前
0
0
39
0
数字IC前端工程师技能发展指南(2026):FPGA与ASIC的共通基础与专业分化

数字IC前端工程师技能发展指南(2026):FPGA与ASIC的共通基础与专业分化

在数字集成电路(IC)设计领域,现场可编程门阵列(FPGA)与专用集成电…
技术分享
19天前
0
0
48
0
评论表单游客 您好,欢迎参与讨论。
加载中…
评论列表
总数:0
FPGA线上课程平台|最全栈的FPGA学习平台|FPGA工程师认证培训
没有相关内容