Ken Shirriff reverse-engineered the tangent implementation in Intel’s 8087 floating-point coprocessor. Intel introduced the chip in 1980 for the IBM PC and other systems. It reduced tangent computation from about 13,000 microseconds on an 8086 to roughly 90 microseconds on the 8087, a speedup close to two orders of magnitude.

FPTAN microcode
FPTAN:
#1039 st(0) -> tmpA store argument in tmpA
#1040 stackPtr-- check if room on stack to push result
#1041 stack overflow?
#1042 jmp #1022 if tmp empty/special/overflow/div exit if bad argument or stack overflow
#1043 jmp #1045 if tmpA:tag ZERO is argument 0?
#1044 except:precision precision exception except for 0
#1045 expconst 0x3ff0 Test if exponent >= -16
#1046 adder: tmpA:exp + 0 cin=1 argument exponent + 1
#1047 expConst -> Breg
#1048 adder: sumreg:frac - Breg cin=1 subtract -15
#1049 jmp #1061 if adder pos CORDIC if exponent >= -16
#1050 expconst 0x3fff non-CORDIC path:
#1051 tmpA:exp -> Breg check original exponent
#1052 expConst -> tmpB:frac against exponent 0
#1053 adder: tmpB:frac - Breg cin=1 subtract
#1054 sumreg:frac -> expConv 3fff - exp (i.e. -exp unbiased)

Shirriff removed the lid from an 8087 with a chisel and photographed the die through a microscope. Its central microcode ROM contains 1,648 16-bit micro-instructions. The lower part of the die contains the floating-point datapath, including the exponent ROM, constant ROM, shifter, adder, stack registers, temporary registers, and a 16-bit shift register for CORDIC decisions.

CORDIC was developed by Jack Volder in 1956 for the Convair B-58 Hustler’s digital navigation computer. The method represents an angle through a vector and applies rotations whose tangents are powers of two. Each rotation therefore needs shifts, additions, and subtractions, while the corresponding angles come from a stored table. The CORDIC-II machine used for the B-58 was a 30-bit serial computer running at 198.4 kHz. It weighed 134 pounds, used 2,498 transistors and 4,265 diodes, and stored about 39 kilobytes on a drum. A CORDIC operation took 5 milliseconds.

The 8087 uses a variation that selects or skips each stored angle. It first reduces the input angle through up to 16 CORDIC steps. Sixteen steps provide about 16 bits of accuracy, so the chip handles the remaining small angle with the rational approximation 3x/(3-x2). Its error scales with x4. With a residual below 2-16, the error stays below 2-64. The numerator and denominator are kept as separate vector coordinates, so FPTAN avoids a final division. The instruction returns X as the denominator and Y as the numerator, which Intel called the Partial Tangent.

The microcode divides the work into CORDIC pseudo-division, rational approximation, and CORDIC pseudo-multiplication. Pseudo-division compares the residual angle with each stored angle and records a 1 or 0 in the shift register. For the example input 0.95 radians, the recorded sequence is [1,0,0,1,0,1,0,1,0,0,1,0,0,1,1,1]. The rotations are applied later in reverse order, with the smallest rotation first, to limit rounding error. The resulting vector does not stay on the unit circle because the rotation matrices are scaled, but Y/X still gives the tangent.

The FPTAN microcode begins at address #1039. It checks for an invalid argument and stack overflow before processing the exponent. Values with an exponent of -64 or lower are returned unchanged, with 1 supplied as the denominator. Values with an exponent of -17 or lower skip the CORDIC phase and go directly to the rational approximation. Inputs with exponents from -1 through -16 use the CORDIC path. The documented input range is 0<θ<π/4, although the implementation explicitly handles zero and appears to work for larger values, with accuracy declining near π/2. The demonstration value 0.95 lies outside Intel’s documented range.

The approximation needs a square of the residual angle. The 8087 performs that operation with radix-4 Booth multiplication, processing two bits per step. Hardware carries out 32 additions within one microcode-controlled multiplication loop. The constant 3 comes from dedicated transistor logic, while shifts and additions produce the remaining operations. The expensive division never occurs.

Internally, the 8087 stores numbers in an 80-bit temporary-real format with one sign bit, a 15-bit exponent, and a 64-bit significand. The exponent bias is 16383, so an exponent of 1 is stored as 0x4000 and -16 as 0x3fef. The eight stack registers use tags for zero, valid, special, and empty states. Temporary registers tmpA and tmpB hold 80-bit values. tmpC has no sign, exponent, or tag, and uses a 68-bit significand with overflow, guard, round, and sticky bits.

The microcode performs integer-like fixed-point calculations with exponents that exist only implicitly. Shifts keep the useful bits packed into the datapath as the values shrink during pseudo-division and grow during pseudo-multiplication. The shifter is 68 bits wide and the adder 69 bits wide in parts of the datapath. A shift or addition generally takes two micro-instructions, and the B register used by the adder is separate from tmpB.

For an input of 0.95, the CORDIC pseudo-division consumes 33% of the execution time. The rational approximation takes 15%, mostly for squaring, and pseudo-multiplication takes 47%. The remaining 5% is overhead. FPTAN typically needs 450 clock cycles, with measured execution ranging from 30 to 540 cycles depending on the input.

The 8087’s FPTAN instruction usually takes 450 clock cycles, which makes it one of the slower operations in the chip. Intel later moved the Pentium toward polynomial approximations because its multiplier made that approach practical. Modern Intel libraries such as MKL and SVML use polynomial methods with SIMD instructions, while x87 operations and 80-bit floating-point values are largely obsolete in 64-bit software.

Shirriff reconstructed the microcode with help from the Opcode Collective, especially Smartest Blob and Gloriouscow. The group converted ROM images into microcode data and used machine learning to classify ROM cells during extraction. The resulting 8087 microcode data is available in the granite repository on GitHub.