Nous extrayons des constantes du cristal du coprocesseur mathématique 8087

En 1980, Intel a introduit la puce 8087 pour accélérer le traitement des nombres à virgule flottante sur les processeurs 8086, et elle a été utilisée dans le PC IBM d'origine. Comme les premiers microprocesseurs ne fonctionnaient qu'avec des entiers, l'arithmétique avec des nombres à virgule flottante était lente, et avec des fonctions transcendantales comme des arctangentes ou des logarithmes, les choses étaient encore pires. L'ajout de la puce du coprocesseur 8087 au système a permis d'accélérer les opérations avec des nombres à virgule flottante jusqu'à cent fois.

J'ai ouvert la puce 8087 et en ai pris quelques photos au microscope. La photo ci-dessous montre un minuscule cristal de puce de silicium. Sur ses côtés, de minuscules conducteurs le relient à 40 pattes externes. Le balisage des principaux blocs fonctionnels dans l'image a été réalisé par moi grâce à la rétro-ingénierie. Si vous étudiez attentivement la puce, vous pouvez extraire diverses constantes de sa mémoire ROM - des nombres tels que π utilisé par la puce dans les calculs. Puce à puce Intel 8087 pour un fonctionnement en virgule flottante avec des blocs de fonction principaux marqués. La ROM avec des constantes est marquée en vert. Cliquable.




Dans la moitié supérieure de la puce se trouvent des circuits de commande. Jusqu'à 1000 étapes peuvent être nécessaires pour exécuter une instruction à virgule flottante; 8087 a utilisé un microcode pour décrire ces étapes. Sur la photo du cristal, vous pouvez voir le "mécanisme" qui a lancé le programme à partir du microcode; en fait, c'est un simple processeur. À côté se trouve une grande ROM, où le microcode est stocké.

Au bas de la puce se trouvent des circuits qui traitent les nombres à virgule flottante. Un nombre à virgule flottante se compose d'une partie fractionnaire (également appelée partie significative d'un nombre ou d'une mantisse), d'un exposant et d'un bit de signe. En notation décimale, le nombre 6,02 × 10 236.02 sera la mantisse et 23 sera l'exposant. Des circuits à puce séparés traitent simultanément la mantisse et l'exposant. Le schéma de traitement de la mantisse prend en charge les valeurs de 67 bits - une mantisse de 64 bits et trois bits supplémentaires pour plus de précision. De gauche à droite, les schémas d'opération de mantisse sont constitués de ROM avec constantes, d'un registre à décalage, d'un additionneur / soustracteur et d'une pile de registres. Le sujet de cet article est ROM avec des constantes; sur la photo, il est surligné en vert.

Le 8087 a fonctionné comme coprocesseur du processeur 8086. Lorsque le processeur 8086 a rencontré une instruction spéciale relative aux nombres à virgule flottante, il l'a ignorée et a donné au 8087 la possibilité de l'exécuter en parallèle. L'interaction des 8086 et 8087 a été arrangée d'une manière plutôt astucieuse. Pour simplifier, 8087 examine le flux d'instructions 8086 et exécute toutes les instructions liées à 8087. La difficulté est que 8086 a un tampon d'instructions de prélecture, donc l'instruction que 8086 reçoit actuellement ne correspond pas à l'instruction il joue. Par conséquent, 8087 a dupliqué le tampon de l'échantillon direct d'instructions 8086 (ou un plus petit tampon de l'échantillon direct d'instructions 8088) afin de savoir avec quoi le 8086 est occupé ( plus de détails sont décrits ici) Une autre difficulté est associée aux modes d'adressage 8086 complexes qui utilisent des registres à l'intérieur de 8086. 8087 ne peut pas exécuter ces modes d'adressage car il n'a pas accès aux registres 8086. Au lieu de cela, lorsque 8086 voit l'instruction pour 8087, il demande des données à partir d'un emplacement spécifié en mémoire et ignore le résultat. Pendant ce temps, 8087 prend l'adresse du bus, au cas où il en aurait besoin. Il peut vous sembler qu'un piège se formera à cet endroit si 8087 n'est pas installé - mais cela ne se produira pas. Sur un système sans 8087, l'éditeur de liens réécrit les instructions 8087, en les remplaçant par des appels de sous-programme à partir de la bibliothèque d'émulation.

