从与非门到8位加法器:用最简单的逻辑构建计算核心
你有没有想过,一台计算机是怎么做加法的?
它不像我们列竖式那样进位、相加、写下结果。它的“大脑”里没有数字,只有高电平和低电平——也就是1和0。而实现这一切运算的起点,可能仅仅是一个小小的与非门(NAND)。
更惊人的是:只用一种逻辑门,就能造出能算两个8位数之和的电路。听起来像天方夜谭?但这不仅是理论可行,更是数字电路设计中极具教学价值的经典实践。
今天我们就来走一遍这条“从零开始”的路径:如何仅用与非门,一步步搭建出一个完整的8位加法器。即使你刚接触数字电路,也能看懂每一步背后的逻辑。
为什么选与非门?因为它“万能”
在所有逻辑门中,与非门是个特殊的存在——它是“功能完备集”,意味着:任何布尔函数,都可以只用与非门实现。
这就像数学中的质数,或者乐高积木里的基础块。只要给你足够的与非门,你就能搭出非门、与门、或门、异或门……甚至整个CPU。
与非门长什么样?
它的逻辑很简单:
只有当所有输入为1时,输出才为0;否则输出为1。
真值表如下:
| A | B | Y |
|---|---|---|
| 0 | 0 | 1 |
| 0 | 1 | 1 |
| 1 | 0 | 1 |
| 1 | 1 | 0 |
对应的布尔表达式是:
$$
Y = \overline{A \cdot B}
$$
别小看这个简单规则。正是这种“先与后非”的结构,让它具备了重构一切逻辑的能力。
第一步:把其他逻辑门“变”出来
既然只能用与非门,那我们就得想办法用它模拟出我们需要的所有基本逻辑单元。
非门(NOT)怎么实现?
很简单:把两个输入连在一起。
assign Y = ~(A & A); // 等价于 ~A电路连接上,就是把信号A同时接到与非门的两个输入端。如果A=1,输出就是0;A=0,输出就是1——完美实现取反。
✅成本:1个NAND门
与门(AND)呢?
我们知道:
$$
A \cdot B = \overline{\overline{A \cdot B}}
$$
所以只要对NAND(A,B)的结果再取一次反,就得到了原始的“与”。
也就是说:
1. 第一个NAND得到 $\overline{A\cdot B}$
2. 第二个NAND当作反相器,将其反转回来
✅成本:2个NAND门
或门(OR)也能做吗?
可以!利用德摩根定律:
$$
A + B = \overline{\bar{A} \cdot \bar{B}}
$$
步骤如下:
1. 用两个NAND分别生成 $\bar{A}$ 和 $\bar{B}$(各自接成反相器)
2. 把这两个反相信号送入第三个NAND
3. 输出即为 $A+B$
✅成本:3个NAND门
最关键的:异或门(XOR)
这是加法器的灵魂。因为一位二进制加法的本质就是异或运算。
回忆一下:
- $0+0=0$ → $0⊕0=0$
- $0+1=1$ → $0⊕1=1$
- $1+0=1$ → $1⊕0=1$
- $1+1=0$(进位)→ $1⊕1=0$
所以和(Sum) = $A ⊕ B$,而进位(Carry) = $A·B$
但XOR不能直接由单个NAND实现,需要巧妙构造。
标准NAND-based XOR使用4个门:
wire w1, w2, w3; nand(w1, a, b); // w1 = ~(a & b) nand(w2, a, w1); // w2 = ~(a & ~(a&b)) = ~a when b=1 nand(w3, b, w1); // w3 = ~(b & ~(a&b)) = ~b when a=1 nand(sum, w2, w3); // sum = ~(w2 & w3) = a ^ b虽然推导略复杂,但你可以把它当成一个“黑盒模板”记住:4个2输入NAND门 = 1个XOR
✅成本:4个NAND门
第二步:构建最小加法单元——半加器
现在我们有了XOR和AND,就可以做一个最简单的加法器:半加器(Half Adder)
它处理两个1位数相加,输出和(Sum)与进位(Carry):
| A | B | Sum | Carry |
|---|---|---|---|
| 0 | 0 | 0 | 0 |
| 0 | 1 | 1 | 0 |
| 1 | 0 | 1 | 0 |
| 1 | 1 | 0 | 1 |
公式清晰:
- Sum = $A ⊕ B$ → 用4个NAND
- Carry = $A·B$ → 用2个NAND(第一个做NAND,第二个做反相)
不过注意!我们在XOR部分已经计算了 $\overline{A·B}$,可以直接拿来作为Carry路径的第一级输入,省去重复计算。
💡优化技巧:共享中间信号 $\overline{A·B}$,可将总门数压缩至5个NAND门
第三步:升级为全加器,支持进位传递
半加器有个致命缺陷:它不知道来自低位的进位。要构成多位加法,必须使用全加器(Full Adder)
全加器有三个输入:A、B、Cin(进位输入),输出Sum和Cout。
其逻辑关系为:
- Sum = $A ⊕ B ⊕ C_{in}$
- Cout = $AB + BC_{in} + AC_{in}$
我们可以用两个半加器来构造:
- 先用HA1计算 $A+B$ → 得到局部Sum1 和 Carry1
- 再用HA2将Sum1与Cin相加 → 得到最终Sum
- 最后用一个或门合并Carry1和新的进位 → 得到Cout
但如果只允许用NAND,就得全部拆解成NAND网络。
下面是推荐的结构化实现方式(基于布尔化简):
module full_adder_nand(input a, input b, input cin, output sum, output cout); wire p, g; // p = A^B, g = A·B wire s1, s2, s3; // 中间信号用于Sum wire c1, c2, c3; // 中间信号用于Carry out // Step 1: 计算 A ^ B → p wire ab_nand, a_ab, b_ab; nand(ab_nand, a, b); nand(a_ab, a, ab_nand); nand(b_ab, b, ab_nand); nand(p, a_ab, b_ab); // Step 2: Sum = p ^ cin wire p_cin_nand, cin_p_nand; nand(p_cin_nand, p, cin); nand(cin_p_nand, cin, p); nand(s1, p, p_cin_nand); nand(s2, cin, cin_p_nand); nand(sum, s1, s2); // Step 3: Carry out = g + (p · cin) // g = A·B wire g_nand; nand(g_nand, a, b); nand(g, g_nand, g_nand); // 取反得 A·B // temp = p · cin wire p_cin_nand_gate, temp; nand(p_cin_nand_gate, p, cin); nand(temp, p_cin_nand_gate, p_cin_nand_gate); // 取反 // Cout = g OR temp wire or_nand1, or_nand2; nand(or_nand1, g, temp); nand(or_nand2, g, temp); nand(cout, or_nand1, or_nand2); endmodule这段代码完全由nand原语构成,每一行都对应一个物理门连接,适合用于FPGA底层建模或教学演示。
📌总结资源消耗:
- Sum路径:约6个NAND
- Carry路径:约4~5个NAND
- 总计:每个全加器约需9~12个2输入NAND门
第四步:拼起来!组成8位加法器
有了全加器,接下来就简单了:串起来就行。
采用经典的行波进位结构(Ripple Carry Adder):
FA0 ← FA1 ← FA2 ← ... ← FA7 ↑ ↑ ↑ ↑ A0B0 A1B1 A2B2 A7B7 ↑ ↑ ↑ ↑ Cin=0 C1 C2 C7 → C_out ↓ ↓ ↓ S0 S1 S7连接规则非常直观:
- 最低位FA0的 Cin 接地(0)
- 每一级的 Cout 连接到下一级的 Cin
- 所有A、B并行输入,所有Sum并行输出
- 最终得到8位和S[7:0]以及最高位进位C8
这就是一个完整的8位加法器!
实际工程考虑:不只是理论游戏
你说:“现在谁还用手动搭门电路?”
确实,现代FPGA用查找表(LUT)几秒钟就能综合出加法器。但我们坚持用NAND实现,并非为了替代工业方案,而是为了理解本质。
但在某些真实场景下,这种方法依然有价值:
✅ 教学实验
高校《数字逻辑》课程常用此项目训练学生:
- 理解组合逻辑设计流程
- 掌握门级抽象与模块化思想
- 动手焊接验证真值表
✅ 老旧设备维修 / 自制CPU
如果你在做一个复古风格的分立元件CPU,手上只有74HC00芯片(每片含4个2输入NAND门),那么这个方案就是救命稻草。
按前面估算:
- 每个FA约10个NAND
- 8位共需约80个NAND
- 使用74HC00(每片4门)→ 需要20片IC
虽然看起来很多,但布局合理的话,一块双面板完全可以容纳。
布局与调试建议
PCB设计要点:
- 按从右到左(低位到高位)排列FA模块,符合进位传播方向
- 进位线尽量短且直,避免与其他信号交叉
- 每片IC旁放置0.1μF陶瓷电容,抑制电源噪声
- 底层铺完整地平面,提升抗干扰能力
测试方法:
- 输入:用拨码开关设置A[7:0]和B[7:0]
- 输出:用8个LED显示Sum,1个LED显示Cout
- 验证典型情况:
- 0 + 0 → 0
- 255 + 1 → 0(溢出,Cout=1)
- 85 + 85 = 170(0x55 + 0x55 = 0xAA)
局限性与进阶思路
当然,行波进位结构也有明显缺点:速度慢。
因为进位要一级一级传递,第7位的结果必须等第6位的Cout稳定后才能计算。对于8位系统,延迟尚可接受;但位数再多就不现实了。
如何提速?试试超前进位加法器(CLA)
CLA的核心思想是:提前预测每一位的进位,而不必等待前一级。
它引入两个新信号:
-Generate(G):本位自己产生进位(如A=B=1)
-Propagate(P):本位会传递进位(如A≠B)
然后通过并行逻辑直接计算各级Cin,大幅缩短延迟。
有趣的是:这些PG逻辑同样可以用NAND门实现。只不过结构更复杂,需要更多门和布线。
但对于追求性能的设计来说,这是必经之路。
回到初心:简单规则如何造就复杂智能
当你站在今天的高度看计算机,它似乎无比复杂:多核CPU、GPU、AI加速器……但追根溯源,它们的算术核心,依然是由一个个最基本的逻辑门组成的加法器。
而这一切,都可以从一个小小的与非门开始。
这个项目的意义,从来不是为了取代现代芯片设计方法,而是提醒我们:
复杂的计算能力,本质上源于最简单的规则重复组合。
掌握这一点,你就掌握了通往现代计算机体系结构的大门钥匙。
无论你是初学者还是资深工程师,亲手走过这一趟“从NAND到Adder”的旅程,都会让你对“硬件如何执行指令”这件事,有更深的理解。
如果你正在学习数字电路、准备电子竞赛,或者只是好奇计算机内部是如何工作的,不妨试着在面包板上搭一个半加器,再一步步扩展到8位。你会发现,那些闪烁的LED背后,藏着人类智慧最纯粹的光芒。
欢迎在评论区分享你的实现过程或遇到的问题,我们一起探讨!