The Intel 8087 chip: floating-point addition and subtraction
Analysis of the Intel 8087: Floating-Point Addition & Subtraction
In 1980, Intel released the 8087, a specialized coprocessor designed to drastically accelerate floating-point calculations for the IBM PC and similar architectures. While the chip was capable of complex transcendental functions—such as , , and —this analysis focuses specifically on the fundamental operations of addition and subtraction.
The performance leap was staggering: the 8087 could perform addition nearly 100 times faster than the 8086 CPU, with even greater gains for more complex math.
Research Methodology: To uncover the inner workings of the chip, Ken Shirriff physically decapped an 8087 using a chisel and analyzed the silicon under a high-resolution microscope to reverse-engineer the microcode and circuitry.
🛠️ Hardware Architecture
The 8087's die is divided into several critical zones:
- Microcode ROM: A large central rectangle containing
1648micro-instructions that orchestrate the chip's logic. - The Datapath: Located in the bottom half (highlighted in red in the original imagery), this is where 80-bit floating-point math actually happens.

Key Functional Blocks
- Integer Adder: The heart of the datapath. It sums a value from the B register with a value from the stack or temporary registers.
- The Shifter: A massive circuit allowing bits to be moved left or right by any arbitrary amount rapidly. This is essential for aligning binary points.
- Leading Zero Circuitry: This logic counts consecutive zeros at the start of a value, allowing the shifter to "strip" them away efficiently.
- Exponent Converter: Manages the exponents and flags conditions like underflow or overflow.
🧮 Floating-Point Fundamentals
Standard integers are insufficient for many tasks because they lack fractional components and have a narrow range (a 32-bit signed integer only spans ). Floating-point representation solves this by using the following formula:
The Components
- Significand: A binary value formatted as (a leading implicit 1 followed by the fractional bits).
- Exponent: This allows the binary point to "float," enabling a massive range. For example, a 32-bit float can represent values from to .
Addition and Subtraction Logic
Unlike integer addition floating-point addition, you cannot simply sum the bits. You must:
- Align the binary points (equalize exponents).
- Perform the integer operation on the significands.
- Normalize the result so it begins with a leading 1.
Example: Addition ()

Example: Subtraction

Normalization Checklist:
- Shift significand right if an overflow occurred (increment exponent).
- Shift significand left if the result is too small (decrement exponent).
- If the result is negative, flip the sign bit and make the significand positive.
- Handle special cases where the result is exactly or .
🔍 Technical Implementation Details
Internally, the 8087 utilizes a high-precision 80-bit format known as the "temporary real."
The Temporary Real Format
| Component | Size | Description |
|---|---|---|
| Sign Bit | 1 bit | Determines positive or negative |
| Exponent | 15 bits | Allows values up to |
| Significand | 64 bits | The precision bits of the number |
The exponent is stored as an unsigned value (biased) to ensure it remains positive in the hardware.
Exponent Examples:
- An exponent of is represented as
0x4000. - An exponent of is represented as
0x3fef.

Special Case Handling
The 8087 must handle "edge cases" such as infinities. The microcode includes specific branches to manage these according to the Intel User's Manual.

Microcode Logic
The process of adding or subtracting is managed by a complex set of micro-instructions. The following flowcharts illustrate the decision-making process for basic arithmetic:

The leading zero detection circuitry is a prime example of the 8087's efficiency, using a specialized hardware path to detect to leading zero bits instantly:

// Conceptual pseudo-code for the normalization step
if (result_overflow) {
significand >>= 1;
exponent++;
} else if (leading_zeros > 0) {
significand <<= leading_zeros;
exponent -= leading_zeros;
}