news 2026/4/21 21:43:46

基于Verilog的同或门FPGA设计实战案例

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于Verilog的同或门FPGA设计实战案例

从零开始:用Verilog在FPGA上“造”一个同或门

你有没有想过,计算机是怎么判断两个数据是否相等的?
别急着说“这还不简单”,其实背后藏着最基础、也最关键的数字逻辑单元之一——同或门(XNOR Gate)。它就像电路世界的“裁判员”,专门负责回答一个问题:“这两个信号,一模一样吗?”

今天,我们就来亲手用VerilogFPGA上实现一个同或门。这不是简单的代码抄写,而是一次完整的硬件设计实战:从真值表出发,到代码编写、仿真验证,再到实际应用场景拓展。哪怕你是第一次接触HDL,也能一步步走完全程。


同或门到底是什么?别被名字吓到

先别管那些复杂的术语,“同或”其实就是“相同才为真”。它的行为非常直观:

AB输出 Y
001
010
100
111

看出规律了吗?只要两个输入一样,输出就是1;不一样就输出0。换句话说,它是异或门(XOR)的反相结果:

$$
Y = A \odot B = \overline{A \oplus B}
$$

也可以展开成与或表达式:
$$
Y = AB + \bar{A}\bar{B}
$$

这意味着我们可以用“与门+非门+或门”搭出来。但在FPGA里,这一切都由查找表(LUT)自动搞定——你只需要告诉综合器“我要什么功能”,剩下的交给工具链。

为什么要在FPGA上做这个?

因为FPGA不是单片机,它不跑程序,而是“变成电路”。你在Verilog里写的每一行逻辑,最终都会映射成实实在在的硬件资源。而像XNOR这样的基础门,在现代FPGA中通常只占用1个LUT6(比如Xilinx Artix-7系列),几乎不占地方,却能并行执行成千上万个。

更重要的是,掌握这种最小粒度的设计思维,是你构建复杂系统的第一步。


Verilog实现:三种写法,哪种最好?

我们先来看最核心的功能模块代码:

module xnor_gate ( input wire A, input wire B, output wire Y ); assign Y = A ~^ B; endmodule

就这么四行?对,就这么简单。

关键点解析:

  • wire是线网类型,用于组合逻辑连接;
  • assign是连续赋值语句,适用于纯组合逻辑;
  • ~^是Verilog内置的按位同或操作符,直接对应XNOR逻辑。

✅ 推荐使用A ~^ B,语义清晰,可读性强,综合效果最优。

但如果你看到别人写成这样呢?

assign Y = ~(A ^ B); // XOR后取反

或者更“教科书式”的结构化写法:

assign Y = (A & B) | (~A & ~B);

这三种写法有什么区别?

写法特点建议场景
A ~^ B最简洁,意图明确日常开发首选
~(A ^ B)逻辑等价,稍绕一步兼容老标准或教学演示
(A&B)\|(~A&~B)完全还原布尔公式初学者理解原理时使用

📌重点提醒:虽然写法不同,但在综合阶段,现代EDA工具(如Vivado、Quartus)会自动优化为相同的底层LUT配置。所以优先选择可读性高的写法,而不是“看起来更底层”的结构化描述。


怎么证明你的电路是对的?靠仿真!

写完代码只是第一步,关键是要验证功能正确。这就需要一个测试平台(Testbench)

下面是完整的testbench代码:

