news 2026/4/21 6:33:49

零基础实现8位加法器(Verilog版)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
零基础实现8位加法器(Verilog版)

从零开始造一台“计算器”:用Verilog实现一个8位加法器

你有没有想过,计算机是怎么做加法的?
不是打开手机计算器点两下那种——而是从最底层的逻辑门开始,一步步搭出能真正把两个数字相加的电路。这听起来像是芯片设计师才该操心的事,但其实,只要你会写几行代码,也能在FPGA开发板上亲手实现它。

今天我们就来干一件“硬核小事”:用 Verilog HDL 从零构建一个 8位加法器。不需要任何前置知识,也不依赖复杂的工具链,目标只有一个——让你看懂每一步发生了什么,理解数字系统中最基础、也最关键的模块之一是如何工作的。


加法器不只是“A+B”,它是整个计算机的起点

在现代处理器里,一切运算最终都归结为加法。减法是“加上负数”,乘法是“多次相加”,就连浮点运算背后也有加法器的身影。可以说,算术逻辑单元(ALU)的核心就是加法器

而作为入门第一课,8位加法器是再合适不过的选择。它足够简单,可以在几十行代码内完成;又足够典型,涵盖了组合逻辑设计、进位传播、模块化思想等关键概念。更重要的是,一旦你搞懂了它,后续扩展到16位、32位甚至带标志位的ALU,就只是水到渠成的事了。

我们采用Verilog来实现,这是一种硬件描述语言(HDL),不像软件那样“执行指令”,而是用来“描述电路结构”。你可以把它想象成画电路图的另一种方式——只不过用的是文本。


先搞清楚:什么是全加器?

要建高楼,先打地基。8位加法器的地基,就是一个叫全加器(Full Adder, FA)的小模块。

它的任务很简单:

输入三个比特:
-a:第一个操作数的一位
-b:第二个操作数的一位
-cin:来自低位的进位

输出两个结果:
-sum:当前位的和
-cout:向高位输出的进位

比如,当a=1,b=1,cin=1时,总共是3(二进制11),所以sum=1,cout=1

它的逻辑公式也很简洁:

sum = a ^ b ^ cin; cout = (a & b) | (cin & (a ^ b));

别被符号吓到,“^”是异或,“&”是与,“|”是或——这些对应着实际的逻辑门电路。这个表达式可以直接综合成真实的门级网表。

写成模块长这样:

module full_adder( input a, input b, input cin, output sum, output cout ); assign sum = a ^ b ^ cin; assign cout = (a & b) | (cin & (a ^ b)); endmodule

就这么几行,没有时钟、没有状态、纯组合逻辑——输入一变,输出立刻跟着变。这就是典型的组合电路行为

✅ 小贴士:为什么不用 always 块?因为这是纯组合逻辑,assign更直观且不易出错。初学者容易在always @(*)中漏写敏感信号,导致仿真和综合不一致。


把8个全加器串起来:做出8位加法器

单个全加器只能处理一位。要想加两个8位数,就得把它们连成一条“流水线”——每一位的结果会影响下一位的进位,这种结构叫做串行进位加法器(Ripple Carry Adder)

它的名字很形象:进位像波纹一样,从最低位一级一级传到最高位。

我们的设计思路是:

  1. 实例化8个full_adder模块;
  2. 第0位使用外部进位cin
  3. 第i位的进位输出接到第i+1位的进位输入;
  4. 最高位的进位输出作为整体的溢出标志cout

听起来重复?确实!所以我们用 Verilog 的generate 循环来避免写8遍几乎一样的代码。

最终顶层模块如下:

module adder_8bit( input [7:0] a, input [7:0] b, input cin, output [7:0] sum, output cout ); wire [7:0] c; // 内部进位链:c[0]~c[6],c[7]即cout // 第0位:用cin作为输入进位 full_adder fa0 (.a(a[0]), .b(b[0]), .cin(cin), .sum(sum[0]), .cout(c[0])); // 第1到第6位:自动生成 genvar i; generate for (i = 1; i <= 6; i = i + 1) begin : adder_stage full_adder fa ( .a(a[i]), .b(b[i]), .cin(c[i-1]), .sum(sum[i]), .cout(c[i]) ); end endgenerate // 第7位(最高位):输出最终进位 full_adder fa7 (.a(a[7]), .b(b[7]), .cin(c[6]), .sum(sum[7]), .cout(cout)); endmodule

关键细节解析:

  • wire [7:0] c:定义了一个8位宽的内部线网数组,用于传递中间进位。注意c[7]并未使用,因为第7位的cout直接连到了输出端口。
  • .a(a[i])这种命名风格:采用模块例化时的“显式端口连接”,可读性强,不怕顺序错乱。
  • generate-for 的作用:省去手动复制粘贴,提升代码整洁度和可维护性。对于更宽的加法器(如32位),这种方式优势更加明显。

虽然串行进位结构速度较慢(毕竟进位要“爬楼梯”),但它胜在结构清晰、资源占用少、适合教学和小型项目。等你掌握了它,再去学超前进位加法器(CLA)会轻松得多。


它能在哪用?不只是玩具!

别以为这只是实验室里的教学案例。实际上,8位加法器在很多真实场景中都有应用:

应用领域使用方式
微控制器 ALU执行 ADD、INC 等基本指令
FPGA 图像处理实现像素亮度叠加、坐标偏移计算
嵌入式传感器系统累加采样值、做简单滤波
教学实验平台验证组合逻辑延迟、观察进位传播

特别是在资源受限的FPGA开发板上,这种轻量级加法器非常实用。你可以把它集成进自己的CPU雏形、简易计算器或者数字时钟项目中。

