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

Verilog 组合逻辑与时序逻辑划分实践指南

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

Quick Start

  • 打开 Vivado(或 Quartus),创建新工程,选择目标器件(如 XC7A35T)。
  • 新建一个 Verilog 源文件,命名为 top.v
  • 编写一个简单的计数器模块:包含时钟输入 clk、复位 rst_n 和输出 cnt[3:0]
  • always @(posedge clk or negedge rst_n) 块中实现时序逻辑if (!rst_n) cnt <= 4'd0; else cnt <= cnt + 1'b1;

前置条件

  • 已安装 Vivado 2020.1 及以上版本(或 Quartus Prime 18.0 及以上版本)。
  • 具备 Verilog 基础语法知识,熟悉 always 块与赋值语句。
  • 了解 FPGA 基本架构(查找表、触发器、布线资源)。

目标与验收标准

  • 掌握组合逻辑时序逻辑的划分原则,能独立判断何时使用 assignalways @(*)always @(posedge clk)
  • 完成一个可综合的计数器设计,并通过仿真验证其功能正确性。
  • 验收标准:仿真波形中 cnt 在每个时钟上升沿递增,复位时清零,无毛刺或竞争风险。

实施步骤

步骤 1:理解组合逻辑与时序逻辑的本质区别

组合逻辑的输出仅取决于当前输入,无记忆特性,典型实现方式为 assign 连续赋值或 always @(*) 过程赋值(使用阻塞赋值 =)。时序逻辑依赖时钟边沿触发,具有状态保持能力,必须使用 always @(posedge clk)always @(negedge clk) 块,且内部赋值采用非阻塞赋值 <=

原因与机制分析:组合逻辑在硬件上映射为查找表(LUT)和门电路,信号传播延迟由路径决定;时序逻辑则通过触发器(FF)在时钟边沿采样并锁存数据,避免了组合逻辑中常见的毛刺与竞争问题。正确划分二者是保证设计时序收敛与功能稳定的基础。

步骤 2:设计计数器模块

创建一个新的 Verilog 源文件 top.v,编写如下代码:

module top (
    input  wire       clk,
    input  wire       rst_n,
    output reg  [3:0] cnt
);

// 时序逻辑:计数器递增
always @(posedge clk or negedge rst_n) begin
    if (!rst_n)
        cnt &lt;= 4'd0;
    else
        cnt &lt;= cnt + 1'b1;
end

endmodule

落地路径:上述代码中,always 块的敏感列表包含时钟上升沿和异步复位下降沿,确保复位立即生效,计数行为仅在时钟边沿更新。这是典型的时序逻辑写法,非阻塞赋值 <= 保证了多个赋值在同一时钟周期内正确同步。

步骤 3:添加组合逻辑示例(可选)

为了对比,可以在同一模块中添加一个组合逻辑输出,例如 even_flag 指示计数器是否为偶数:

