第04课 · 加法器
算术电路半加器全加器RCA
📌 学习目标:从半加器→全加器→4位行波进位加法器(RCA),逐步构建算术运算电路,并使用 Verilator 验证每一步的正确性。
一、半加器(Half Adder)
半加器是最简单的加法电路,将两个1位二进制数相加,产生和(Sum)与进位(Carry)。
Sum = A ⊕ B
Carry = A · B
| A | B | Sum | Carry |
| 0 | 0 | 0 | 0 |
| 0 | 1 | 1 | 0 |
| 1 | 0 | 1 | 0 |
| 1 | 1 | 0 | 1 |
⚠️ 半加器不能处理来自低位的进位输入,因此无法级联构成多位加法器。
二、全加器(Full Adder)
全加器在半加器基础上增加了进位输入 Cin,可以级联构成任意位宽的加法器。
Sum = A ⊕ B ⊕ Cin
Cout = (A · B) + (Cin · (A ⊕ B))
= (A · B) + (A · Cin) + (B · Cin)
| Cin | A | B | Sum | 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 |
三、行波进位加法器(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 实现
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
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 测试台
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
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;
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;
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;
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;
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