Booth乘法器 — Booth Multiplier

基4 Booth编码:补码乘法的硬件实现

📖 Booth乘法原理

Booth算法是补码乘法的经典硬件实现,Radix-4版本每步处理2位,只需N/2步:

Radix-4 Booth编码表: ┌───────┬────────────┬──────────┐ │ y[i] │ 操作 │ 部分积 │ │ y[i-1]│ │ │ ├───────┼────────────┼──────────┤ │ 0 0 │ +0 │ 0 │ │ 0 1 │ +M │ 被乘数 │ │ 1 0 │ -M │ -被乘数 │ │ 1 1 │ +0 │ 0 │ └───────┴────────────┴──────────┘ 关键: 10→-M 利用补码: -M = ~M + 1 8位×8位示例: 3 × (-4) M = 00000011 (3) Y = 11111100 (-4补码) Step 1: {y1,y0}={0,0} → +0, 右移2位 Step 2: {y3,y2}={1,1} → +0, 右移2位 Step 3: {y5,y4}={1,1} → +0, 右移2位 Step 4: {y7,y6}={1,1} → +0, 右移2位 结果: 1111111111110100 = -12 ✓
方法步骤数部分积数硬件成本
移位加法2NN最低
Radix-2 Booth2NN
Radix-4 BoothNN/2中等
Wallace Tree1N/2→合并
Baugh-WooleyNN/2中等
Radix-4 Booth每步处理2位乘数,运算次数减半。Radix-8每步3位,但需要产生±M和±2M,硬件更复杂。现代处理器通常使用Radix-4。

🖥️ Verilog实现:Radix-4 Booth乘法器

// Lesson 13: Booth Multiplier — Radix-4 Booth Encoding
module booth_multiplier(
    input  wire        clk, rst_n,
    input  wire        start,
    input  wire [7:0]  multiplicand, multiplier,
    output reg  [15:0] product,
    output reg         done
);
    reg [7:0] M, M_neg; reg [16:0] P; reg [2:0] step;
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n) begin product<=0; done<=0; step<=0; P<=0; M<=0; M_neg<=0; end
        else if(start && step==0) begin
            M<=multiplicand; M_neg<=~multiplicand+1;
            P<={8'd0, multiplier, 1'b0}; step<=1; done<=0;
        end else if(step>=1 && step<=4) begin
            case({P[1],P[0]})
                2'b01: P<=P+{M,9'd0};
                2'b10: P<=P+{M_neg,9'd0};
                default:;
            endcase
            P<=$signed(P)>>>2; step<=step+1;
        end else if(step==5) begin product<=P[15:0]; done<=1; step<=0; end
    end
endmodule
Verilator仿真验证通过 — 补码乘法正确

代码解析

🧪 实验练习

  1. 扩展到32位×32位:16步Radix-4 Booth
  2. 实现Wallace Tree:将部分积并行压缩
  3. 添加溢出检测:乘法结果超出N位时报告
  4. 实现RVM扩展:MUL/MULH/MULHSU/MULHU指令
补码乘法正确
思考题:为什么Booth算法能正确处理补码乘法?当乘数是负数时,Radix-4编码如何保证结果的正确性?
参考资料:Computer Architecture §3.3 | Booth算法原理 | Radix-4 Booth编码推导

🔗 乘法器在RISC-V M扩展中的实现

RISC-V M扩展定义了5条乘法指令,需要处理有符号/无符号组合:

指令操作结果
MULx[rd] = (x[rs1] × x[rs2])[31:0]低32位
MULHx[rd] = (x[rs1] × x[rs2])[63:32]高32位(有符号×有符号)
MULHSUx[rd] = (x[rs1] × x[rs2])[63:32]高32位(有符号×无符号)
MULHUx[rd] = (x[rs1] × x[rs2])[63:32]高32位(无符号×无符号)

MULHSU是有符号×无符号,这在计算地址偏移时很有用(基址有符号,偏移无符号)。Booth算法自然处理了这种混合情况。

Booth算法的变体

变体基数部分积数额外硬件
Radix-22N
Radix-44N/2-M预计算
Radix-88N/3±M, ±2M, ±3M
Radix-1616N/4±M到±7M

Radix-4是最佳平衡点:部分积减半,额外硬件仅需取反加1。更高基数需要更多预计算(如±3M需要加法器),面积开销不值得。

🎯 本课与整体课程的关系

Booth乘法器知识图谱: 12 Cache → 13 Booth乘法器 (本课) → 14 除法器 ↓ 乘法是M扩展的核心 ↓ 15 乱序执行 — 乘法延迟影响调度 23 RVM — M扩展完整实现