wire even_flag;
assign even_flag = (cnt[0] == 1'b0);

这里 assign 语句直接根据当前 cnt 的最低比特位计算输出,不依赖时钟,属于纯组合逻辑。

步骤 4:编写测试激励并仿真

新建一个仿真文件 tb_top.v

module tb_top;
    reg  clk;
    reg  rst_n;
    wire [3:0] cnt;

    top uut (
        .clk   (clk),
        .rst_n (rst_n),
        .cnt   (cnt)
    );

    initial begin
        clk = 0;
        forever #5 clk = ~clk;  // 10ns 时钟周期
    end

    initial begin
        rst_n = 0;
        #20 rst_n = 1;
        #200 $finish;
    end

    initial begin
        $monitor("Time=%0t, cnt=%d", $time, cnt);
    end
endmodule

在 Vivado 或 ModelSim 中运行仿真,观察波形。确认复位期间 cnt 保持为 0,释放后每个时钟上升沿递增 1。

验证结果

仿真通过后,应得到如下波形特征:

  • 复位信号 rst_n 为低电平时,cnt 立即清零。
  • 复位释放后,cntclk 的每个上升沿加 1。
  • even_flag(如果添加)在 cnt 为偶数时输出高电平,无延迟。

若出现 cnt 变化与时钟不同步、或复位后未清零,请检查敏感列表与赋值类型。

排障指南

  • 问题:仿真中 cnt 不递增 —— 可能原因:时钟未翻转或复位未释放。检查 clk 生成逻辑与 rst_n 时序。
  • 问题:综合后出现锁存器(latch)警告 —— 通常是因为组合逻辑块中未覆盖所有分支。确保 always @(*) 中每个条件都有赋值,或使用 default 语句。
  • 问题:时序违例 —— 检查时钟频率是否过高,或组合逻辑路径过长。可插入流水线寄存器拆分关键路径。

扩展:复杂场景下的划分策略

在实际工程中,组合逻辑与时序逻辑的边界往往模糊。例如,状态机中的下一状态计算属于组合逻辑,而状态寄存属于时序逻辑。推荐采用“三段式”状态机写法,将组合逻辑(次态与输出)与时序逻辑(现态更新)分离,提高可读性与综合质量。

风险边界:切勿在同一个 always 块中混用阻塞与非阻塞赋值,或将组合逻辑写入时钟敏感列表中,这会导致仿真与综合结果不一致。始终遵循“组合逻辑用阻塞赋值,时序逻辑用非阻塞赋值”的黄金法则。

参考

  • IEEE Std 1364-2001 Verilog HDL 标准
  • Vivado Design Suite User Guide: Synthesis (UG901)
  • Clifford E. Cummings, “Nonblocking Assignments in Verilog Synthesis, Coding Styles That Kill!”

附录:完整代码清单

// top.v
module top (
    input  wire       clk,
    input  wire       rst_n,
    output reg  [3:0] cnt,
    output wire       even_flag
);

// 时序逻辑:计数器
always @(posedge clk or negedge rst_n) begin
    if (!rst_n)
        cnt &lt;= 4'd0;
    else
        cnt &lt;= cnt + 1'b1;
end

// 组合逻辑:偶数指示
assign even_flag = (cnt[0] == 1'b0);

endmodule
标签:
本文原创,作者:二牛学FPGA,其版权均为FPGA线上课程平台|最全栈的FPGA学习平台|FPGA工程师认证培训所有。
如需转载,请注明出处:https://z.shaonianxue.cn/37510.html
二牛学FPGA

二牛学FPGA

初级工程师
这家伙真懒,几个字都不愿写!
61017.52W3.94W3.67W
分享:
成电国芯FPGA赛事课即将上线
基于FPGA的CORDIC算法实现与精度分析指南
基于FPGA的CORDIC算法实现与精度分析指南上一篇
AXI4-Stream 接口时序约束与验证实践指南下一篇
AXI4-Stream 接口时序约束与验证实践指南
相关文章
总数:658
FPGA实现DDR3/DDR4控制器:初始化、读写时序与校准

FPGA实现DDR3/DDR4控制器:初始化、读写时序与校准

本文档提供在FPGA平台上实现DDR3/DDR4存储控制器的完整实施路径…
技术分享
8天前
0
0
22
0
2026年FPGA工程师招聘新趋势:技能要求与面试准备全攻略

2026年FPGA工程师招聘新趋势:技能要求与面试准备全攻略

本文旨在为有志于在2026年及以后寻求FPGA工程师职位的技术从业者,提…
技术分享
5天前
0
0
23
0
FPGA遇上HBM3:2026年,你的设计需要这条“数据高速公路”

FPGA遇上HBM3:2026年,你的设计需要这条“数据高速公路”

嘿,如果你正在关注AI、高性能计算这些前沿领域,一定感受到了那股汹涌的“…
技术分享
1个月前
0
0
54
0
评论表单游客 您好,欢迎参与讨论。
加载中…
评论列表
总数:0
FPGA线上课程平台|最全栈的FPGA学习平台|FPGA工程师认证培训
没有相关内容