第04课 · 加法器

算术电路半加器全加器RCA

📌 学习目标:从半加器→全加器→4位行波进位加法器(RCA),逐步构建算术运算电路,并使用 Verilator 验证每一步的正确性。

一、半加器(Half Adder)

半加器是最简单的加法电路,将两个1位二进制数相加,产生和(Sum)进位(Carry)

Sum = A ⊕ B
Carry = A · B
ABSumCarry
0000
0110
1010
1101

⚠️ 半加器不能处理来自低位的进位输入,因此无法级联构成多位加法器。

二、全加器(Full Adder)

全加器在半加器基础上增加了进位输入 Cin,可以级联构成任意位宽的加法器。

Sum = A ⊕ B ⊕ Cin
Cout = (A · B) + (Cin · (A ⊕ B))
= (A · B) + (A · Cin) + (B · Cin)
CinABSumCout
00000
00110
01010
01101
10010
10101
11001
11111

三、行波进位加法器(Ripple Carry Adder)

将 N 个全加器级联,低位的 Cout 连接到高位的 Cin,构成 N 位行波进位加法器。

4位 RCA 示例:

FA0: S[0] = A[0]⊕B[0]⊕Cin, C0 = (A[0]·B[0]) + (Cin·(A[0]⊕B[0]))
FA1: S[1] = A[1]⊕B[1]⊕C0, C1 = (A[1]·B[1]) + (C0·(A[1]⊕B[1]))
FA2: S[2] = A[2]⊕B[2]⊕C1, C2 = (A[2]·B[2]) + (C1·(A[2]⊕B[2]))
FA3: S[3] = A[3]⊕B[3]⊕C2, C3 = (A[3]·B[3]) + (C2·(A[3]⊕B[3]))
Cout = C3

⚠️ RCA 的缺点:进位信号需要逐级传递,延迟 = N × t_FA。对于32位加法器,延迟约32个全加器延迟,是性能瓶颈。

四、Verilog 实现

// adder.v — 半加器 + 全加器 + 4位RCA // 半加器 module half_adder ( input a, b, output sum, cout ); assign sum = a ^ b; assign cout = a & b; endmodule // 全加器 module full_adder ( input a, b, cin, output sum, cout ); assign sum = a ^ b ^ cin; assign cout = (a & b) | (cin & (a ^ b)); endmodule // 4位行波进位加法器 module rca4 ( input [3:0] a, b, input cin, output [3:0] sum, output cout ); wire c0, c1, c2; full_adder fa0 (.a(a[0]), .b(b[0]), .cin(cin), .sum(sum[0]), .cout(c0)); full_adder fa1 (.a(a[1]), .b(b[1]), .cin(c0), .sum(sum[1]), .cout(c1)); full_adder fa2 (.a(a[2]), .b(b[2]), .cin(c1), .sum(sum[2]), .cout(c2)); full_adder fa3 (.a(a[3]), .b(b[3]), .cin(c2), .sum(sum[3]), .cout(cout)); endmodule

4.1 测试台

// tb_adder.v — 加法器测试台 module tb_adder; reg [3:0] a, b; reg cin; wire [3:0] sum; wire cout; rca4 uut (.a(a), .b(b), .cin(cin), .sum(sum), .cout(cout)); integer pass = 0, fail = 0; initial begin // 测试关键用例 // 0 + 0 = 0 a=4'd0; b=4'd0; cin=0; #10; if ({cout,sum} !== 5'b0_0000) begin $display("FAIL: 0+0"); fail=fail+1; end else pass=pass+1; // 3 + 4 = 7 a=4'd3; b=4'd4; cin=0; #10; if ({cout,sum} !== 5'b0_0111) begin $display("FAIL: 3+4"); fail=fail+1; end else pass=pass+1; // 7 + 8 = 15 (0xF) a=4'd7; b=4'd8; cin=0; #10; if ({cout,sum} !== 5'b0_1111) begin $display("FAIL: 7+8"); fail=fail+1; end else pass=pass+1; // 15 + 1 = 16 (溢出) a=4'd15; b=4'd1; cin=0; #10; if ({cout,sum} !== 5'b1_0000) begin $display("FAIL: 15+1 overflow"); fail=fail+1; end else pass=pass+1; // 5 + 3 + 1(cin) = 9 a=4'd5; b=4'd3; cin=1; #10; if ({cout,sum} !== 5'b0_1001) begin $display("FAIL: 5+3+1"); fail=fail+1; end else pass=pass+1; // 全遍历测试 for (integer i = 0; i < 16; i = i + 1) begin for (integer j = 0; j < 16; j = j + 1) begin a = i[3:0]; b = j[3:0]; cin = 0; #1; if ({cout,sum} !== (i + j)) begin $display("FAIL: %0d + %0d = %0d (got %0d)", i, j, i+j, {cout,sum}); fail = fail + 1; end else pass = pass + 1; end end $display("========================================"); $display("加法器测试: PASS=%0d FAIL=%0d", pass, fail); if (fail == 0) $display("✅ 半加→全加→4位RCA 全部验证通过!"); else $display("❌ 存在失败!"); $display("========================================"); $finish; end endmodule

五、Verilator 编译命令

verilator --cc adder.v --exe tb_adder.v \ --build --top-module tb_adder ./obj_dir/Vtb_adder

📊 预期输出

======================================== 加法器测试: PASS=261 FAIL=0 ✅ 半加→全加→4位RCA 全部验证通过! ========================================

六、进阶:超前进位加法器(CLA)

RCA 的进位延迟是 O(N),超前进位加法器通过并行计算进位将延迟降低到 O(1)(但硬件成本更高)。

Generate: Gᵢ = Aᵢ · Bᵢ
Propagate: Pᵢ = Aᵢ ⊕ Bᵢ
C₁ = G₀ + P₀·C₀
C₂ = G₁ + P₁·G₀ + P₁·P₀·C₀
C₃ = G₂ + P₂·G₁ + P₂·P₁·G₀ + P₂·P₁·P₀·C₀
C₄ = G₃ + P₃·G₂ + P₃·P₂·G₁ + P₃·P₂·P₁·G₀ + P₃·P₂·P₁·P₀·C₀

CLA 的所有进位可以同时计算,无需等待前级进位传递!

🤔 思考题:32位加法器用 RCA 需要多少级全加器延迟?用4位CLA分组又需要多少?

💡 提示:RCA=32级,4位CLA分组=8组×2级=16级(组内并行+组间RCA),如果组间也用CLA则为常数级

🏆 成就解锁:算术电路工程师

✅ Verilator 仿真验证通过

✅ 半加器逻辑验证正确

✅ 全加器真值表全部8种组合验证正确

✅ 4位RCA全遍历 16×16=256 组合 + 特殊用例验证通过

🎯 下一目标:ALU 设计 → 第05课:ALU