| ★ CODING ★ CHRONIQUE Jean-Pierre Richard pour l'Ordinateur Individuel ★ Les opérations arithmétiques: addition et soustraction ★ |
| L'Ordinateur individuel n°21 - Les opérations arithmétiques: addition et soustraction |
Nous voici arrivés à la quatrième partie sur l'assembleur du microprocesseur Z80. Avec l'addition, la soustraction, la multiplication et la division, nous allons y aborder un point délicat du langage machine. Cet article, à la différence des précédents, posera de sérieux problèmes au lecteur qui n'a pas eu la curiosité de fréquenter l'école primaire, ou tout au moins n'a pas d'atomes crochus avec les « maths ». Mais ne nous décourageons pas si vite et attaquons courageusement opérations arithmétiques, opérations de comparaison, de logique, de décalage ou de rotation... et finalement les opérations d'entrée et de sortie. Mais comme de si nombreuses opérations seraient indigestes en une seule fois, nous nous contenterons dans cette avant-dernière partie de l'étude des additions et des soustractions.Mais d'abord, avant toutes choses et réciproquement (Pierre Dac), effectuons ensemble quelques révisions nécessaires à la bonne compréhension de ce qui va suivre... Expliquer ce qu'est un nombre en base n n'est pas si simple : il existe des règles dont certaines nous paraissent évidentes car nous les appliquons couramment. En voici quelques-unes :
En base 10, on dit que : 3 est à la position des centaines Il y a encore deux règles à se rappeler avant de manipuler les nombres en des bases différentes :
Prenons quelques exemples pour nous entraîner : quelle valeur prendra le nombre 101 suivant la base choisie ? En base 10 (ou base décimale), suivant la formule a x 10 la valeur du nombre 101 est : (1 x 10²)+ (0 x 10¹) + (1 x 100) En base 8 (ou base octale), toujours suivant la formule a x 8 , le nombre 101 représente la valeur décimale : (1 x8²) + (0x8¹) + (1 x 80) C'est-à-dire 101 (base 8) = 65 (base 10). C'est compris? alors la base 16 n'est plus qu'un jeu d'enfant : En base 16 (ou base hexadécimale), la formule à appliquer est a x 16l et le nombre 101 prend la valeur décimale : (1 x 16²) + (0 x 16¹) + (1 x 160) En effet, le nombre noté 101 représente en base 8 la valeur 65, en base 16 la valeur 257 et bien sûr en base 10 la valeur 101 (ouf !). Pour une base supérieure à 10, le problème de la représentation du chiffre se pose : en effet, si a est supérieur à 9, a n'est plus un chiffre mais un nombre (dans « notre » notation décimale !) Il occupe alors deux places et la détermination de l'indice i devient problématique. Un exemple classique est celui de la représentation du temps (celui qui passe...) : Dans la valeur 3 h 30 mn 45 s, a est un nombre. La séparation dans l'ordre par les symboles h, mn, s est imposée : l'heure est à l'indice i = 2, les mn à l'indice i = 1 et les secondes à l'indice i = 0. (Sans cette séparation par des symboles, un rendez-vous donné à 33045 sera manqué à coup sûr !). Dans le cas h, mn, s la base est 60 et la formule bien connue maintenant donne : a x 60i : (3 x 60²) + (30 x 60¹) + (45 x 600) Cette représentation est très lourde à manipuler : c'est pourquoi en base hexadécimale on a chois de représenter 10 par la lettre A, 11 par B et ainsi de suite jusqu'à F qu correspond à 15; ainsi a n'occupe dans cette base qu'une seule place. Et en base 2 (ou binaire) quelle valeur prend le nombre 101 ? a x 2i : C'est-à-dire que 101 (base 2) = 5 (base 10) Et maintenant La représentation binaire ne doit plus avoir de secrets pour vous; l'ensemble de 8 chiffres s'appelle octet et le chiffre ne peut prendre que la valeur 0 ou 1 (cf. règles précédemment énoncées). Quittons maintenant les problèmes posés par la manipulation des bases et gardons uniquement en mémoire (si j'ose m'exprimer ainsi) la représentation en base binaire. La première des opérations arithmétiques à étudier est l'addition : la règle primaire ou table de vérité est la suivante : 1 + 1 = (1) 0 où (1 ) est la retenue. Voici un exemple élémentaire qui met cette règle en pratique : 0011 (3) Entre parenthèses on trouve la valeur décimale correspondante. L'addition se décompose de la façon suivante : 1re colonne : 1 + 1 = 0 retenue (1 ) Continuons sur notre lancée et attaquons la soustraction : en fait, la soustraction est une addition entre un nombre positif et un nombre négatif. Nous avons déjà étudié la représentation du signe dans un octet Le BPS (Bit le Plus Significatif), chiffre indice 7, est égal à zéro (0)si le nombre est positif. Pour que le résultat de la soustraction soit exact il est nécessaire d'utiliser la représentation en complément à deux. Voici la marche à suivre pour trouver la représentation en complément à deux : la valeur décimale 17 se représente en binaire de la façon suivante : 000 1000 1 La représentation à un consiste à passer les 0 à l'état 1 et les 1 à l'état 0: 1110 1110 Pour obtenir la représentation à deux, il faut ajouter 1, ce qui donne : 1110 1111 soit — 17 (valeur décimale) en complément à deux (ou EF en hexadécimal que l'on notera EFH). Effectuons la soustraction 18 moins 17 : 0001 0010 ( 18) Le résultat est correct (ouf !). Une retenue a été posée sur le bit indice 0 d'un octet qui serait apparié à l'octet résultat. Ce nouvel octet est en fait le registre indicateur d'état, tandis que le bit indice 0 est l'indicateur de report C (C comme Carry). La représentation en complément à deux permet d'afficher sur un octet une valeur positive maximale de 01111111 soit 127 (décimal) et une valeur négative de 1000 0000 soit -128 (décimal). Vérifions à titre d'exemple si le nombre 1111 1111 (ou FFH en hexadécimal) est bien la représentation de signe négatif de la valeur décimale 1. Effectuons le complément àun(1 devient 0 et 0 devient 1), soit 00000000 puis le complément à deux (+ 1 ), soit 0000 0001 qui est bien égal à + 1. La programmation d'une opération arithmétique utilise beaucoup le registre indicateur d'état. Nous avons vu précédemment l'utilité de l'indicateur de report, voyons maintenant celle de l'indicateur de dépassement et de parité (parity overflow). Si l'on applique rigoureusement les règles précédentes, la somme de 01110000 (112 en décimal) et de 01001000 (72) donne 10111000: cette somme est bien évidemment négative puisqu'elle commence par 1. Son complément à deux est 0100 1000 (72). Le résultat obtenu est donc — 72 en décimal : ceci est complètement faux car, comme chacun le sait, la somme de deux nombres positifs est obligatoirement positive ! Pourquoi cette erreur ? En fait la somme décimale de 112 et de 72 doit donner 184, et nous avons vu précédemment que nous étions limités à + 127. Ce problème surviendra chaque fois que le résultat d'une opération sur 8 bits (addition ou soustraction) sera supérieur à +127 ou inférieur à — 128. De la même façon, le résultat d'une opération sur 16 bits devra être compris entre -32768 et + 32767. C'est ici qu'intervient le registre indicateur d'état et plus précisément le bit indice 2, indicateur P/V de dépassement. Ce bit et celui correspondant à l'indicateur de report permettront de vérifier la bonne exécution des opérations arithmétiques. Les exemples suivants vont nous permettre de mettre en évidence les modifications d'état des indicateurs considérés. 0000111 + 01000000 = 01000111 00000111 + 11111100 = (1)00000011 0111 1111 + 0000 0001 = 10000000 10000000 + 1111 1111 = (1)0111 1111 Si l'indicateur C est égal à 1, cela nous indique que le résultat est trop élevé pour être contenu dans le registre et qu'il y a un report sur un bit extérieur à l'octet; le résultat n'est pas faux pour autant. Si l'indicateur P/V est différent de zéro, il y a une erreur dans le résultat: il faudra donc appeler un sous-programme par JP pour y remédier. Quels sont les ordres d'exécution des additions ou soustractions en langage assembleur? Une table de vérité pour l'addition Dans le cas d'opérations arithmétiques 8 bits, un des termes se trouve obligatoirement dans l'accumulateur, l'autre terme étant soit dans un registre, soit à une adresse pointée par HL ou un registre indexé ; il peut aussi tout simplement être une valeur'numérique. Le résultat est consigné dans l'accumulateur. Voici ci-contre un exemple simple d'addition et de soustraction (voir liste A) : Les instructions ADC et SBC effectuent une addition ou soustraction tout comme ADD et SBB mais il y a ajout (ADC) ou retrait (SBC) de la retenue située dans l'indicateur de report. L'exemple de programme d'addition multibit qui va suivre illustre cette fonction d'ajout de la retenue. Les termes de cette addition, IX et IY, sont indiqués dans le tableau suivant :
A titre d'exercice, je vous conseille de faire l'addition «à la main » (le résultat est : 0111 0100 1001 0010 1111 0110) et de constater le report entre les deuxième et troisième octets (voir ci-dessus liste B). Le début du programme devra comprendre l'instruction ORA pour mettre à zéro l'indicateur de report, s'il doit être intégré comme sous-programme. Pour une opération sur 16 bits, le registre pair de base est le plus souvent HL (par contre les instructions ADC et SBC utilisent obligatoirement HL). La durée d'exécution de l'instruction est plus courte pour HL que pour les trois autres registres pairs possibles, IX, IY ou SP. Il faut noter que seul SBC (soustraction avec carry) existe en 16 bits. Un tableau peut être établi comme précédemment : les valeurs seront exprimées en 1 6 bits au lieu de huit bits. Le programme sera très similaire, à vous d'essayer...
Un moniteur (NASBUG, TBUG...) vous permettra de connaître le contenu des adresses mémoires et de vérifier le résultat. Multiplication et division en «binaire » seront étudiées le mois prochain en même temps que les « dernières» opérations disponibles qui sont néanmoins encore très nombreuses. Allons ! Encore un petit effort ! Il ne vous restera plus ensuite que... la pratique. Jean-Pierre Richard, L'Ordinateur individuel n°21
|