Je ne dirai pas en détail le fonctionnement interne de 8087, mais en général, les opérations en virgule flottante sont implémentées par des ajouts, des soustractions et des décalages d'entiers. Pour ajouter ou soustraire deux nombres à virgule flottante, 8087 décale les nombres jusqu'à ce que les virgules binaires soient alignées (comme les virgules décimales, uniquement dans le système binaire), puis ajoute ou soustrait la mantisse. La multiplication, la division et la prise de la racine carrée sont effectuées par des décalages et additions / soustractions successifs. Les fonctions transcendantales (tangente, arctangente, logarithme, degré) utilisent des algorithmes CORDIC , qui utilisent des décalages et des ajouts de constantes spéciales pour augmenter l'efficacité des calculs.

Implémentation de la ROM


Cet article décrit la ROM où les constantes sont stockées. Ne le confondez pas avec une ROM à quatre niveaux plus grande où le microcode est stocké - ce dernier est implémenté en utilisant une technologie inhabituelle qui stocke deux bits par transistor. Cela se fait en utilisant des transistors de trois tailles différentes ou en l'absence d'un transistor à chaque position. Ces quatre options indiquent deux bits. Cette technologie sophistiquée était nécessaire pour installer une grande ROM sur une puce 8087.

La ROM pour les constantes utilise des technologies standard pour stocker les constantes (telles que π, ln (2) et √2) requises par 8087 pour les calculs. La photo ci-dessous montre une partie de la ROM avec des constantes. Pour voir le cristal lui-même, une couche métallique en a été retirée. Les zones rosâtres sont en silicium avec des impuretés lui conférant des propriétés différentes, et les lignes rougeâtres et verdâtres sont en polysilicium , un type spécial de câblage en silicium se trouvant sur le dessus. Faites attention à la structure de la ROM, semblable au réseau correct. La ROM se compose de deux colonnes de transistors stockant des bits. Pour expliquer le schéma de son fonctionnement, je vais commencer par le schéma de fonctionnement du transistor.


Partie de la ROM avec constantes, avec une couche de métal enlevée. Trois colonnes de transistors plus grands sont utilisées pour sélectionner les lignes.

Les circuits intégrés à haute densité (CI) dans les années 1970 étaient généralement fabriqués à partir de transistors N-MOS. (Les ordinateurs modernes sont faits de CMOS, consistant en une polarité inverse N-MOS et P-MOS). Le diagramme ci-dessous montre la structure d'un transistor N-MOS. Le circuit intégré est assemblé à partir d'un substrat de silicium sur lequel des transistors sont créés. Des impuretés sont ajoutées aux sites de silicium, créant des régions "diffuses" avec les propriétés électriques souhaitées. Un transistor peut être considéré comme un interrupteur qui permet au courant de circuler entre deux sections de diffusion, appelées source et drain. Le transistor est contrôlé par une grille constituée d'un type spécial de silicium - polysilicium. L'application d'une tension à la grille permet au courant de circuler entre la source et le drain; sinon, aucun courant ne circule. Le 8087 est assez complexe, avec environ 40 000 transistors dessus.

Différentes sources donnent un nombre différent de transistors pour 8087: Intel en dit environ 40 000, Wikipédia en dit environ 45 000. Le tout est peut-être dans différentes méthodes de calcul. Étant donné que le nombre de transistors dans une ROM, PLA ou autre structure similaire dépend des données stockées, les sources indiquent souvent le nombre de transistors "potentiels" au lieu de réels. Vous pouvez également considérer ou non les transistors pull-up, ou considérer les pilotes à courant élevé comme un transistor ou plusieurs parallèles.


Structure MOS implémentée dans IP

En zoomant, des transistors ROM individuels peuvent être considérés. Les zones rosées sont en silicium avec des impuretés qui forment des sources et des drains. Les lignes de bus verticales en silicium polycristallin forment des grilles de transistor. Les zones marquées de silicium sont connectées à la masse et abaissent un côté de chaque transistor. Les cercles sont VIA , un vias intercouche entre les pneus en silicone et en métal ci-dessus. Pour les photos, les pneus métalliques sont retirés; l'emplacement de l'un d'eux est indiqué par la ligne orange.