举个例子,在一条简单的ADD R1, R2指令中:
1. 控制器从寄存器读取R1R2的值;
2. 数据送入adder_8bit
3. 几纳秒后得到结果和cout
4. 结果写回目标寄存器,cout存入状态标志位(如 Carry Flag);
5. 程序继续运行。

整个过程无需额外时钟节拍(如果是纯组合路径),效率极高。


别踩坑!这些经验帮你少走弯路

我在第一次写这个加法器的时候,也犯过不少低级错误。下面这几个“坑”,希望你能提前避开:

❌ 坑点1:忘了初始化cin

如果你没特别说明,综合工具可能会默认cin是不确定状态。正确做法是在测试平台中明确赋值,例如常用情况下设为1'b0

✅ 秘籍:可以用参数化设计增强灵活性

parameter WIDTH = 8; input [WIDTH-1:0] a, b;

这样以后想升级成16位,只需改个参数即可。

❌ 坑点2:误以为“速度快”

串行进位的最大问题是延迟随位宽线性增长。8位可能只有几ns,但32位就可能成为关键路径瓶颈。高速设计中应考虑CLA或混合结构。

✅ 秘籍:仿真一定要覆盖边界情况

  • 8'hFF + 8'h01→ 应该产生sum=0,cout=1(溢出)
  • 8'h00 + 8'h00→ 验证零值处理
  • 8'hAA + 8'h55→ 测试交替位模式,确保每位正常工作

下一步可以怎么玩?

现在你已经有了一个可用的8位加法器,接下来完全可以把它当作积木,搭建更复杂的功能:

  • 支持减法:通过补码实现,只需要加一个控制信号来决定是否对B取反并置cin=1
  • 增加零标志(Zero Flag):判断sum == 0
  • 封装成ALU模块:加入AND、OR、XOR等功能;
  • 接入寄存器文件:做成一个微型CPU数据通路;
  • 上板验证:在FPGA开发板上用拨码开关输入,LED显示结果。

甚至可以尝试改造成超前进位加法器(Carry Look-Ahead Adder),体验性能飞跃的感觉。


写在最后:动手才是最好的学习

掌握8位加法器的设计,不是为了真的去替代商用IP核,而是为了理解计算机如何“思考”数字世界。当你亲手把两个二进制数相加成功那一刻,你会发现:原来那些神秘的芯片,并非遥不可及。

这项技能的价值在于:
-建立硬件思维:从“执行流程”转向“并发结构”;
-打通软硬界限:程序员也能看懂RTL代码;
-为深入学习铺路:无论是FPGA开发、IC设计还是体系结构研究,这都是必经之路。

所以,别光看——赶紧打开你的 Vivado、ModelSim 或 EDA Playground,把上面的代码跑一遍吧!

如果你在实现过程中遇到了问题,比如波形不对、进位没传上去,欢迎留言交流。我们一起debug,一起进步。

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

Vitis中Zynq软硬件协同设计实战案例解析

Vitis中Zynq软硬件协同设计实战&#xff1a;从图像处理看异构系统开发的现代路径你有没有遇到过这样的场景&#xff1f;一个嵌入式项目需要实时处理摄像头数据&#xff0c;ARM主控跑算法时CPU飙到90%以上&#xff0c;帧率却只有十几FPS。你想用FPGA加速&#xff0c;但面对Veril…

作者头像 李华
网站建设 2026/4/18 6:25:30

基于Verilog的组合逻辑电路建模:语法与规范

从零构建可靠的组合逻辑&#xff1a;Verilog建模实战精要你有没有遇到过这样的情况&#xff1f;仿真时一切正常&#xff0c;波形完美&#xff0c;结果正确——可一进综合工具&#xff0c;就冒出一堆“latch inference”的警告。更糟的是&#xff0c;FPGA跑起来后某些输入组合下…

作者头像 李华
网站建设 2026/4/20 4:52:29

零基础理解蜂鸣器电路原理图:通俗解释核心组成

从“滴”一声开始&#xff1a;拆解蜂鸣器背后的电路逻辑你有没有想过&#xff0c;按下微波炉按钮时那声清脆的“滴”&#xff0c;是怎么来的&#xff1f;或者&#xff0c;智能门锁识别失败时那一声短促的“哔——”&#xff0c;背后究竟发生了什么电子魔法&#xff1f;其实&…

作者头像 李华
网站建设 2026/4/20 11:27:32

Xilinx Ultrascale+中实现XDMA双工通信的从零实现

从零构建XDMA双工通信&#xff1a;在Xilinx Ultrascale上打通高速PCIe数据通路 你有没有遇到过这样的场景&#xff1f;FPGA采集了海量图像或雷达回波数据&#xff0c;却卡在“怎么快速传给主机”这一关。传统的USB、千兆以太网早已力不从心&#xff0c;而CPU轮询搬运又占资源、…

作者头像 李华
网站建设 2026/4/17 1:45:04

DAY 48随机函数与广播机制

一、 随机张量的生成 在深度学习中经常需要随机生成一些张量&#xff0c;比如权重的初始化&#xff0c;或者计算输入纬度经过模块后输出的维度&#xff0c;都可以用一个随机函数来实现需要的张量格式&#xff0c;而无需像之前一样必须加载一张真实的图片。 随机函数的种类很多…

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

Windows 11下Multisim安装操作指南

如何在 Windows 11 上顺利安装 Multisim&#xff1f;一份来自实战的避坑指南 最近帮实验室几位同学装 Multisim&#xff0c;发现很多人卡在第一步—— 系统明明是 Win11&#xff0c;配置也不低&#xff0c;怎么点一下 setup.exe 就报错、卡死甚至直接退出&#xff1f; 别急。…

作者头像 李华