四位加法器:从半加器到全加器的数字电路设计详解

目录

  • [1. 引言](#1. 引言)
  • [2. 基础知识:二进制加法](#2. 基础知识:二进制加法)
  • [3. 半加器(Half Adder)](#3. 半加器(Half Adder))
    • [3.1 真值表](#3.1 真值表)
    • [3.2 逻辑表达式](#3.2 逻辑表达式)
    • [3.3 电路实现](#3.3 电路实现)
  • [4. 全加器(Full Adder)](#4. 全加器(Full Adder))
    • [4.1 真值表](#4.1 真值表)
    • [4.2 逻辑表达式](#4.2 逻辑表达式)
    • [4.3 电路实现](#4.3 电路实现)
  • [5. 四位加法器的构建](#5. 四位加法器的构建)
    • [5.1 结构图](#5.1 结构图)
    • [5.2 Verilog 实现](#5.2 Verilog 实现)
    • [5.3 测试平台](#5.3 测试平台)
    • [5.4 进位链与延迟分析](#5.4 进位链与延迟分析)
  • [6. 用 Python 模拟四位加法器](#6. 用 Python 模拟四位加法器)
  • [7. 四位加法器的应用](#7. 四位加法器的应用)
    • [7.1 4 位 ALU 设计示例](#7.1 4 位 ALU 设计示例)
  • [8. 扩展到八位加法器](#8. 扩展到八位加法器)
    • [8.1 级联方式与进位传递](#8.1 级联方式与进位传递)
    • [8.2 Verilog 实现](#8.2 Verilog 实现)
    • [8.3 简要说明](#8.3 简要说明)
  • [8. 总结](#8. 总结)

摘要

本文从二进制加法规则出发,依次讲解半加器、全加器,并通过级联四个全加器构建四位加法器,再扩展到八位加法器。读者将掌握行波进位与超前进位的延迟分析,并学会用 Verilog 实现加法器与 ALU、用 Python 模拟其行为。

1. 引言

加法器是数字电路中最基础、最重要的运算单元之一,几乎所有的算术运算(减法、乘法、除法)最终都可以归结为加法运算。四位加法器(4-bit Adder)能够对两个四位二进制数进行加法运算,并输出四位结果和进位信号。本文将带你从最基础的半加器出发,逐步构建出完整的四位加法器,并给出可运行的代码实现。

2. 基础知识:二进制加法

在深入加法器之前,我们先回顾一下二进制加法的基本规则。二进制只有 0 和 1 两个数字,其加法规则如下:

  • 0 + 0 = 0,进位为 0
  • 0 + 1 = 1,进位为 0
  • 1 + 0 = 1,进位为 0
  • 1 + 1 = 0,进位为 1

当两个二进制数相加时,如果某一位的和超过 1,就需要向高位进位。例如:

复制代码
  1011
+ 0110
------
 10001

从最低位开始逐位相加,每一位的运算不仅需要考虑当前位的两个输入,还需要考虑来自低位的进位。

3. 半加器(Half Adder)

半加器是最简单的加法电路,它只处理两个一位二进制数的相加,不考虑来自低位的进位。半加器有两个输入(A、B)和两个输出(和 S、进位 C)。

3.1 真值表

输入 A 输入 B 和 S 进位 C
0 0 0 0
0 1 1 0
1 0 1 0
1 1 0 1

3.2 逻辑表达式

从真值表可以推导出:

  • 和 S = A ⊕ B(异或)
  • 进位 C = A · B(与)

3.3 电路实现

verilog 复制代码
module half_adder(
    input  A,
    input  B,
    output S,
    output C
);
    assign S = A ^ B;  // 异或
    assign C = A & B;  // 与
endmodule

4. 全加器(Full Adder)

全加器在半加器的基础上增加了进位输入(Cin),能够处理来自低位的进位。全加器有三个输入(A、B、Cin)和两个输出(和 S、进位输出 Cout)。

4.1 真值表

输入 A 输入 B 进位输入 Cin 和 S 进位输出 Cout
0 0 0 0 0
0 0 1 1 0
0 1 0 1 0
0 1 1 0 1
1 0 0 1 0
1 0 1 0 1
1 1 0 0 1
1 1 1 1 1

4.2 逻辑表达式

  • 和 S = A ⊕ B ⊕ Cin
  • 进位输出 Cout = (A · B) + (Cin · (A ⊕ B))

4.3 电路实现

verilog 复制代码
module full_adder(
    input  A,
    input  B,
    input  Cin,
    output S,
    output Cout
);
    assign S    = A ^ B ^ Cin;
    assign Cout = (A & B) | (Cin & (A ^ B));
endmodule

5. 四位加法器的构建

四位加法器由四个全加器级联而成,前一级的进位输出连接到后一级的进位输入。最低位的进位输入(Cin)通常接地(置 0)。

5.1 结构图

渲染错误: Mermaid 渲染失败: Setting FA3 as parent of FA3 would create a cycle

5.2 Verilog 实现

verilog 复制代码
module adder_4bit(
    input  [3:0] A,
    input  [3:0] B,
    input        Cin,
    output [3:0] S,
    output       Cout
);
    wire c1, c2, c3;

    full_adder fa0(
        .A(A[0]), .B(B[0]), .Cin(Cin),
        .S(S[0]), .Cout(c1)
    );
    full_adder fa1(
        .A(A[1]), .B(B[1]), .Cin(c1),
        .S(S[1]), .Cout(c2)
    );
    full_adder fa2(
        .A(A[2]), .B(B[2]), .Cin(c2),
        .S(S[2]), .Cout(c3)
    );
    full_adder fa3(
        .A(A[3]), .B(B[3]), .Cin(c3),
        .S(S[3]), .Cout(Cout)
    );
endmodule

5.3 测试平台

5.4 进位链与延迟分析

上面通过级联四个全加器构建的四位加法器,属于行波进位加法器(Ripple Carry Adder,RCA)。它的特点是结构简单、易于理解,但存在一个明显的性能瓶颈------进位信号需要逐级向后传播,形成一条长长的「进位链」。

5.4.1 关键路径延迟

所谓关键路径(Critical Path),是指从输入到输出经过逻辑门级数最多、延迟最大的那条路径。对于行波进位加法器,关键路径正是进位信号的传播路径。

假设每个全加器产生进位输出需要经过两级门延迟(记为 2T),那么四位行波进位加法器的进位传播延迟为:

复制代码
T_carry = 2T × 4 = 8T

也就是说,最高位的进位输出(Cout)要等最低位的进位逐级「爬」上来才能稳定,总共需要 8 个门延迟。相比之下,每一位的和 S 可以在进位到达后很快算出,因此整体速度由进位链决定。

推广到 n 位行波进位加法器,其关键路径延迟为:

复制代码
T_carry = 2T × n

随着位宽增加,延迟线性增长。这也是为什么行波进位加法器不适合用于高位宽、高性能的运算单元。

5.4.2 超前进位加法器(Carry Lookahead Adder)

为了缩短进位链,超前进位加法器(Carry Lookahead Adder,CLA) 被提出。它的核心思想是:提前并行计算出每一位的进位,而不是等待低位进位逐级传来。

为此,我们定义两个中间信号:

  • 生成信号(Generate) :G_i = A_i · B_i,表示第 i 位本身就能产生进位(两个输入都为 1)。
  • 传播信号(Propagate) :P_i = A_i ⊕ B_i,表示第 i 位能把低位的进位继续向上传递(两个输入不同)。

于是第 i 位的进位可以写成:

复制代码
C_{i+1} = G_i + P_i · C_i

展开后,每一位的进位只依赖输入 A、B 和最低位进位 C0,不再依赖前一级的进位结果。例如四位超前进位加法器的进位为:

复制代码
C1 = G0 + P0 · C0
C2 = G1 + P1 · G0 + P1 · P0 · C0
C3 = G2 + P2 · G1 + P2 · P1 · G0 + P2 · P1 · P0 · C0
C4 = G3 + P3 · G2 + P3 · P2 · G1 + P3 · P2 · P1 · G0 + P3 · P2 · P1 · P0 · C0

所有进位可以并行 计算,因此关键路径延迟从「随位宽线性增长」降为常数级。对于四位超前进位加法器,进位输出大约只需 3~4 级门延迟,远小于行波进位加法器的 8T。

下面给出一个完整的 4 位超前进位加法器 Verilog 实现,包含生成信号 G、传播信号 P 的计算,以及并行进位 C1~C4 的赋值逻辑:

verilog 复制代码
module cla_4bit(
    input  [3:0] A,      // 加数 A
    input  [3:0] B,      // 加数 B
    input        Cin,    // 最低位进位输入
    output [3:0] S,      // 和
    output       Cout    // 进位输出
);
    wire [3:0] G;        // 生成信号:G[i] = A[i] & B[i]
    wire [3:0] P;        // 传播信号:P[i] = A[i] ^ B[i]
    wire [4:1] C;        // 各级进位:C[1]~C[4]

    // 计算每一位的生成信号 G 与传播信号 P
    assign G[0] = A[0] & B[0];   // 第 0 位:两个输入都为 1 时产生进位
    assign G[1] = A[1] & B[1];   // 第 1 位
    assign G[2] = A[2] & B[2];   // 第 2 位
    assign G[3] = A[3] & B[3];   // 第 3 位

    assign P[0] = A[0] ^ B[0];   // 第 0 位:两个输入不同时传播进位
    assign P[1] = A[1] ^ B[1];   // 第 1 位
    assign P[2] = A[2] ^ B[2];   // 第 2 位
    assign P[3] = A[3] ^ B[3];   // 第 3 位

    // 并行计算各级进位(只依赖输入 A、B 和 Cin,不依赖前一级进位)
    assign C[1] = G[0] | (P[0] & Cin);                    // C1 = G0 + P0·Cin
    assign C[2] = G[1] | (P[1] & G[0]) | (P[1] & P[0] & Cin);  // C2 = G1 + P1·G0 + P1·P0·Cin
    assign C[3] = G[2] | (P[2] & G[1]) | (P[2] & P[1] & G[0]) | (P[2] & P[1] & P[0] & Cin);
    assign C[4] = G[3] | (P[3] & G[2]) | (P[3] & P[2] & G[1]) | (P[3] & P[2] & P[1] & G[0]) | (P[3] & P[2] & P[1] & P[0] & Cin);

    // 每一位的和:S[i] = A[i] ^ B[i] ^ C[i] = P[i] ^ C[i]
    assign S[0] = P[0] ^ Cin;    // 最低位进位输入为 Cin
    assign S[1] = P[1] ^ C[1];   // 第 1 位进位为 C[1]
    assign S[2] = P[2] ^ C[2];   // 第 2 位进位为 C[2]
    assign S[3] = P[3] ^ C[3];   // 第 3 位进位为 C[3]

    assign Cout = C[4];          // 最高位进位输出
endmodule

这段代码中,所有进位 C[1]~C[4] 都是通过组合逻辑并行计算出来的,彼此之间没有依赖关系,因此关键路径延迟被压缩到常数级,这正是超前进位加法器相比行波进位加法器的核心优势。

5.4.3 性能对比
类型 关键路径延迟(4 位) 位宽扩展性 硬件复杂度
行波进位加法器(RCA) 8T(随位宽线性增长) 差,位宽越大越慢 低,结构简单
超前进位加法器(CLA) 约 3~4T(常数级) 好,位宽增大延迟基本不变 高,逻辑门数量多

小结:行波进位加法器胜在结构简单、面积小,适合对速度要求不高的场景;超前进位加法器以更多逻辑门为代价,换取了更短的进位链和更高的运算速度,常用于高性能处理器和 ALU 中。实际工程中,也常采用「超前进位 + 行波进位」混合的分组进位设计,在速度与面积之间取得平衡。

verilog 复制代码
module adder_4bit_tb;
    reg  [3:0] A, B;
    reg        Cin;
    wire [3:0] S;
    wire       Cout;

    adder_4bit uut(
        .A(A), .B(B), .Cin(Cin),
        .S(S), .Cout(Cout)
    );

    initial begin
        A = 4'b1011; B = 4'b0110; Cin = 1'b0;
        #10;
        // 期望结果:1011 + 0110 = 10001,S=0001,Cout=1
        $display("A=%b B=%b Cin=%b => S=%b Cout=%b", A, B, Cin, S, Cout);

        A = 4'b0101; B = 4'b0011; Cin = 1'b0;
        #10;
        // 期望结果:0101 + 0011 = 1000,S=1000,Cout=0
        $display("A=%b B=%b Cin=%b => S=%b Cout=%b", A, B, Cin, S, Cout);

        A = 4'b1111; B = 4'b0001; Cin = 1'b0;
        #10;
        // 期望结果:1111 + 0001 = 10000,S=0000,Cout=1
        $display("A=%b B=%b Cin=%b => S=%b Cout=%b", A, B, Cin, S, Cout);

        $finish;
    end
endmodule

6. 用 Python 模拟四位加法器

如果你没有硬件开发环境,也可以用 Python 来模拟四位加法器的行为,便于理解其工作原理。

python 复制代码
def full_adder(a, b, cin):
    """单比特全加器"""
    s = a ^ b ^ cin
    cout = (a & b) | (cin & (a ^ b))
    return s, cout

def adder_4bit(A, B, cin=0):
    """四位加法器:A、B 为 4 位二进制列表(低位在前)"""
    S = [0] * 4
    carry = cin
    for i in range(4):
        S[i], carry = full_adder(A[i], B[i], carry)
    return S, carry

# 测试:1011 + 0110 = 10001
A = [1, 1, 0, 1]  # 低位在前,即二进制 1011
B = [0, 1, 1, 0]  # 低位在前,即二进制 0110
S, cout = adder_4bit(A, B)
print("S =", S[::-1], "Cout =", cout)  # 输出:S = [0, 0, 0, 1],Cout = 1

7. 四位加法器的应用

四位加法器在实际工程中有广泛的应用场景:

  • 算术逻辑单元(ALU):加法器是 ALU 的核心部件,配合补码电路可以实现减法运算。下面给出一个简单的 4 位 ALU 设计示例,展示如何利用加法器实现加法和减法。
7.1 4 位 ALU 设计示例

减法运算可以通过补码实现:A - B = A + (~B + 1)。因此,我们只需在加法器的基础上增加一个控制信号 Sub,当 Sub=1 时对 B 取反并令进位输入为 1,即可完成减法。

verilog 复制代码
module alu_4bit(
    input  [3:0] A,
    input  [3:0] B,
    input        Sub,      // 0:加法,1:减法
    output [3:0] Result,
    output       Cout
);
    wire [3:0] B_eff;

    // 减法时对 B 取反(补码),加法时直接使用 B
    assign B_eff = Sub ? ~B : B;

    // 复用四位加法器:减法时进位输入置 1,实现 +1
    adder_4bit u_add(
        .A(A),
        .B(B_eff),
        .Cin(Sub),
        .S(Result),
        .Cout(Cout)
    );
endmodule

测试平台:

verilog 复制代码
module alu_4bit_tb;
    reg  [3:0] A, B;
    reg        Sub;
    wire [3:0] Result;
    wire       Cout;

    alu_4bit uut(
        .A(A), .B(B), .Sub(Sub),
        .Result(Result), .Cout(Cout)
    );

    initial begin
        // 加法:5 + 3 = 8
        A = 4'b0101; B = 4'b0011; Sub = 1'b0;
        #10;
        $display("5 + 3 = %d (Result=%b, Cout=%b)", Result, Result, Cout);

        // 减法:5 - 3 = 2
        A = 4'b0101; B = 4'b0011; Sub = 1'b1;
        #10;
        $display("5 - 3 = %d (Result=%b, Cout=%b)", Result, Result, Cout);

        // 减法:9 - 6 = 3
        A = 4'b1001; B = 4'b0110; Sub = 1'b1;
        #10;
        $display("9 - 6 = %d (Result=%b, Cout=%b)", Result, Result, Cout);

        $finish;
    end
endmodule

这里 Sub 同时充当了取反使能信号和最低位进位输入:减法时 B_eff = ~B、Cin = 1,正好完成 A + (~B) + 1 = A - B;加法时 B_eff = B、Cin = 0,即普通加法。这样一个简单的 ALU 就同时支持了加法和减法两种运算。

8. 扩展到八位加法器

掌握了四位加法器的设计后,扩展到八位加法器就非常直观了:只需实例化两个 adder_4bit 模块,将低四位加法器的进位输出连接到高四位加法器的进位输入即可。这种「模块级联」的方式与之前用全加器级联构建四位加法器的思路完全一致,只是把「全加器」这个基本单元换成了「四位加法器」这个更高层的模块。

8.1 级联方式与进位传递

八位加法器的结构如下:

  • 低四位 :adder_4bit 处理 A3:0 与 B3:0,其进位输入接外部 Cin,进位输出记为 c_mid。
  • 高四位 :另一个 adder_4bit 处理 A7:4 与 B7:4,其进位输入接 c_mid,进位输出即为最终的 Cout。

进位信号从最低位开始,先经过低四位加法器内部的进位链,再通过 c_mid 传入高四位加法器,继续在高四位内部逐级传播。因此八位行波进位加法器的关键路径延迟约为 2T × 8 = 16T,正好是四位加法器的两倍,符合「延迟随位宽线性增长」的规律。

8.2 Verilog 实现

verilog 复制代码
module adder_8bit(
    input  [7:0] A,
    input  [7:0] B,
    input        Cin,
    output [7:0] S,
    output       Cout
);
    wire c_mid;  // 低四位到高四位的进位

    // 低四位
    adder_4bit low(
        .A(A[3:0]),
        .B(B[3:0]),
        .Cin(Cin),
        .S(S[3:0]),
        .Cout(c_mid)
    );

    // 高四位
    adder_4bit high(
        .A(A[7:4]),
        .B(B[7:4]),
        .Cin(c_mid),
        .S(S[7:4]),
        .Cout(Cout)
    );
endmodule

8.3 简要说明

  • 两个 adder_4bit 模块通过中间进位线 c_mid 串联,低四位的进位输出恰好是高四位的进位输入,进位传递逻辑与四位加法器内部完全一致。
  • 这种层次化设计体现了硬件描述语言的核心思想:自顶向下、逐层复用。只要底层模块接口稳定,就可以像搭积木一样不断扩展位宽。
  • 同理,若要构建十六位加法器,只需再实例化两个 adder_8bit 模块,或直接实例化四个 adder_4bit 模块,级联方式完全相同。

8. 总结

本文从二进制加法规则出发,依次介绍了半加器、全加器,并通过级联四个全加器构建了四位加法器。核心要点如下:

  • 半加器处理两个一位输入,不考虑进位输入。
  • 全加器增加进位输入,是构建多位加法器的基本单元。
  • 四位加法器通过级联四个全加器实现,前级进位输出接后级进位输入。
  • 最低位的进位输入通常置 0。

掌握了四位加法器的设计思路,你就可以进一步扩展到八位、十六位加法器,甚至设计更复杂的算术运算单元。

相关推荐
老当益壮梁奶奶1 小时前
驱动学习(二):从零开始:驱动工程搭建与字符设备驱动框架详解(基于IMX6ULL)
c语言·arm开发·驱动开发·嵌入式硬件·学习
Yyq130208696821 小时前
紫荆M100,RISC-V开源架构,工业控制,电机驱动,国产替代
单片机·嵌入式硬件·risc-v
2501_922639582 小时前
率能半导体 SS6208L半桥MOSFET驱动器:12V/4A集成方案,覆盖电子烟、无线充电、半桥应用三大场景
单片机·嵌入式硬件·硬件工程
尼喃3 小时前
平芯微HY2120-CB充放电一体化:充电口与放电口合并电路原理图
嵌入式硬件
国科安芯13 小时前
立方星与微纳卫星综合电子微型化趋势下的抗辐射MCU选型综述
人工智能·单片机·嵌入式硬件·mcu·risc-v·抗辐射
xunyan623413 小时前
3-1 独立按键控制LED亮灭(SDCC + Notepad++ + STC-ISP/普中ISP)
单片机·嵌入式硬件·接口隔离原则
WD1372980155713 小时前
WD5030L,为充电桩、工业设备、5G 基站、车载系统、消费电子提供电源,7-30V 的宽压输入
stm32·单片机·嵌入式硬件·5g·车载系统·51单片机
创界工坊工作室15 小时前
30-基于STM32的小麦烘干塔温度控制系统设计
stm32·单片机·嵌入式硬件·proteus
单片机仿真设计17 小时前
【proteus仿真设计】基于 STM32 的开荒机器人遥控控制系统设计(仿真图+程序)
stm32·嵌入式硬件·机器人·proteus