Partie de ROM avec constantes. Chaque bus d'échantillonnage sélectionne une constante spécifique. Les transistors sont représentés en jaune. X marque le transistor manquant correspondant au bit 0. La ligne orange indique l'emplacement du conducteur métallique.

Une caractéristique importante de la ROM est l'absence de certains transistors - il n'y en a pas de premier dans la rangée supérieure et deux marqués d'un X dans la rangée inférieure. Les bits sont programmés en ROM en changeant le circuit pour ajouter des impuretés au silicium, qui créent des transistors ou laissent des zones isolantes. Chaque transistor disponible ou manquant représente un bit. Lorsque le bus d'échantillonnage est activé, tous les transistors de cette colonne s'ouvrent, tirant vers le bas les bus de sortie correspondants. Mais s'il n'y a pas de transistor dans la position sélectionnée, la sortie correspondante restera élevée. Ainsi, la valeur est lue à partir de la ROM en activant le bus d'échantillonnage, qui sort cette valeur de la ROM vers les bus de sortie.

Contenu de la ROM


La ROM avec constantes comprend 143 lignes et 21 colonnes. Il contient 134 rangées de 21 bits, à l'exception d'un morceau de transistors 6 × 6 en haut à gauche. Par conséquent, la taille physique de la ROM avec des constantes est de 2946 bits.



Sur la base du schéma ROM, la section manquante signifie que les 12 premières constantes sont 64 bits, et non 67 bits. Ce sont des constantes non liées à CORDIC, et elles ne nécessitent apparemment pas de précision supplémentaire.

Sous le microscope, le motif de bits ROM est visible, il peut donc être retiré de là. Cependant, il n'est pas du tout évident de savoir comment interpréter ces bits plus tard. La première question est de savoir si la présence d'un transistor indique 0 ou 1 (plus tard, il s'est avéré que la présence d'un transistor est 1). Le deuxième problème est de savoir comment traduire la grille 134 × 21 bits en valeurs.

Le codage des bits peut être défini de deux manières. La première consiste à suivre le circuit en lisant les données de la ROM et à voir comment elles sont utilisées. La seconde consiste à rechercher des modèles dans les données brutes et à essayer de les comprendre. Étant donné que 8087 est très complexe, je voulais éviter l'ingénierie inverse complète lors de l'étude des constantes, j'ai donc utilisé la deuxième approche.

Le chemin de données de la puce se compose de 67 lignes horizontales, il était donc clair que les 134 lignes de la ROM correspondent à deux ensembles de constantes de 67 bits. J'ai extrait un ensemble de constantes de la série impaire et l'autre de la série paire, mais les valeurs obtenues n'avaient pas de sens. En réfléchissant un peu plus, j'ai réalisé que les rangées ne s'alternaient pas, mais marchaient en répétant l'ordre ABBA.

Les lignes sont passées dans l'ordre ABBAABBAABBA ..., où les lignes A contenaient des bits pour un ensemble de constantes et les lignes B contenaient des bits pour un autre. Un tel circuit a été utilisé au lieu de simplement alterner ABAW, peut-être parce qu'un contact peut contrôler deux transistors adjacents. Autrement dit, un conducteur peut sélectionner chacun des groupes AA et BB.

Lorsque j'ai pris en compte l'ordre ABBA, j'ai obtenu un tas de constantes familières, y compris π et 1. Le diagramme ci-dessous montre les bits de ces constantes. Sur la photo, le bit 1 est une bande verte, le bit 0 est rouge. Dans le système binaire, π est 11,001001 ..., et c'est cette valeur qui est visible dans la rangée supérieure de bits marqués. La valeur inférieure est constante 1. La


ligne de bits supérieure est le nombre π, la valeur inférieure est 1. Ce diagramme est tourné de 90 ° par rapport aux autres.

