Ken Shirriff a reconstitué le calcul de la tangente dans le coprocesseur flottant Intel 8087. Intel a lancé cette puce en 1980 pour l’IBM PC et d’autres systèmes. Elle calculait une tangente en environ 90 microsecondes, contre près de 13 000 microsecondes pour l’émulation sur un 8086.

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 a retiré le capot de la puce avec un ciseau, puis a examiné le die au microscope. La ROM de microcode située au centre contient 1 648 micro-instructions de 16 bits. La partie inférieure du die regroupe le chemin de données flottantes, la ROM des exposants, la ROM des constantes, le décaleur, l’additionneur, les registres de pile, les registres temporaires et un registre à décalage de 16 bits pour les décisions CORDIC.

Jack Volder a conçu CORDIC en 1956 pour l’ordinateur de navigation numérique du Convair B-58 Hustler. La méthode représente un angle par un vecteur et applique des rotations dont les tangentes sont des puissances de deux. Les rotations se réduisent donc à des décalages, des additions et des soustractions, avec les angles stockés dans une table. La machine CORDIC-II du B-58 était un ordinateur série de 30 bits cadencé à 198,4 kHz. Elle pesait 134 livres, utilisait 2 498 transistors et 4 265 diodes, et conservait environ 39 kilooctets sur une mémoire à tambour. Une opération CORDIC durait 5 millisecondes.

Le 8087 emploie une variante qui sélectionne ou ignore chaque angle de la table. Il réduit d’abord l’angle d’entrée avec jusqu’à 16 étapes CORDIC. Cette phase fournit environ 16 bits de précision. Pour le petit angle résiduel, la puce applique l’approximation rationnelle 3x/(3-x2). Son erreur évolue comme x4. Quand le résidu reste inférieur à 2-16, l’erreur demeure sous 2-64. Le processeur conserve le numérateur et le dénominateur comme deux coordonnées du vecteur. Il évite ainsi une division finale. FPTAN renvoie X comme dénominateur et Y comme numérateur, un résultat nommé Partial Tangent par Intel.

Le microcode sépare le traitement en pseudo-division CORDIC, approximation rationnelle et pseudo-multiplication CORDIC. Pendant la pseudo-division, le résidu est comparé à chaque angle stocké. Le résultat, 1 ou 0, est placé dans le registre à décalage. Pour l’entrée de 0,95 radian utilisée dans l’étude, la séquence obtenue est [1,0,0,1,0,1,0,1,0,0,1,0,0,1,1,1]. Les rotations sont ensuite exécutées dans l’ordre inverse. La plus petite vient en premier pour limiter l’erreur d’arrondi. Le vecteur final ne reste pas sur le cercle unité, mais le rapport Y/X fournit toujours la tangente.

Le microcode FPTAN commence à l’adresse #1039. Il vérifie d’abord les arguments invalides et le débordement de pile. Pour un exposant inférieur ou égal à -64, il renvoie l’argument inchangé et fournit 1 comme dénominateur. Pour un exposant inférieur ou égal à -17, il saute la phase CORDIC et rejoint directement l’approximation rationnelle. Les exposants compris entre -1 et -16 suivent le chemin CORDIC. La documentation fixe le domaine d’entrée à 0<θ<π/4. Le code traite explicitement zéro et semble fonctionner au-delà de cette limite, avec une perte de précision à l’approche de π/2. La valeur 0,95 de la démonstration est hors du domaine documenté.

L’approximation doit calculer le carré de l’angle résiduel. Le 8087 utilise pour cela une multiplication Booth radix 4, qui traite deux bits à chaque étape. Le matériel effectue 32 additions dans une boucle pilotée par le microcode. La constante 3 provient de transistors dédiés. Les autres opérations utilisent des décalages et des additions. La division coûteuse n’a pas lieu.

En interne, le 8087 stocke les nombres dans le format Temporary Real de 80 bits. Celui-ci comprend un bit de signe, un exposant de 15 bits et une significande de 64 bits. Le biais de l’exposant vaut 16 383. L’exposant 1 est donc stocké comme 0x4000 et l’exposant -16 comme 0x3fef. Les huit registres de pile utilisent les états zero, valid, special et empty. tmpA et tmpB sont des registres de 80 bits. tmpC ne possède ni signe, ni exposant, ni tag. Sa significande fait 68 bits et s’accompagne de bits d’overflow, guard, round et sticky.

Le microcode effectue des calculs proches du point fixe entier. Les exposants restent implicites. Les décalages maintiennent les bits utiles dans la largeur disponible pendant la pseudo-division et la pseudo-multiplication. Certaines parties du chemin de données utilisent un décaleur de 68 bits et un additionneur de 69 bits. Une addition ou un décalage demande généralement deux micro-instructions. Le registre B utilisé par l’additionneur ne correspond pas au registre tmpB.

Pour l’entrée 0,95, la pseudo-division CORDIC consomme 33 % du temps. L’approximation rationnelle en prend 15 %, principalement pour le carré. La pseudo-multiplication représente 47 %. Les 5 % restants correspondent aux opérations annexes. FPTAN demande typiquement 450 cycles d’horloge, avec une durée comprise entre 30 et 540 cycles selon l’entrée.

Avec le Pentium, Intel est passé aux approximations polynomiales, car le multiplicateur de cette génération rendait cette méthode efficace. Les bibliothèques Intel modernes, comme MKL et SVML, utilisent des polynômes et des instructions SIMD. Les opérations x87 et les flottants de 80 bits sont devenus marginaux dans les logiciels 64 bits.

Le travail de Shirriff a bénéficié de l’aide de l’Opcode Collective, notamment Smartest Blob et Gloriouscow. Le groupe a converti les images de ROM en données de microcode et utilisé un algorithme d’apprentissage automatique pour classer les cellules de ROM. Les données de microcode du 8087 sont disponibles dans le dépôt granite sur GitHub.