Microcode in Intel's 8087 floating-point chip: the scale instruction
130 points
• 2 days ago
• Article
Link
Intel 8087 于 1980 年问世,通过为浮点运算建立严格的标准而彻底改变了计算领域。 在此之前,业界的浮点实现常常不一致、精度不足。 8087 以高速且数学上准确的计算改变了这种局面,并最终为几乎所有现代计算机采用的 IEEE 754 标准奠定了基础。 芯片性能的核心是一套复杂的微代码引擎,它不仅完成常规算术,还处理大量棘手的边界情况。
要理解 8087 的工作方式,观察其架构很有帮助:指数采用 16 位数据通路,有效数字采用 64 位数据通路。芯片使用内部寄存器存储 80 位数值,其中包含一个符号位、 15 位指数和 64 位有效数字。架构的一个关键部件是微代码 ROM,其中含有 1648 条微指令。对这些指令的逆向工程揭示了芯片如何处理复杂任务,例如通过调整指数按二的幂缩放数值的 FSCALE 指令。
FSCALE 本身就是 8087 隐藏复杂性的典型例子。表面上它很简单,但在实现上需要超过 140 条微指令和多次子程序调用,以应对各种特殊情况。微代码必须处理零、无穷大和 Not-a-Number(NaN)等条目,以及溢出和下溢情形。这个过程包括用桶形移位器对浮点参数进行精确移位以转换为整数、更新指数,并通过指数转换器和加法器等内部电路谨慎管理舍入模式。
芯片的大量智能体现在处理"特殊"参数和非规范结果的子程序中。例如,为了在接近零时保持精度,8087 能处理非规格化数(denormalized numbers),这些数在有效数字中不含前导 1 。 8087 还采用了复杂的舍入机制,跟踪保护位、舍入位和粘滞位,以保证即便必须舍入,结果也尽可能精确,这也是它能成功取代基于软件的浮点仿真器的原因之一。
总的来说,8087 之所以成功,是因为它在保持高可靠性的同时,把大量数学计算从主处理器中卸载出来。通过专用硬件电路与详尽微代码的结合,它有效地收拾了早期浮点标准的混乱。如今,像 Opcode Collective 这样的团体持续进行的逆向工程工作,继续揭示这块开创性硬件如何为我们在现代计算中仍依赖的数值稳定性和性能奠定基础。
The Intel 8087, introduced in 1980, revolutionized computing by establishing a rigorous standard for floating-point arithmetic. Before its release, the industry suffered from inconsistent and imprecise floating-point systems. The 8087 changed this landscape by providing high-speed, mathematically accurate calculations, which eventually paved the way for the IEEE 754 standard used in nearly all modern computers. At the heart of this chip's performance was a complex microcode engine that handled everything from standard arithmetic to a vast array of challenging edge cases.
To understand how the 8087 operates, it is helpful to look at its architecture, which is split into a 16-bit datapath for exponents and a 64-bit datapath for significands. The chip uses internal registers to store 80-bit numbers, which include a sign bit, a 15-bit exponent, and a 64-bit significand. A crucial component of this architecture is the microcode ROM, which contains 1648 micro-instructions. Reverse-engineering these instructions reveals how the chip manages complex tasks, such as the FSCALE instruction, which scales a number by a power of two by manipulating its exponent.
The FSCALE instruction itself is a prime example of the 8087's hidden complexity. While conceptually simple, it requires over 140 micro-instructions and multiple subroutine calls to manage various special conditions. The microcode must handle zero values, infinities, and Not-a-Number (NaN) entries, as well as overflow and underflow scenarios. The process involves converting floating-point arguments into integers through precise shifts using a barrel shifter, updating the exponent, and carefully managing rounding modes through internal circuitry like the exponent converter and the adder.
A significant portion of the chip's intelligence resides in subroutines that handle "special" arguments and non-normal results. For instance, the chip can manage denormalized numbers, which are extremely small values that lack a leading 1 in their significand, to maintain precision near zero. The 8087 also employs a sophisticated rounding system that tracks guard, round, and sticky bits. This hardware ensures that even when a value must be rounded, the result remains as accurate as possible, demonstrating why the 8087 was so effective at replacing software-based floating-point emulators.
Ultimately, the 8087 succeeded because it offloaded intensive mathematical work from the main processor while maintaining exceptional reliability. By using a mix of specialized hardware circuits and detailed microcode, it effectively managed the "anarchy" of early floating-point standards. Today, the ongoing reverse-engineering efforts by groups like the Opcode Collective continue to shed light on how this pioneering piece of hardware established the foundations of numerical stability and performance that we still rely on in modern computing.
50 comments • Comments Link
• 8087 协处理器通过允许浮点运算与整数指令并行执行,为早期 x86 系统中的数学密集型应用带来了显著的性能提升。
• 早期 x86 微架构需要手工、指令级的调度来充分利用超标量能力,这与现代通过乱序执行透明管理流水线的方式形成鲜明对比。
• x87 架构由于基于栈的设计,对编译器而言具有独特挑战,需要复杂的寄存器交换、溢出管理以及对 80 位扩展精度值的不一致处理办法。
• 现代编译器与处理器更倾向于使用 SIMD 单元(SSE/AVX),因为它们提供标准化的单精度和双精度类型,避免了 x87 的 80 位栈所带来的不可控精度偏移。
• 80 位格式是一种设计取舍,旨在为高精度整数算术提供 64 位的有效数字(significand),在有效适配 10 字节块的同时保持尾数按 2 的幂次对齐。
• 虽然有时被称为 64 位处理器,但 8087 严格来说是一个依赖主 CPU 执行内存寻址等任务的协处理器,而像 IBM 7030 Stretch 和 Cray-1 这样的早期系统则奠定了 64 位计算的基础。
• 历史上有些遗留软件(例如旧版 .NET Framework)依赖 x87 进行数学运算,这说明尽管现代 SIMD 单元在性能上占优,业界长期以来仍不愿完全放弃对 x87 的支持。
• 早期计算器通常采用二进制编码十进制(BCD)和专用串行架构,以简化人类可读十进制与机器算术之间的转换。
• 8087 的内部实现采用垂直微码,每周期执行一条微指令来管理复杂算法,这比纯软件例程提供了显著的性能优势。
• Intel 为 8087 提供了一个庞大的软件仿真器,以便在缺乏硬件协处理器的系统上维持功能,不过那是用汇编语言完全重写的实现,而非对内部微码状态机的直接移植。
讨论侧重于浮点算术的发展和 x87 协处理器的架构特性。参与者回顾了 8087 在早期 x86 时代带来的显著性能提升,以及它对编译器设计和数值一致性带来的技术挑战。共识认为,尽管 8087 在实现高精度数学运算方面开创性很强,但其基于栈的 80 位架构长期来看过于特殊化,因此业界最终转向了更符合现代编译器预期和 64 位数据标准的 SSE 与 AVX 等基于 SIMD 的指令集。 • The 8087 coprocessor delivered massive performance gains for math-heavy applications on early x86 systems by allowing simultaneous, parallel execution of floating-point operations alongside integer instructions.
• Early x86 microarchitectures required manual, instruction-level scheduling to exploit superscalar capabilities, a stark contrast to the modern era where out-of-order execution transparently handles pipeline management.
• The x87 architecture is uniquely challenging for compilers due to its stack-based design, which forces complex register swapping, spillage management, and inconsistent handling of 80-bit extended-precision values.
• Rather than targeting x87, modern compilers and processors favor SIMD units (SSE/AVX) because they offer standard single and double-precision types, avoiding the uncontrollable precision shifts inherent in the x87's 80-bit stack.
• The 80-bit format was a design choice intended to provide a 64-bit significand for high-precision integer arithmetic, fitting efficiently into 10-byte blocks while maintaining power-of-two alignment for the mantissa.
• While sometimes labeled a 64-bit processor, the 8087 was strictly a coprocessor dependent on the host CPU for tasks like memory addressing, whereas earlier systems like the IBM 7030 Stretch and Cray-1 established 64-bit computing foundations.
• Legacy software, such as older versions of the .NET Framework, historically relied on x87 for math, highlighting a long-standing reluctance to transition fully to SSE/AVX despite the clear performance benefits of modern SIMD units.
• Early calculators often utilized Binary Coded Decimal (BCD) and specialized serial architectures to simplify the conversion between human-readable decimal and machine arithmetic.
• The 8087's internal implementation utilized vertical microcode, executing one microinstruction per cycle to manage complex algorithmic tasks, which provided significant performance advantages over pure software routines.
• Intel provided a substantial software emulator for the 8087 to maintain functionality for systems lacking the hardware coprocessor, though this was a complete assembly-language rewrite rather than a direct port of the internal microcode state machine.
The discussion centers on the evolution of floating-point arithmetic and the architectural quirks of the x87 coprocessor. Contributors reflect on the dramatic performance improvements the 8087 provided in the early x86 era and the subsequent technical challenges it imposed on compiler design and numerical consistency. The consensus highlights that while the 8087 was a groundbreaking device that enabled high-precision math, its unique stack-based, 80-bit architecture ultimately proved too idiosyncratic for long-term use. Consequently, the industry shifted toward SIMD-based instruction sets like SSE and AVX, which better align with modern compiler expectations and 64-bit data standards.