La prochaine difficulté d'interprétation est que seule la mantisse est stockée dans la ROM, mais pas l'exposant (jusqu'à présent, je n'ai pas trouvé de ROM séparée avec les exposants). Et j'ai expérimenté avec divers exposants jusqu'à obtenir des valeurs significatives. Certains étaient immédiatement clairs: par exemple, la constante 1,204120 donne log 10 (2) en utilisant l'exposant 2 -2 . D'autres étaient plus difficiles à comprendre, par exemple 1 734 723. Au final, j'ai réalisé que 1,734723 × 2 59 = 10 18 . Pourquoi y a-t-il une telle constante en 8087? Peut-être parce que le 8087 prend en charge le code décimal binaire compressé à 18 caractères.

Certains exposants étaient très difficiles à trouver, et j'ai utilisé la méthode de la force brute pour voir si le résultat produirait un logarithme ou un degré quelconque. Le plus difficile a été de déterminer la constante de ln (2) / 3. L'importance de ce nombre n'est pas claire pour moi.

Voici la liste complète des constantes de la ROM. La colonne «sens» est ma description du sens.

ConstantesValeur décimaleSens
1,204120 × 2 -20,3010300journal 10 (2)
1,386294 × 2 -10,6931472ln (2)
1,442695 × 2 01.426950log 2 (e)
1,570796 × 2 13.1415927π
1,000000 × 2 01,0000001
1,660964 × 2 13.219281journal 2 (10)
1.734723 × 2 591,00e + 1810 18
1.734723 × 2 591,00e + 1810 18
1.848392×2-30.2310491ln(2)/3
1.082021×224.2808513*log2(e)
1.442695×201.426950log2 (e)
1.414214×201.4142136√2
1.570796×2-10.7853982atan(20)
1.854590×2-20.4636476atan(2-1)
2.000000×2-150.0000610atan(2-14)
2.000000×2-160.0000305atan(2-15)
1.959829×2-30.2449787atan(2-2)
1.989680×2-40.1243550atan(2-3)
2.000000×2-130.0002441atan(2-12)
2.000000×2-140.0001221atan(2-13)
1.997402×2-50.0624188atan(2-4)
1.999349×2-60.0312398atan(2-5)
1.999999×2-110.0009766atan(2-10)
2.000000×2-120.0004883atan(2-11)
1.999837×2-70.0156237atan(2-6)
1.999959×2-80.0078123atan(2-7)
1.999990×2-90.0039062atan(2-8)
1.999997×2-100.0019531atan(2-9)
1.441288×2-90.0028150log2(1+2-9)
1.439885×2-80.0056245log2(1+2-8)
1.437089×2-70.0112273log2(1+2-7)
1.431540×2-60.0223678log2(1+2-6)
1.442343×2-110.0007043log2(1+2-11)
1.441991×2-100.0014082log2(1+2-10)
1.420612×2-50.0443941log2(1+2-5)
1.399405×2-40.0874628log2(1+2-4)
1.442607×2-130.0001761log2(1+2-13)
1.442519×2-120.0003522log2(1+2-12)
1.359400×2-30.1699250log2(1+2-3)
1.287712×2-20.3219281log2(1+2-2)
1.442673×2-150.0000440log2(1+2-15)
1.442651×2-140.0000881log2(1+2-14)


Je ne sais pas pourquoi 10 18 est répété - peut-être que la différence est exponentielle.

Physiquement, les constantes sont réparties en trois groupes. Le premier groupe est constitué des valeurs que l'utilisateur peut charger (1, π, log 2 10, log 2 e, log 10 2 et ln), ainsi que des valeurs à usage interne (10 18 , ln (2) / 3, 3 * log 2 (e), log 2 (e) et √2). Le deuxième groupe se compose de 16 constantes arctangentes et le troisième se compose de 14 constantes log 2 .

En 8087, il y a sept instructions pour charger directement les constantes. Les instructions FDLZ, FLD1, FLDPI, FLD2T, FLD2E, FLDLG2 et FLDLN2 chargent les constantes 0, 1, π, log 2 10, log 2 sur la pilee, log 10 2 et ln 2, respectivement. Toutes ces constantes sauf 0 sont stockées dans la ROM.

Les deux derniers groupes de constantes sont utilisés pour calculer les fonctions transcendantales à l'aide des algorithmes CORDIC.

Algorithmes CORDIC


