HP Nanoprocessor Part II: Reverse engineering de circuits basés sur des masques photo

Première partie



En 1974, Hewlett-Packard a développé un microprocesseur pour contrôler diverses fonctions de ses produits, des lecteurs de disquettes aux voltmètres. Ce processeur simple n’était pas à la hauteur des microprocesseurs standard - il ne prenait même pas en charge l’addition ou la soustraction - on l’appelait donc un «nanoprocesseur». Les principales caractéristiques du nanoprocesseur étaient un faible coût et une vitesse de travail élevée: par rapport au Motorola 6800 moderne coûtant 360 $, le nanoprocesseur coûtait 15 $ et les opérations de contrôle étaient beaucoup plus rapides.



Bien qu'il n'ait pas d'opération d'addition, Nanoprocessor pouvait (lentement) ajouter des nombres en incrémentant ou décrémentant à plusieurs reprises (les opérations qu'il supportait). Dans d'autres cas, par exemple, avec un voltmètre de Hewlett-Packard, des puces ALU (74LS181) ont été ajoutées au produit, qui ont été ajoutées rapidement - elles ont été accédées en tant que périphériques d'E / S. Naturellement, étant donné que Turing est terminé, Nanoprocessor pourrait théoriquement tout faire, du calcul des fonctions en virgule flottante au lancement d'un jeu Crysis; ce serait juste très lent.



Le photomasque du processeur peut être téléchargé à partir du lien (122 Mo PSD).







HP Nanoprocessor, 1820-1691. , -2,5 , – . , .



Dans les décennies suivantes, le processeur est resté inconnu jusqu'à récemment, son développeur, Larry Bauer, a partagé les photomasques et la documentation de la puce avec le projet CPU Shack. Là, ils ont scanné les photomasques et ont écrit un article sur Nanoprocessor. Après qu'Antoine Berkovichi ait assemblé les images en une seule, j'ai écrit une critique de Nanoprocessor basée sur celui-ci . C'est la deuxième partie de l'article où je discute de certains détails du circuit nanoprocesseur tout en faisant de la rétro-ingénierie basée sur des photomasques. Les blocs fonctionnels du Nanoprocesseur sont intéressants à étudier car il contourne l'implémentation minimale des fonctions nécessaires, tout en restant un microprocesseur utile.



À l'intérieur du nanoprocesseur



Comme la plupart des processeurs de cette époque, le nanoprocesseur est 8 bits. Cependant, il ne prend pas en charge la mémoire à accès aléatoire et le code est exécuté à partir d'une ROM externe de 2 Ko. Il dispose de 16 registres 8 bits - plus que la plupart des processeurs et suffisamment pour compenser le manque de mémoire pour de nombreuses applications. Le nanoprocesseur avait 48 instructions - nettement moins que les 72 instructions pour le Motorola 6800. Cependant, le nanoprocesseur avait un ensemble pratique d'opérations de définition de bits, d'effacement et de vérification qui manquaient à d'autres processeurs de l'époque. Il disposait également de plusieurs commandes d'E / S prenant en charge à la fois les ports d'E / S et les broches d'E / S à usage général, facilitant ainsi le contrôle d'autres périphériques.



Le nanoprocesseur n'avait pas d'instructions pour prendre en charge la gestion de la mémoire, car il était conçu pour des opérations ne nécessitant pas de stockage de données. Cependant, dans certaines applications, le nanoprocesseur utilisait la RAM comme périphérique d'E / S. Une adresse a été envoyée à l'un des ports d'E / S et un octet de données a été lu sur l'autre. Photomasques combinés à nanoprocesseur (cliquables) À partir de l'image de photomasque ci-dessus, nous pouvons conclure que le nanoprocesseur est simple. Les lignes bleues sont des conducteurs métalliques sur le dessus de la puce, les vertes sont du silicium avec des impuretés. Carrés noirs autour du périmètre - 40 tampons pour la communication avec les contacts externes du CI. Les petites zones noires à l'intérieur sont des transistors. Si vous regardez de près, vous pouvez en compter 4 639.













Si nous prenons en compte le fait que le décodeur d'instructions se compose de paires de petits transistors, ce qui est fait pour la commodité de l'agencement des composants, et que nous comptons ces paires comme une, alors nous obtenons 3829 transistors. Parmi ceux-ci, 1061 sont des pull-ups et 2668 sont actifs. À titre de comparaison, le 6502 avait 4 237 transistors, dont 3 218 étaient actifs. Le 8008 avait 3500 transistors, tandis que le Motorola 6800 en avait 4100.



Le schéma fonctionnel ci-dessous montre la structure interne du nanoprocesseur. Au milieu, il y a 16 registres de maintien. Le comparateur vous permet de comparer deux valeurs pour fournir un branchement conditionnel. L'unité logique de commande s'occupe des opérations d'incrémentation, de décrémentation, de décalage et de bit de l'accumulateur. Il n'a pas les opérations arithmétiques et logiques de l'ALU standard. Le compteur de programme (à droite) extrait une instruction du registre d'instructions (à gauche); les interruptions et les appels de sous-programmes ont leurs propres piles à un élément pour stocker les adresses de retour.





Organigramme de travail à partir des instructions pour Nanoprocessor



Permettez-moi de souligner que, malgré sa simplicité et l'absence d'opérations arithmétiques, le nanoprocesseur n'est pas une sorte de processeur «jouet» qui commute les lignes de contrôle. C'est un processeur rapide et puissant utilisé pour effectuer des opérations complexes. Par exemple, le module d'horloge en temps réel HP 98035 a utilisé Nanoprocessor pour traiter deux douzaines de chaînes de contrôle ASCII différentes, ainsi que pour compter le nombre de jours dans un mois.



Un projet intéressant pour le plaisir peut être la création d'une version FPGA du Nanoprocessor - puisque Nanoprocessor est peut-être la version la plus simple d'un vrai processeur commercial. Les instructions pour cela décrivent toutes les commandes et donnent des exemples de code que vous pouvez exécuter.



Registres



La photo du cristal ci-dessous montre qu'une partie importante du nanoprocesseur est occupée par ses 16 registres. Ils communiquent avec le reste des composants via le bus de données. Les chaînes en haut choisissent un registre particulier. Enregistrez R0, à droite, à côté du comparateur.





Une partie importante du nanoprocesseur est occupée par ses registres 16.



Le bloc de construction d'un registre est constitué de deux inverseurs dans la boucle de rétroaction, stockant un bit comme indiqué ci-dessous. Si le conducteur supérieur est 0, l'onduleur droit émettra 1 vers le conducteur inférieur, puis l'onduleur gauche émettra un 0 vers le conducteur supérieur, terminant le cycle. Le circuit reste stable en «se souvenant» de 0. De la même manière, si le conducteur supérieur est 1, il est inversé à 0 en bas, et à 1 en haut. Le réseau peut stocker 0 ou 1 de cette manière, formant un emplacement mémoire de 1 bit.





Deux onduleurs dans un circuit de stockage de bits stable



Le schéma ci-dessous montre comment ce stockage à deux onduleurs est implémenté sur une puce. L'emplacement physique des composants est indiqué sur la gauche, basé sur un photomasque. La disposition est optimisée pour que la cellule occupe le moins de place possible. Lignes bleues - couche métallique, vertes - silicium. Au milieu, un schéma du circuit correspondant avec des transistors est montré. Chaque onduleur se compose d'une paire de transistors, comme illustré à droite. Les transistors en haut et en bas sont "traversants", ils permettent d'accéder à la cellule de stockage.





Stockage d'un bit dans le nanoprocesseur. Chaque bit est implémenté sur 6 transistors (cellule SRAM 6T).



Un ensemble de registres se compose d'une matrice de telles cellules binaires. Le bus de sélection de registre sélectionne un registre (une colonne) pour la lecture ou l'écriture. Les transistors passe-haut et bas relient ensuite les inverseurs à leurs lignes de bits horizontales respectives. Pour la lecture, la ligne de bit supérieure fournit la valeur stockée dans la cellule; il y a huit lignes de bit pour les huit bits stockés dans le registre. Pour l'écriture, la valeur est transférée à la ligne de bit supérieure et la valeur inversée est transférée à la ligne inférieure. Ces valeurs remplacent les signaux des onduleurs, les amenant à prendre la valeur souhaitée et à stocker ce bit. Ainsi, une grille de lignes de bit horizontales et de lignes de sélection verticales permet à une valeur d'être lue ou écrite dans un registre particulier.



Commandes de décodage



Les circuits de décodage sont engagés à prendre le code binaire de l'instruction (par exemple, 01101010), et à déterminer ce qu'est l'instruction (dans ce cas, "charger l'accumulateur du registre 10"). Par rapport à de nombreux processeurs, les instructions de Nanoprocessor sont assez simples: il en a relativement peu (48), et le code d'instruction est toujours d'un octet. Le schéma ci-dessous montre que la logique de décodage des instructions (rouge) occupe une partie importante de la puce. Le registre d'instructions (vert) est un ensemble de huit verrous qui contiennent l'instruction en cours. Le registre de commande est situé à côté des broches de données auxquelles la commande provient de la ROM. Dans cette section, nous décomposerons la chaîne de décodage représentée en jaune.







Le décodage est effectué par des portes NOR. Chaque porte NOR reconnaît une commande ou un groupe de commandes spécifique. La porte NOR accepte les bits de commande ou leur complément en entrée. Lorsque tous les bits entrants sont à zéro, la porte NOR signale une correspondance. Cela vous permet de rechercher des matchs à la fois dans toute l'équipe dans son ensemble et dans une partie de l'équipe. Par exemple, la commande "charger l'accumulateur à partir du registre R" a un format binaire 0110rrrr, dans lequel les quatre derniers bits indiquent le registre requis. La porte NOR (bit7 + bit6 '+ bit5' + bit4) 'correspondra à cette commande.



Un décodeur d'instructions ainsi structuré est bon en ce qu'il peut être assemblé à partir de circuits compacts et répétitifs. Il est souvent appelé PLM (Programmable Logic Array). L'idée est que les signaux entrants vers la matrice sont alimentés horizontalement et les signaux sortants sont alimentés verticalement. À chaque intersection, il peut y avoir un transistor, puis le signal entrant fait partie de la grille; s'il n'y a pas de transistor, cette entrée est ignorée. Le résultat est des vannes NOR disposées de manière compacte. Dans les premiers microprocesseurs, le décodeur était souvent fabriqué à partir d'une matrice de portes NOR - par exemple, c'était le cas avec le 6502.



Le diagramme ci-dessous montre trois décodeurs agrandis sur le côté droit, qui sont entourés en jaune dans le diagramme ci-dessus. Ce diagramme correspond au décodeur le plus à gauche. Faites attention à la correspondance des transistors sur le schéma avec les taches roses des transistors sur le schéma. L'idée est que si un signal d'entrée active le transistor, alors le transistor tire le signal de sortie vers la masse. Sinon, la sortie est tirée vers le haut par une résistance. Les onduleurs situés en bas amplifient le signal afin qu'il y ait suffisamment de courant pour alimenter les huit parties de la batterie. Fait intéressant, cette disposition utilise des paires de transistors avec la masse et la sortie connectées - je ne vois aucun avantage à utiliser simplement un seul transistor. Dans tous les cas, remarquez comment le PLM fournit un arrangement dense de décodeurs.



Notez que l'onduleur dans le décodeur d'instructions est tiré jusqu'à 12 V, et non 5 V. C'est parce que le nanoprocesseur utilise des transistors à grille métallique au lieu des transistors à grille en silicium plus avancés que l'on trouve dans d'autres microprocesseurs de l'époque. L'inconvénient d'un transistor avec une grille métallique est une tension de seuil accrue, de sorte que la tension de sortie du transistor est bien inférieure à la tension à la grille. La sortie d'un onduleur conventionnel est trop petite pour alimenter la grille du transistor de passage, car sa tension de sortie va chuter à nouveau. La solution est d'utiliser une alimentation 12 V pour les onduleurs du décodeur qui contrôle les transistors de dérivation de la batterie, les signaux auront alors une tension suffisante pour activer les transistors de passage. En d'autres termes, le nanoprocesseur a besoin de 12+ V supplémentaires,car il utilise des transistors à grille métallique au lieu des transistors à grille silicium plus avancés.





L'un des circuits de décodeur du nanoprocesseur. Le diagramme de gauche correspond au décodeur le plus à gauche des trois indiqués à droite.



Ce circuit génère un signal d'incrémentation / décrémentation qui est introduit dans le circuit accumulateur. La ligne détecte une correspondance lorsque le niveau de signal du générateur d'horloge, de la demande, du 6ème bit de commande et du 2ème bit de commande est bas - une correspondance est trouvée sous la forme x0xxx0xx pendant la phase d'exécution. Ces commandes comprennent «Increment Binary» (00000000), «Increment BCD» (00000010), «Decrement Binary» (00000001) et «Decrement BCD» (00000011).



La chaîne montrée dans le diagramme recherche des correspondances avec des commandes de la forme x0xxx0xx, donc la correspondance est trouvée avec beaucoup plus de commandes que simplement incrémenter et décrémenter. Pourquoi ne recherche-t-il pas une correspondance complète? La raison en est que si l'accumulateur n'est pas utilisé, l'activation du signal d'incrémentation / décrémentation n'a pas d'importance. En élargissant la liste des options correspondantes, les développeurs pourraient se débarrasser de certains des transistors du circuit. Il est important que la chaîne remplace les autres instructions relatives à l'accumulateur telles que «Effacer l'accumulateur» (00000100) ou «Charger l'accumulateur à partir du registre» (0110rrrr).



Comparateur



Un circuit nanoprocesseur important est un comparateur qui compare la valeur stockée dans l'accumulateur avec la valeur du registre R0. Le comparateur utilise un circuit unique mais délicat pour les comparer. Essentiellement, l'algorithme compare deux nombres en commençant par les bits les plus significatifs. Si les bits sont égaux, passez aux bits inférieurs. La première différence de bit détermine la valeur la plus élevée (par exemple, dans le cas de 10101010 et 10100111, cela détermine le 4ème bit à partir de la droite).



L'algorithme est implémenté en huit étapes, une étape à la fois, en commençant par le bit le plus significatif en bas. Chaque étape se compose de deux parties symétriques - l'une détermine si l'inégalité A> R0 est vraie, et sa partie supplémentaire vérifie l'inégalité A <R0. Si les nombres étaient toujours égaux, mais qu'une différence a été trouvée à ce stade, l'étage génère un signal «plus» ou «moins». Sinon, il transmet la décision à un niveau inférieur. La décision finale est prise par l'échelon le plus élevé. Veuillez noter que la comparaison pour l'égalité dans le comparateur a lieu "gratuitement" - s'il n'y a pas de signaux "plus" ou "moins" à la sortie, alors les valeurs sont égales.





Une des étapes d'un comparateur 8 bits



Le schéma ci-dessous montre la disposition physique des deux étages du comparateur. Une astuce dans la disposition du comparateur est qu'il se situe entre le registre 0 à gauche et l'accumulateur à droite, ce qui minimise la longueur des fils. Le comparateur accède directement au registre 0, en contournant les chemins habituels de sélection de registre et de bus de données.





Deux étapes du comparateur - comme spécifié sur le photomasque



Les commandes de branchement conditionnel du nanoprocesseur peuvent inspecter la sortie du comparateur. Les circuits de dérivation conditionnels sont assez simples: quelques bits de l'instruction de branchement sélectionnent un contrôle particulier via le multiplexeur. Ensuite, le 7ème bit de la commande décide s'il faut sélectionner "cette branche si vraie" ou "cette branche si elle est fausse". Contrairement à la plupart des processeurs, Nanoprocessor ne permet pas de branchement à une adresse. Il saute simplement deux octets de commande si la condition est remplie (et généralement ces deux octets contiennent la commande pour aller à la cible souhaitée, mais parfois il y a d'autres commandes). Le schéma de saut est simple: le compteur de programme est appelé à nouveau, en augmentant la valeur non pas de 1, mais de 2, en sautant deux commandes. Il s'avère que Nanoprocessor implémente une large gamme de contrôles conditionnels sur un nombre relativement petit de réseaux.



Le nanoprocesseur a un grand ensemble de conditions de branchement - étonnamment grand pour un processeur aussi simple. Vous pouvez vérifier les conditions suivantes: A> R0, A> = R0, A <R0, A <= R0, A == R0 ou A! = R0. De plus, le branchement conditionnel peut dépendre du fait que la valeur dans l'accumulateur est zéro ou non, si un bit particulier de la valeur stockée dans l'accumulateur est égal à zéro, si l'indicateur de débordement est défini ou si un certain bit du registre d'E / S est défini.



Batterie et dispositif logique de contrôle



L'accumulateur est un registre spécial de 8 bits qui stocke l'octet en cours de traitement. Les opérations avec la batterie sont effectuées par un dispositif logique de contrôle (ULU), qui dans les instructions du processeur est appelé le "cœur du nanoprocesseur" ULU est l'équivalent d'une unité arithmétique et logique (ALU) dans la plupart des processeurs, mais il n'effectue pas d'opérations arithmétiques ou logiques. Dans le même temps, l'ULU n'est pas aussi inutile qu'il n'y paraît à première vue. Il peut incrémenter ou décrémenter la valeur de l'accumulateur, en code décimal binaire ou binaire (BCD). Le BCD stocke deux décimales dans un octet. C'est un mode très utile pour les E / S ou les affichages. En outre, l'ULU peut trouver le complément binaire de l'accumulateur ou le réinitialiser, ainsi que définir et effacer un certain bit. Finalement,il prend en charge les opérations de décalage gauche et droite.





Circuits liés à la batterie



Le schéma ci-dessus montre les circuits de la batterie et ULD. Dans la première section, divers réseaux sont localisés, définissant une valeur nulle, prenant en charge le BCD et fournissant un glissement de report - génération rapide d'un report à partir des 4 bits les moins significatifs. La deuxième section contient la batterie principale et les circuits ULU. La troisième section distribue les signaux de commande de la logique de décodage ci-dessus aux huit parties de l'accumulateur. La dernière section contient la logique de décodage des instructions qui décode les opérations sur les bits et envoie le signal à la partie souhaitée de l'accumulateur.



Le corps principal de l'accumulateur / ULU se compose de 8 parties, une par bit, avec le bit le moins significatif en haut. Nous examinerons quatre circuits de chaque partie: un générateur de report pour les opérations d'incrémentation / décrémentation, un générateur de bits pour les opérations d'incrémentation / décrémentation, un multiplexeur pour sélectionner une nouvelle valeur d'accumulateur et un verrou où la valeur de l'accumulateur est stockée.



Chaque partie du dispositif d'incrémentation / décrémentation (ci-dessous) est implémentée à l'aide d'un demi-additionneur. La direction de la chaîne d'incrémentation / décrémentation détermine l'opcode: 0 dans le bit de poids faible de l'opcode indique incrémentation et 1 pour décrémentation. La chaîne de report sur la gauche génère le signal de report. Pour un incrément, créez une sortie de report si une entrée de report est reçue et que le bit courant est 1 (depuis lors, il sera incrémenté en binaire 10). Pour la décrémentation, la ligne de report signale un emprunt , donc une sortie de report est générée lorsqu'il y a une entrée de report (c'est-à-dire, un emprunt) et le bit actuel est 0.





Une partie de la chaîne d'incrémentation / décrémentation



La ligne de droite met à jour le bit courant avec un incrément ou un décrément. Le bit actuel est basculé lorsqu'une entrée de retenue est présente - essentiellement une implémentation XOR via trois portes NOR. L'une des difficultés est de s'adapter au BCD. Pour l'opération d'incrémentation BCD, le report se produit lorsque le chiffre 9 est incrémenté, et pour l'opération de décrémentation BCD, le chiffre 0 diminue à 9 au lieu du binaire 1111.



Le multiplexeur gère les différentes opérations de la batterie. Selon le fonctionnement, un transistor à un passage est activé, sélectionnant la valeur souhaitée. Par exemple, pour une opération d'incrémentation / décrémentation, le transistor supérieur sélectionne la sortie du circuit d'incrémentation / décrémentation décrit ci-dessus. Le transistor active le décodeur d'instructions décrit précédemment, qui a trouvé l'instruction d'incrémentation / décrémentation correspondante. De même, une commande de décalage vers la droite active un transistor de décalage vers la droite en appliquant n + 1 bits de batterie à chacune des parties de l'accumulateur pour décaler la valeur.





Circuit pour un verrou qui stocke un bit de la batterie et un multiplexeur qui sélectionne l'entrée pour la batterie



Le verrou détient un bit pour l'accumulateur. Lorsque le transistor de maintien de batterie est activé, les deux portes NOR forment une boucle de maintien. Si le transistor de charge de batterie est activé à la place, la batterie charge la valeur souhaitée à partir du multiplexeur. Les lignes pour effacer le n bit et définir le n bit permettent aux commandes de changer des bits individuels de l'accumulateur; le multiplexeur met alors à jour tous les bits de l'accumulateur à la fois.



Adressage des compteurs et des programmes



Un autre gros bloc de chaînes est le compteur de programme à 11 bits situé dans le coin inférieur gauche du nanoprocesseur. Dans ce bloc également, il y a un verrou qui stocke l'adresse de retour du sous-programme, et un autre verrou qui stocke le compteur de programme après l'interruption. Considérez-les comme une pile d'un élément de long. Le compteur logiciel a un dispositif d'incrémentation qui est responsable du passage à la commande suivante. Il sait également incrémenter de deux à la fois, permettant aux instructions de branchement conditionnel de sauter deux instructions (un tel dispositif d'incrémentation est implémenté simplement en augmentant le 1er bit au lieu du 0ème bit). Pour accélérer le fonctionnement du dispositif d'incrémentation, il dispose d'une fonction de report; si les six bits les moins significatifs sont tous 1, il incrémentera le 6ème bit à la fois, sans attendre que le report passe par tous les bits les moins significatifs.



Contrôle et fréquence d'horloge



La dernière partie du nanoprocesseur est le circuit de contrôle. Comparé à d'autres microprocesseurs, le schéma de contrôle des nanoprocesseurs semble presque trivial: le processeur passe de l'horloge de demande à l'horloge d'exécution et inversement (avec des interruptions périodiques). Le circuit de contrôle n'est que quelques bascules et portes, donc il n'y a pas grand chose à dire à ce sujet.



Conclusion



Le schéma ci-dessous montre les principaux blocs fonctionnels de Nanoprocessor. Le nanoprocesseur a réussi à les adapter très étroitement, bien mieux que ce à quoi je m'attendais de la technologie obsolète des obturateurs métalliques. L'ingénierie inverse montre que ces blocs fonctionnels sont mis en œuvre avec des circuits simples mais soigneusement conçus.



Le nanoprocesseur utilisait des transistors à grille métallique, tandis que d'autres microprocesseurs ont commencé à passer aux transistors à grille en silicium depuis plusieurs années. La différence peut sembler incompréhensible, mais elle a un effet significatif sur la localisation des composants: dans la fabrication d'un transistor à grilles en silicium, une couche de polysilicium avec des conducteurs est ajoutée. Cela facilite grandement le positionnement des composants, car vous disposez de deux couches de conducteurs pouvant traverser la couche adjacente. Si vous n'avez qu'une couche métallique, il est beaucoup plus difficile de positionner les composants car les conducteurs se mettent en travers. Dans d'autres puces que j'ai étudiées qui utilisaient la technologie des transistors à grille métallique,la disposition des composants était dégoûtante - un tas de fils emmêlés apportant des signaux à chaque transistor maintenait la densité des transistors faible. D'un autre côté, les blocs fonctionnels Nanoprocessor sont conçus avec beaucoup de soin et tous les signaux s'entendent très bien. Il y a un peu d'espace supplémentaire, par exemple, pour le bus de données, mais dans l'ensemble, je suis impressionné par la densité de la disposition du nanoprocesseur.







Composants fonctionnels de nanoprocesseur basés sur mon



nanoprocesseur de rétro-ingénierie - le processeur est inhabituel. À première vue, il m'a même semblé être un "faux processeur", faute d'opérations arithmétiques de base. Cependant, après l'avoir étudié plus en détail, j'étais toujours impressionné. Sa conception simple lui permet de fonctionner plus rapidement que les autres processeurs de l'époque. Le jeu de commandes peut faire plus que ce que vous voyez. Hewlett-Packard a utilisé le nanoprocesseur dans nombre de ses produits dans les années 1970 et 1980, dans des rôles plus complexes que ce à quoi on pouvait s'attendre - par exemple, analyser des chaînes et effectuer des calculs. Une fois ses masques publiés, nous pouvons apprendre tous les secrets des chaînes grâce auxquelles Nanoprocessor a travaillé.







Nanoprocesseur (puce blanche) faisant partie d'un module de synchronisation de précision Hewlett-Packard. Notez la tension manuscrite; chaque puce nécessitait sa propre tension de polarisation.



All Articles