从 8086 到 80386,处理器的算术逻辑单元经历了一次根本性的架构重构。8086 的乘法指令采用微码控制下的迭代移位加法循环,每执行一次 16 位乘法需要消耗大约 200 个时钟周期,这种性能瓶颈在 32 位计算时代变得不可接受。80386 的设计团队选择为乘除运算分配独立的硬件单元,配合 Radix-4 Booth 重编码算法,实现了 9 至 41 个周期的 32 位乘法性能,首次在 x86 架构中引入了真正意义上的硬件乘法器。
从迭代到流水线:8086 与 80386 的乘法实现差异
8086 处理器的乘法单元本质上是一个被微码驱动的简单移位加法器。当执行 MUL 或 IMUL 指令时,控制单元会重复执行一个固定的微序列:检查乘数的最低位,如果为 1 则将被乘数加到部分积寄存器,然后整体右移一位。这个过程对于 N 位操作数需要恰好 N 次迭代,16 位乘法对应 16 次循环,每次循环包含移位、条件加法和状态更新等多个微操作。80286 虽然将主频提升至 12 MHz,但乘法运算的结构基本沿袭 8086,性能提升主要来自时钟频率而非架构优化。
80386 的设计者意识到,要支撑 32 位计算和日益复杂的图形与数字信号处理应用,必须为乘法运算配备专用硬件。这个被称为「乘除法单元」(Multiply/Divide Unit,MDU)的模块独立于主 ALU 运行,采用三级流水线结构:第一级由 Booth 编码器生成部分积选择信号,第二级通过进位保存加法器阵列压缩多个部分积,第三级由超前进位加法器输出最终结果。这种架构将乘法运算的延迟从与操作数位数线性相关改为与有效数字位数相关,使得大多数情况下 32 位乘法的实际耗时远低于最坏情况。
Radix-4 Booth 重编码:减少一半迭代次数的关键技术
Radix-4 Booth 重编码是 80386 乘法器性能提升的核心。与原始的 Radix-2 Booth 算法每次检查 1 位乘数不同,Radix-4 算法每次处理 2 位乘数并参考前 1 位的状态,从而将迭代次数从 N 减少到 N/2。对于 32 位操作数,这意味着只需 16 次迭代即可完成乘法,而非 32 次。更重要的是,Radix-4 编码支持 ±1 和 ±2 倍的被乘数选择,相比 Radix-2 仅有 ±1 倍的选择范围,能够更有效地压缩连续零或连续一带来的冗余操作。
具体而言,Radix-4 Booth 编码器根据当前两位乘数位(记为 y_i 和 y_{i+1})以及前一次的移出位(y_{i-1})生成三位选择信号,决定当前周期应当向部分积加 0、被乘数、被乘数的两倍、被乘数的负数,还是被乘数负数的两倍。这个编码过程可以在一个时钟周期内完成,且编码结果直接驱动部分积生成电路。80386 的部分积阵列将 16 个部分积压缩为两个中间值,随后通过超前进位加法器在单周期内完成最终求和。这种并行处理方式使得乘法器的吞吐量大幅提升,尽管单次乘法的绝对延迟仍受制于进位链的长度。
除法的复杂性:为何需要更多时钟周期
80386 的除法运算没有采用与乘法相同的硬件加速策略,而是使用了更为复杂的恢复余数算法(Restoring Division),导致无符号 32 位除法需要 38 个时钟周期,有符号除法需要 43 个周期。这个数字远高于乘法器的 9 至 41 周期范围,反映出除法运算在硬件实现上的本质困难。
除法的核心挑战在于每一位的商位确定依赖于前一位的余数结果,无法像乘法那样通过 Booth 编码一次性生成所有部分积。每一步除法迭代都需要将被除数或中间余数左移一位,然后尝试减去除数,根据结果决定商位并可能恢复余数。这种串行依赖关系使得除法运算难以通过并行化或流水线化获得显著的性能提升。此外,有符号除法还需要额外的符号处理和修正步骤,包括将负数转换为正数进行运算、调整商的符号、处理边界情况(如除数为负一时可能导致的溢出)等,这些额外逻辑进一步延长了指令的执行周期。
从芯片面积的角度看,乘法器已经占用了相当数量的晶体管来实现 Booth 编码器和进位保存加法器阵列。如果为除法单元配备同等规模的并行化硬件,整个 MDU 的面积将超过合理范围,对于当时 1.5 微米工艺下 275,000 晶体管的总预算而言是不经济的。因此,80386 选择用微码控制下的专用硬件执行除法运算,在保持相对较小面积的同时提供了可接受的性能。
硬件权衡与历史遗留问题
80386 的乘除法单元设计体现了典型的工程权衡。在乘法性能方面,Radix-4 Booth 编码配合进位保存加法器实现了接近理论极限的效率,同时保持硬件复杂度在可控范围内。周期数从 8086 的约 200 周期大幅缩短至最好情况下的 9 周期,最坏情况 41 周期也远优于前代产品。这种可变延迟设计意味着乘法指令的实际执行时间取决于操作数的位模式,对于包含大量连续零或连续一的操作数,Booth 编码能够跳过不必要的加法步骤,从而获得更快的执行速度。
然而,早期版本的 80386 处理器存在一个著名的乘法缺陷。在某些特定操作数组合下,32 位乘法可能产生错误的结果。这个 bug 的成因与 Booth 编码器在处理边界情况时的状态机实现有关,导致部分积选择信号出错。受影响的芯片被 Intel 标记为「16-bit S/W ONLY」,意味着它们只能可靠地运行 16 位软件,不适合用于需要 32 位乘法运算的现代操作系统和应用程序。这个事件也促使后续处理器在微架构验证方面投入更多资源,包括形式化验证和更广泛的测试覆盖。
从系统设计的视角来看,80386 的 MDU 单元为后续 x86 处理器奠定了乘除法硬件的基础架构。80486 进一步将乘法延迟压缩至单周期,同时引入除法微操作缓存来加速重复除法运算。Pentium 系列的超标量架构则允许在一个时钟周期内发射一条乘法指令和一条独立运算的指令,实现了更高的指令级并行度。这些演进都可以追溯到 80386 首次在芯片上实现专用乘除法硬件的设计决策。
工程参数与实践意义
对于系统程序员和编译器开发者而言,理解 80386 乘除法单元的时序特性具有直接的优化价值。乘法指令的 9 至 41 周期可变延迟意味着编译器应当尽量将乘法操作安排在不会阻塞后续指令的位置,例如放在循环展开后的并行调度区间,或者利用超标量处理器的独立执行单元同时发射乘法和算术逻辑指令。对于性能敏感的数字信号处理代码,选择具有良好位模式特性的乘数可以触发 Booth 编码的优化路径,从而获得接近最佳情况的执行速度。
除法指令的固定 38 至 43 周期延迟则更易于进行静态时序分析。编译器应当将除法操作从关键路径中移除,或者在可能的情况下使用移位和乘法近似替代。例如,除以常数 3 可以改写为乘以 0xAAAAAAAB 后进行位调整,这种技术不仅适用于 80386,在现代处理器上仍能带来显著的性能收益。操作系统在进行任务切换时也应当注意保存乘除法单元的状态,因为 80386 的乘除法操作会使用隐式的中间寄存器,切换上下文时必须正确处理这些隐藏的状态。
80386 的乘除法单元代表了 1980 年代中期处理器设计的一个重要里程碑。它标志着 x86 架构从通用 ALU 加微码控制向专用加速单元的转型,为后续数十年的性能演进奠定了硬件基础。理解其 Radix-4 Booth 编码和除法算法的实现细节,不仅有助于深入认识计算机算术的底层原理,也为当代硬件设计提供了有价值的参考案例。
参考资料
- Intel Corporation, Introduction to the 80386, April 1986.
- Intel Corporation, 80386 Programmer's Reference Manual, 1986.
- Hennessy, John L., and Patterson, David A., Computer Architecture: A Quantitative Approach, Chapter on Arithmetic.