Par les constantes de la ROM, vous pouvez trouver quelques détails sur le fonctionnement des algorithmes 8087. La ROM contient 16 valeurs pour l'arctangente, les arctangentes de 2 -n . Il y a aussi 14 logarithmes stockés sur la base 2 de (1 + 2 -n ). De telles valeurs peuvent sembler inhabituelles, mais elles sont utilisées dans l'algorithme efficace CORDIC, inventé en 1958.

L'idée de CORDIC est que la tangente et l'arc tangente peuvent être calculées en divisant l'angle en plus petits avec la rotation du vecteur par ces angles. L'astuce est que si vous choisissez les bons angles plus petits, chaque rotation peut être calculée à l'aide des décalages et des ajouts effectifs au lieu des fonctions trigonométriques. Supposons que nous ayons besoin de trouver tan (z). On peut diviser z en la somme des petits angles: z ≈ {atan (2 -1 ) ou 0} + {atan (2 -2) ou 0} + {atan (2 -3 ) ou 0} + ... + {atan (2 -16 ou 0}. Vous pouvez faire pivoter le vecteur par, disons, atan (2 -2 ) en multipliant par 2 -2 et en ajoutant. l'essentiel est que la multiplication par 2 -2 est réalisée par une opération de bits rapide shift.Taking tout cela en compte, on peut calculer tan (z) en comparant z avec des constantes atan, puis après être passé par 16 cycles d'additions et de décalages, qui se fait rapidement sur le fer. pour atan sont pré-calculés et stockés dans la ROM. L'arc tangente est calculée de la même manière, mais vice versa - dans le processus de rotation, les angles (à partir de la ROM avec des constantes) sont additionnés et donnent le dernier.

Lors du calcul du logarithme et de l'exposant, les algorithmes CORDIC et leurs constantes logarithmiques correspondantes sont également utilisés. L'essentiel ici est que la multiplication par (1 + 2 -n ) peut être effectuée rapidement à l'aide de décalages et d'additions. Le logarithme et l'exposant peuvent être calculés en multipliant un côté de l'équation par une séquence de valeurs et en ajoutant les constantes logarithmiques correspondantes à l'autre. Selon les algorithmes de calcul du logarithme et exposant de la documentation pour 8087, je ne l'ai pas trouvé. Je pense qu'ils sont similaires à ceux décrits dans l' article suivant , seul 8087 utilise la base 2 au lieu de e. Je ne comprends pas pourquoi 8087 n'a pas la constante log 2 (1 + 2 -1 ) nécessaire pour cet algorithme.

La prise en charge des fonctions transcendantales dans 8087 n'est pas aussi étendue que vous pourriez vous y attendre. Il prend uniquement en charge la tangente et l'arc tangente, sans sinus ni cosinus. Pour calculer ce dernier, il est nécessaire d'appliquer des identités trigonométriques. Les logarithmes et exposants ne prennent en charge que la base 2 - pour les bases 10 ou e, l'utilisateur devra appliquer un facteur d'échelle. À un moment donné, 8087 a étendu les limites de la capacité des puces, de sorte que le nombre d'instructions a été minimisé.

Conclusion


Le 8087 est une puce complexe, et à première vue, il ressemble à un labyrinthe désespérément emmêlé. Cependant, pour la plupart, il peut être compris après une étude approfondie. Dans sa ROM, 42 constantes sont stockées et leurs valeurs peuvent être extraites à l'aide d'un microscope. Certaines constantes (par exemple π) étaient attendues, tandis que d'autres (par exemple ln (2) / 3) soulèvent davantage de questions. De nombreuses constantes sont utilisées pour calculer les tangentes, les arctangentes, les logarithmes et les degrés à l'aide des algorithmes CORDIC. Photo d'un cristal 8087 sans couche métallique. Cliquable.




Bien qu'Intel 8087 pour le fonctionnement en virgule flottante ait été introduit il y a 40 ans, son impact se fait encore sentir. Il a engendré la norme IEEE 754 pour les nombres à virgule flottante, utilisée dans la plupart des calculs arithmétiques, et les instructions 8087 restent une partie des processeurs x86 utilisés sur la plupart des ordinateurs.

All Articles