`timescale 1ns / 1ps module tb_xnor; reg A, B; wire Y; // 实例化被测模块 xnor_gate uut ( .A(A), .B(B), .Y(Y) ); initial begin $dumpfile("xnor_wave.vcd"); $dumpvars(0, tb_xnor); // 施加所有输入组合 A = 0; B = 0; #10; A = 0; B = 1; #10; A = 1; B = 0; #10; A = 1; B = 1; #10; $finish; end // 控制台实时监控 initial begin $monitor("Time=%0t | A=%b B=%b | Y=%b", $time, A, B, Y); end endmodule

运行后你会看到输出:

Time= 0 | A=0 B=0 | Y=1 Time=10 | A=0 B=1 | Y=0 Time=20 | A=1 B=0 | Y=0 Time=30 | A=1 B=1 | Y=1

完全符合真值表!🎉

再打开波形文件(.vcd)用GTKWave查看,你会发现每个信号的变化都精准对齐时间轴——这就是硬件仿真的魅力:时间就是一切


别小看它,同或门能干大事!

你以为这只是个玩具案例?错。同或门是很多高级功能的基础构件。举几个真实应用场景:

1. 8位数据比较器:判断两数是否相等

module comparator_8bit ( input [7:0] A, input [7:0] B, output equal ); wire [7:0] cmp; genvar i; generate for (i = 0; i < 8; i = i + 1) begin : bit_comp xnor_gate single (.A(A[i]), .B(B[i]), .Y(cmp[i])); end endgenerate assign equal = &cmp; // 所有位都匹配才算相等 endmodule

👉 每一位做XNOR,最后来个“归约与”(AND reduction)。只要有一位不同,equal就是0。

这类结构广泛用于地址匹配、状态同步、冗余校验等场景。


2. 二值神经网络(BNN)中的乘法替代

在AI边缘计算中,为了降低功耗和面积,有些模型把权重和激活值都压缩成+1/-11/0。这时候传统的乘法可以用XNOR + 计数来近似:

  • 1 x 1 = 1→ XNOR得1
  • 1 x 0 = 0→ XNOR得0
  • 0 x 1 = 0→ XNOR得0
  • 0 x 0 = 1→ XNOR得1

你会发现:当两个比特相同时,XNOR输出为1,正好对应乘积为1的情况

于是整个矩阵乘法就可以转化为大量并行的XNOR运算 + 统计1的个数(POP_COUNT)。这种方法在FPGA上效率极高,已经被用于低功耗AI加速器设计。


3. 双核锁步系统的故障检测

在航天、汽车电子等高可靠性系统中,常用双核锁步架构(Lockstep Dual-Core):两个CPU同时运行相同代码,输出实时比对。

怎么比对?用的就是一大排XNOR门!

一旦发现某个时刻输出不一致(即某位XNOR结果为0),立即触发错误中断,防止系统失控。


开发实践中要注意这些“坑”

别以为写了代码就能顺利烧板子。以下是新手常踩的雷区:

❌ 忘记覆盖所有输入分支 → 综合出锁存器(Latch)

如果你写的是组合逻辑但没处理所有条件,例如:

always @(*) begin if (A == 1) Y = B; // 没写else! end

综合器会认为你需要“记住”上次的值,从而推断出latch。这在同步设计中可能引发亚稳态问题。

✅ 正确做法:要么补全else,要么用assign写纯组合逻辑。


✅ 最佳实践清单

建议说明
使用命名端口连接.A(A)避免接错线,提升可读性
添加$dumpvars$monitor调试利器,尤其适合初学者
信号命名要有意义data_match,bit_eq而非tmp1,sig_a
合理使用generate结构构建重复逻辑时更清晰
开启综合警告(Synthesis Warnings)查看是否有未连接信号、悬空输出等问题

写在最后:小门背后的大世界

你可能会觉得:“就为了一个同或门写了这么多?”
但正是这种看似简单的练习,教会了我们最重要的东西:

  • 硬件思维:不是“顺序执行”,而是“并发存在”;
  • 模块化设计:从最小单元出发,层层搭建复杂系统;
  • 验证先行:没有仿真的设计等于赌博;
  • 抽象与映射:你写的A ~^ B,最终变成了FPGA里的一个LUT配置比特流。

下一步你可以尝试:

  • 把同或门扩展成多输入版本(树形结构);
  • 加一个使能端,做成可控制的比较器;
  • 结合D触发器,做一个带采样的状态监测电路;
  • 试着用SystemVerilog重写,并加入随机测试激励。

随着FPGA越来越多地应用于自动驾驶、智能传感、5G通信等领域,对底层逻辑的掌控能力反而变得更加重要。越高级的应用,越依赖扎实的基本功。

而这个小小的同或门,正是你通往硬件设计自由之路的第一块基石。

如果你正在学习FPGA,欢迎在评论区分享你的第一个成功仿真的瞬间——那往往是热爱开始的地方。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/21 3:50:00

无需联网也能精准识图?ResNet18大模型镜像实战解析

无需联网也能精准识图&#xff1f;ResNet18大模型镜像实战解析 在边缘计算、隐私保护和低延迟识别需求日益增长的今天&#xff0c;离线可用、高精度、轻量级的图像分类方案正成为开发者和企业的刚需。本文将深入解析一款基于 PyTorch 官方 ResNet-18 模型构建的 “通用物体识别…

作者头像 李华
网站建设 2026/4/15 15:27:48

PyTorch官方ResNet18镜像发布|支持离线部署与实时分析

PyTorch官方ResNet18镜像发布&#xff5c;支持离线部署与实时分析 &#x1f310; 背景与技术演进&#xff1a;从图像分类到通用物体识别 在计算机视觉的发展历程中&#xff0c;图像分类是最早被系统研究的核心任务之一。其目标是对整张图像赋予一个最可能的语义标签&#xff0c…

作者头像 李华
网站建设 2026/4/15 15:28:11

轻量高效!40MB小模型实现高精度图像识别(附镜像)

轻量高效&#xff01;40MB小模型实现高精度图像识别&#xff08;附镜像&#xff09; 在深度学习领域&#xff0c;模型性能与资源消耗往往是一对矛盾体。大型模型如ResNet-152、EfficientNet等虽然精度高&#xff0c;但动辄数百MB的体积和GPU依赖让其难以部署在边缘设备或低配服…

作者头像 李华
网站建设 2026/4/20 19:45:14

C++ 信号处理

C 信号处理基础信号是操作系统用于通知进程发生某种事件的机制&#xff0c;例如用户按下 CtrlC&#xff08;SIGINT&#xff09;或程序访问非法内存&#xff08;SIGSEGV&#xff09;。C 通过 <csignal> 头文件提供信号处理支持。常用信号类型SIGINT&#xff1a;终端中断&a…

作者头像 李华
网站建设 2026/4/17 23:09:11

Elementor 自带的progress bar组件如何去掉百分比%符号

Elementor 自带的progress bar 使用的时候&#xff0c;如下图&#xff1a;则在前端&#xff0c;它会显示成这样&#xff1a;如果想去掉百分比%符号&#xff0c;可以按下面的方法步骤&#xff1a;1. 选中组件&#xff0c;然后到Advanced>CSS Classes 中填写 no-percent-progr…

作者头像 李华
网站建设 2026/4/20 0:25:59

Keil uVision5使用教程:一文说清RTOS在工控中的集成方法

从零开始掌握 Keil uVision5 中的 RTOS 集成&#xff1a;工控开发实战指南你有没有遇到过这样的场景&#xff1f;一个简单的温控系统&#xff0c;既要定时采集传感器数据&#xff0c;又要刷新显示屏&#xff0c;还得响应按键操作和串口指令。用传统的“主循环轮询”方式写代码&…

作者头像 李华