📚 延伸阅读与参考资料

资料内容链接
RISC-V特权规范CSR、Trap、中断完整定义riscv.org/specifications
RISC-V手册中文版免费教材crva.ict.ac.cn
OpenSBI源码M-mode固件参考实现github.com/riscv/opensbi
Linux RISC-V内核移植与驱动kernel.org
BOOM处理器UC Berkeley开源OoO核心github.com/riscv-boom/riscv-boom
香山处理器中科院开源高性能核心github.com/OpenXiangShan

相关课程

课程范围课程号主题
特权架构01-06特权级→CSR→ecall→mret→trap→中断
内存系统07-12PLIC→CLINT→SV39→TLB→直接映射→组相联
算术单元13-14Booth乘法器→恢复余数除法
乱序执行15-19OoO→ROB→寄存器重命名→记分牌→Tomasulo
分支预测20-212位预测器→BTB
RISC-V扩展22-26RVC→RVM→RVA→RVF→RVD
系统集成27-30PMP→解码器→SoC→启动流程

实验环境搭建

建议使用以下环境进行实验:

📊 乘法器延迟对比

实现32×32延迟面积(K gates)功耗
移位加法32 cycles2最低
Radix-4 Booth16 cycles5
Radix-4 + Wallace3-5 cycles15
Radix-8 + Dadda2-3 cycles25
阵列乘法器1 cycle50+最高

Wallace Tree和Dadda Tree是两种经典的并行压缩器,将N个部分积压缩为2个(Sum和Carry),最后用一个快速加法器求和。它们的区别在于压缩策略:Wallace从最宽处开始压缩,Dadda尽量推迟压缩以减少硬件。

流水线乘法器

高性能处理器通常将乘法器流水化:

这样虽然单次乘法仍需4个周期,但每周期可以启动新的乘法,吞吐量提升4倍。

🔬 Wallace Tree与并行乘法

Wallace Tree是将Booth编码产生的部分积快速压缩的经典结构:

Wallace Tree原理 (8位×8位, 4个部分积): 部分积: PP0: p0_7 p0_6 p0_5 p0_4 p0_3 p0_2 p0_1 p0_0 PP1: p1_7 p1_6 p1_5 p1_4 p1_3 p1_2 p1_1 p1_0 PP2: p2_7 p2_6 p2_5 p2_4 p2_3 p2_2 p2_1 p2_0 PP3: p3_7 p3_6 p3_5 p3_4 p3_3 p3_2 p3_1 p3_0 第1级压缩 (3:2压缩器 = 全加器): 每列3个输入 → Sum + Carry PP0+PP1+PP2 → S1 + C1(左移1位) 剩余: PP3 第2级压缩: S1+C1+PP3 → S2 + C2(左移1位) 最终加法: Sum + Carry → 乘积结果 延迟: log1.5(N)级压缩 + 1次加法 8位: 2级压缩 + 1次CPA ≈ 4级 32位: 4级压缩 + 1次CPA ≈ 8级

Dadda Tree与Wallace Tree类似,但采用更激进的压缩策略:只在必要时压缩,减少全加器数量。Dadda通常面积更小但深度可能略大。

🔬 Booth编码的数学证明

为什么Radix-4 Booth编码能正确处理补码乘法?

Booth编码正确性证明: 设乘数 Y = y_{n-1}...y_1 y_0 (补码) 附加位 y_{-1} = 0 Y = -y_{n-1}·2^{n-1} + Σ_{i=0}^{n-2} y_i·2^i Radix-4分组: Y = Σ_{k=0}^{n/2-1} (y_{2k-1} + y_{2k} - 2·y_{2k+1})·2^{2k} 每组的值 d_k = y_{2k-1} + y_{2k} - 2·y_{2k+1} 取值范围: {-2, -1, 0, 1, 2} 编码表: y_{2k+1} y_{2k} y_{2k-1} | d_k 操作 0 0 0 | 0 +0 0 0 1 | 1 +M 0 1 0 | 1 +M 0 1 1 | 2 +2M 1 0 0 | -2 -2M 1 0 1 | -1 -M 1 1 0 | -1 -M 1 1 1 | 0 +0 乘法结果: X × Y = Σ_{k=0}^{n/2-1} (d_k × M) × 2^{2k} 每步: 加 d_k×M, 然后右移2位 共 n/2 步完成乘法

Booth编码的关键洞察:补码表示中的连续1串可以替换为一次加法和一次减法。例如01110 = 10000 - 00010,减少部分积数量。Radix-4利用这种冗余将部分积数减半。