Dans ce chapitre, nous construisons un processeur (CPU) 8 bits qui va offrir une partie de la palette fonctionnelle du microprocesseur Intel 8080.
Nous commençons par l'unité arithmétique et logique ALU (Arithmetic Logic Unit). Cette ALU va être répartie en deux parties: - la première est l'unité arithmétique qui va réaliser les additions et soustractions, - l'autre va gérer les opérations logiques entre bits.
En haut à gauche, nous trouvons deux boutons binaires permettant de sélectionner une fonction parmi quatre: - Add pour l'addition (instruction ADD dans le 8080), - Add with Carry pour l'addition avec retenue (ADC dans le 8080), - Subtract pour la soustraction (SUB dans le 8080) et - Subtract with Borrow pour la soustraction avec retenue (borrow) (SBB dans le 8080).
Les deux rotacteurs A et B en haut à droite servent à choisir les deux valeurs hexadécimales à traiter. La paire de flèches à gauche de chaque nombre sert à progresser de 10h en 10h (donc de 16 en 16 en décimal). La paire de flèches à droite de chaque nombre sert à incrémenter et décrémenter (donc de 1 en 1).
Le Résultat est affiché en bas en hexadécimal. La retenue peut être ajoutée en entrée grâce au bouton de gauche CY In et un témoin de retenue CY Out est présent à droite.
Le circuit diverge un peu des précédents dans le sens où les valeurs de retenue CY In et CY Out sont inversées pour la soustraction.
Un processeur 8 bits doit savoir traiter en addition et en soustraction des valeurs sur 16, 24 ou 32 bits, etc. Il doit donc savoir préserver la retenue d'une première opération sur 8 bits pour l'injecter dans la suite du calcul.
Dans le cas de la fonction Add (ADD), le bouton d'entrée de retenue CY In à gauche n'a aucun effet. L'afficheur Résultat en bas montre l'octet bas de la somme des deux nombres, entre 00h et FFh. Le bit de sortie de retenue CY Out vaut 1 si la somme a dépassé 255.
Dans le cas de la fonction Add with Carry (ADC), basculer le bouton CY In à 1 permet d'ajouter 1 à la somme des deux valeurs en faisant passer l'entrée CI de l'additionneur 8 bits à 1.
Quand il s'agit d'additionner deux valeurs sur plusieurs octets, on utilise l'instruction de base Add pour les octets de poids faible (LSB). Pour le ou les octets suivants, on utilise la variante avec retenue Add with Carry sans oublier de positionner l'entrée de retenue CY In dans l'état qu'avait pris la sortie de retenue CY Out de l'addition précédente.
Pour faire quelques essais avec des valeurs sur 16 bits, profitez des nombres ronds suivants dont les équivalents en hexadécimal sont fournis dans ce tableau.
Valeur décimale | Equivalent en hexadécimal |
---|---|
10000 | 2710h |
15000 | 3A98h |
20000 | 4E20h |
25000 | 61A8h |
30000 | 7530h |
40000 | 9C40h |
Pour additionner 10000 et 30000, donc 2710h et 7530h, nous procédons en deux étapes. Nous additionnons d'abord les deux octets de poids faible 10h et 30h par l'opération de base Add (fonction 00). Le demi-résultat vaut 40h sans générer de retenue (CY Out reste à 0). Nous additionnons ensuite les deux octets de poids fort 27h et 75h par l'autre instruction d'addition, celle avec retenue Add with Carry (code 01) en laissant CY In à 0. Le demi-résultat valant 9Ch, nous reconstituons le résultat complet qui vaut bien 9C40h.
Pour un exemple avec retenue, partons des valeurs 3A98h et 61A8h (revoyez le tableau). Nous additionnons par Add les deux octets de poids faibles (octets bas), 98h et A8h. Le résultat 40h n'est juste qu'en tenant compte de l'armement de la retenue CY Out à 1. Pour les octets hauts, nous appliquons la variante avec retenue Add with Carry sur les valeurs 3Ah et 61h sans oublier que l'entrée de retenue CY In doit être armée (à 1), ce qui reflète l'état de CY Out après la première addition. Le demi-résultat 9Ch amène à un total général de 9C40h.
Osons maintenant combiner 7530h à 9C40h (ce qui fera 70000d, donc plus que 65535d qui est le plafond sur 16 bits). Nous appliquons d'abord Add à 30h et 40h, ce qui donne 70h avec CY Out à 0. Nous poursuivons avec Add with Carry de 75h et 9Ch en laissant CY In à 0. Le demi-résultat est 11, c'est-à-dire un résultat de 1170h (4464d), ce qui est visiblement faux. D'ailleurs CY Out est passé à 1, ce qui avertit qu'il y a eu débordement (overflow).
Ce débordement avertit que le résultat est à considérer sur 24 bits. Nous devons donc réaliser une troisième addition, toujours avec retenue Add with Carry entre les deux valeurs 00h et 00h mais avec la retenue CY In à 1. Le sous-résultat est bien sûr 01, ce qui permet de reconstituer la valeur sur 3 octets égale à 011170h (soit 70000 décimal).
Dans le cas de l'instruction Subtract (SUB), l'état de l'entrée de retenue CY In n'a aucun effet. La valeur choisie dans B est soustraite de celle dans A par inversion des bits de B, addition à ceux de A, et ajout de 1 par basculement de l'entrée de retenue CI à 1. Si la valeur dans B est inférieure ou égale à celle dans A, le Résultat est la différence comme attendu. Si B est supérieur à A, le témoin CY Out avertit qu'une retenue borrow est nécessaire.
Procédons à quelques essais. Demandons de calculer 7530h moins 4E20h (30000d - 20000d). Nous traitons d'abord les deux octets bas (de poids faible) : nous optons pour la fonction de base Subtract (code 10) et réglons A sur 30h et B sur 20h. La différence vaut 10h alors que la sortie de retenue CY Out reste à 0. Nous traitons ensuite les deux octets de poids fort avec la variante à retenue Subtract with Borrow (SBB) en réglant A à 75h et B à 4Eh et vérifions que CY In est à 0. Le demi-résultat vaut 27h et le résultat final composite se lit 2710h (soit 10000d).
Essayons 7530h moins 3A98h (30000d - 15000d). Nous choisissons la fonction Subtract avec A à 30h et B à 98h. Le sous-résultat vaut 98h et la retenue CY Out est à 1. Nous optons alors pour la fonction Subtract with Borrow pour traiter les deux octets hauts 75h et 3Ah en n'oubliant pas d'armer à 1 la retenue CY In afin de propager la retenue apparue dans CY Out. Le demi-résultat vaut 3Ah et le résultat final composite se lit 3A98h (soit 15000d).
Voyons pour finir un débordement causé par 3A98h moins 7530h (15000d - 30000d). Subtract appliqué aux octets bas 98h et 30h donne 68h avec CY Out à 0. Subtract with Borrow appliqué aux octets hauts 3Ah et 75h en laissant CY In à 0. Le demi-résultat vaut C5h et le résultat final composite se lit C568h (valeur fausse). En effet, la sortie de retenue CY Out est passée à 1, ce qui confirme la survenue d'un débordement (overflow).
Comme dans le cas du débordement d'une addition, vous pouvez terminer l'opération sur 24 bits en utilisant la même fonction Subtract with Borrow mais avec A et B forcés à 0 et la retenue CY In forcée à 1. Le résultat devient égal à FFh et CY In reste à 1.
Si vous utilisez votre Calculatrice Windows ou macOS en mode Programmeur, vous pouvez saisir en hexadécimal la soustraction 3A98h moins 7530h. Vous obtenez FFFFFFFFFFFFC598h, ce qui correspond à la valeur décimale négative –15,000. (Vous pouvez aussi chercher le complément à 2 de FFFFFFFFFFFFC598h par inversion de tous les bits et ajout de 1, ce qui donne 3A98h, soit 15000d.)
Le sous-ensemble de traitement logique de l'ALU est bien plus simple puisqu'il se résume à trois modules pour les trois opérations binaires AND, XOR et OR. Un sélecteur permet de choisir lequel des trois tampons triple-état TRI est activé (Enable).
Ici aussi, nous trouvons à droite deux rotacteurs de sélection des deux chiffres hexa d'un nombre sur 16 bits. Les trois boutons de gauche servent à choisir une fonction. Les trois opérations logiques supposent que le premier bouton de gauche soit à 1.
Si le bouton de gauche est à 0, les deux autres servent à choisir une des quatre opérations arithmétiques déjà vues plus haut. Dans ce cas, aucun des tampons TRI n'est activé. Le code 111 correspond à l'opération Compare dont nous parlons dans le circuit combiné suivant.
L'unité ALU combine celle d'addition/soustraction et l'unité logique. La version du livre a été simplifiée et ne gère pas correctement les instructions Compare qui nécessitent quelques aménagements plus complexes que voici.
Les entrées de données A et B sont en haut à gauche et à droite. Le sélecteur de fonction est au milieu en haut.
L'entrée d'horloge Clock en bas à gauche déclenche le stockage du résultat et l'état des trois drapeaux flags. En bas à droite, le bouton d'autorisation Enable fait afficher le résultat.
Les quatre premières instructions sont celles prises en charge par le sous-ensemble Add/Sub vu plus haut. La sortie de retenue CY Out est préservée dans le verrou des drapeaux Flags en bas et aussi réinjectée dans l'entrée de retenue CY In.
Les trois fonctions logiques AND, XOR et OR sont traitées par le sous-ensemble Logique en haut à droite. Toutes trois forcent le drapeau de retenue Carry à zéro, en relation avec une partie des traitements logiques dans la partie supérieure menant à l'entrée de retenue CY du verrou des drapeaux Flags.
Pour les 7 fonctions (les 4 arithmétiques et les 3 logiques), le drapeau Zero passe à 1 si le résultat est égal à 0. L'action est gérée par deux portes NOR à huit entrées vers le milieu du circuit.
La partie délicate est celle consacrée à l'opération Compare. Elle arme les deux drapeaux Zero et Carry comme si une soustraction venait d'être réalisée. Le drapeau Zero est armé (à 1) si la valeur dans A est la même dans B. Le drapeau de retenue CY est armé si A est inférieur à B.Cela dit, la comparaison ne modifie pas le contenu de l'Accumulateur. L'entrée de donnée A est activée avec le tampon triple-état tout à gauche sauvegardé dans le Verrou en bas à droite.
Lors de la comparaison, le module Add/Sub effectue une soustraction avec retenue parce que F1 et F0 sont tous deux à 1. C'est pourquoi l'entrée de retenue CY In est forcée à 0 lors d'une opération Compare.