Lesson 15

➕ 串行加法器

🏆 逐位进位仿真正确
✅ Verilator仿真验证通过

📖 实验描述

实现8位串行加法器,每周期处理1位,保留进位链,逐位完成多位加法运算。

串行加法器是最基础的加法器结构。与并行加法器一次性计算所有位不同,串行加法器每次只处理1位,利用时序逻辑在时钟驱动下逐位计算。 核心原理:全加器 FA(a, b, cin) = (sum, cout),其中 sum = a XOR b XOR cin,cout = (a AND b) OR (a AND cin) OR (b AND cin)。 8位串行加法需要9个时钟周期(8位数据+1位进位输出),面积仅为1个全加器+寄存器,远小于8位超前进位加法器的面积。 这种结构在面积受限的FPGA设计中很有价值,也帮助理解加法器的进位传播本质。2024年RISC-V Tiny核心仍采用串行ALU节省面积。

🧠 核心概念

📐 电路结构

电路与状态图
串行加法器结构:

  a[i] → ┐
  b[i] → ├─ FA ──→ sum[i]
  c    → ┘    └──→ c_next

  每周期:
  1. 取 a[bit_idx] 和 b[bit_idx]
  2. sum_bit = a_bit ^ b_bit ^ c
  3. c_next = (a_bit & b_bit) | (a_bit & c) | (b_bit & c)
  4. 存 c_next → c,sum[bit_idx] ← sum_bit
  5. bit_idx++

  8周期后:carry_out = c

📝 设计步骤

  1. 1初始化:bit_idx=0, carry=0
  2. 2取当前位:a_bit=a[bit_idx], b_bit=b[bit_idx]
  3. 3计算和:sum_bit = a_bit ^ b_bit ^ carry
  4. 4计算进位:carry_next = majority(a_bit, b_bit, carry)
  5. 5存储结果:sum[bit_idx] ← sum_bit, carry ← carry_next
  6. 6递增索引:bit_idx++,若=8则输出done
  7. 7最终:carry_out = carry(溢出标志)

💻 Verilog实现

serial_adder.svSystemVerilog · Verilator 5.020
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
// Serial Adder - 逐位串行加法器
// 每周期处理1位,保留进位,逐位完成多位加法
module serial_adder(
    input  wire clk,
    input  wire rst,
    input  wire start,
    input  wire [7:0] a,
    input  wire [7:0] b,
    output reg  [7:0] sum,
    output reg  carry_out,
    output reg  done
);

reg [3:0] bit_idx;
reg c;
reg running;

always @(posedge clk or posedge rst) begin
    if (rst) begin
        sum       <= 8'd0;
        carry_out <= 1'b0;
        done      <= 1'b0;
        bit_idx   <= 4'd0;
        c         <= 1'b0;
        running   <= 1'b0;
    end else begin
        done <= 1'b0;
        
        if (start && !running) begin
            // Start new computation
            running <= 1'b1;
            bit_idx <= 4'd0;
            c       <= 1'b0;
            sum     <= 8'd0;
        end
        
        if (running) begin
            if (bit_idx < 4'd8) begin
                reg abit, bbit, s;
                abit = a[bit_idx[2:0]];
                bbit = b[bit_idx[2:0]];
                s    = abit ^ bbit ^ c;
                c    <= (abit & bbit) | (abit & c) | (bbit & c);
                sum[bit_idx[2:0]] <= s;
                bit_idx <= bit_idx + 4'd1;
            end else begin
                carry_out <= c;
                done      <= 1'b1;
                running   <= 1'b0;
            end
        end
    end
end

endmodule

🔬 仿真说明

仿真环境与策略

测试3组数据:(1) 123+89=212, carry=0 (2) 200+100=44, carry=1 (3) 255+1=0, carry=1。所有结果与预期完全一致。

✅ 验证结果

Verilator 5.020 仿真通过

本实验所有Verilog代码已通过Verilator编译验证,功能行为正确。测试用例覆盖核心功能路径,确保设计满足规格要求。

⚠️ 常见错误

🌍 真实世界

工业应用

串行加法器在面积受限场景(如ASIC加密模块、低功耗MCU)中仍有应用。现代处理器使用超前进位(CLA)或进位选择加法器实现高速并行加法,但串行加法器帮助理解进位传播的本质。2024年RISC-V的Tiny核心仍使用串行ALU以节省面积。

💡 扩展挑战

🚀 自己动手

# 编译并运行
verilator --cc serial_adder.sv --exe serial_adder_tb.cpp --build -j 0
./obj_dir/Vserial_adder

🎯 试一试

修改参数

尝试修改代码中的关键参数,观察仿真结果变化:

  • 调整位宽,观察不同数据范围
  • 修改初始值/种子,观察不同起始条件
  • 改变时钟分频,测试不同速度

💡 Verilator会在位宽不匹配时给出Warning,这是学习的好机会

添加功能

在现有基础上增加新功能:

  • 添加新的输入信号和控制逻辑
  • 增加状态或修改状态转移条件
  • 扩展输出,增加更多显示信息

🔧 增量开发:每次只改一个地方,验证通过后再改下一个

📋 Verilog速查

语法说明示例
reg [7:0]8位寄存器reg [7:0] data;
wire组合逻辑连线wire valid = cnt > 5;
always @(posedge clk)时序逻辑上升沿触发
always @(*)组合逻辑敏感列表自动推导
localparam局部常量localparam DIV = 50000000;
case多分支选择注意default分支
$display仿真打印不可综合,仅仿真用

📊 性能指标

资源估算(FPGA参考)

本设计在典型FPGA上的资源占用估算:LUT约20-120个,FF约30-100个,无BRAM/DSP依赖(特殊模块除外)。时钟频率可达50-100MHz+。Verilator仿真速度约5-10M周期/秒。

← 上一课 📚 目录 下一课 →