★ CODING ★ Dr.Watson - Autoformation à l'assembleur par Micro Application ★ |
Dr.Watson - Autoformation à l'assembleur par Micro Application - Chapitre 06 |
CHAPITRE 6 MULTIPLICATION, DIVISION ET GROUPE ROTATION Presque toutes les applications réelles des ordinateurs demandent la manipulation des nombres. Alors que quelques unes ne demandent qu'une addition ou une soustraction fondamentale/ d'autres demandent la multiplication et la division. Dans ce chapitre nous verrons comment ces fonctions arithmétiques peuvent être réalisées en langage assembleur. MULTIPLICATION BINAIRE Avant de nous embarquer dans la Multiplication Binaire, observons le processus de la multiplication décimale. Prenez le total 13x14. Nous définissons 13 comme le MULTIPLICANDE et 14 comme le MULTIPLICATEUR et posons la multiplication comme ceci : 13 Multiplicande 14 Multiplicateur -- 52 130 -- 182 Réponse La multiplication est accomplie en multipliant le multiplicande par le chiffre situé à l'extrême droite du multiplicateur et en stockant ce résultat comme le "produit partiel", soit : 13x4=52. Ensuite nous multiplions le multiplicande par le chiffre suivant du multiplicateur, ce qui nous donne un deuxième produit partiel, soit : 1x13=13. On écrit ce produit partiel avec un décalage d'une position vers la gauche. Les deux produits partiels sont alors additionnés et donnent un résultat de 182, ce qui est la réponse juste. Il est tout à fait possible d'utiliser la même méthode pour effectuer une multiplication binaire. Par exemple, pour multiplier 5x7 en binaire : 5 = 0101 (Calcul en 4 bits seulement) 7 = 0111 ; 0111 = (7) ; x 0101 = (5) ; Puis en additionnant Produit partiel 1 0111 ;0111 Produit partiel 2 00000 ;0111 Produit partiel 3 011100 ;100011 Produit partiel 1 0000000 ;100011 Rep: 100011 100011 = (1x32)+(0x16)+(0x8)+(0x4)+(1x2)+(1x1)=35 Avec 1 pour chiffre à l'extrême droite du multiplicateur, le produit partiel a la même disposition de chiffres que le multiplicande, soit : 0111, Sinon le produit partiel est zéro, soit : 0000. Tout nouveau produit partiel est écrit en le décalant d'une position vers la gauche. Ainsi la multiplication binaire se réduit à des additions successives et des décalages. MULTIPLICATION A 8 BITS Pour effectuer une multiplication en utilisant le Z80, nous utiliserons l'accumulateur pour garder le 'total en cours', le registre C pour garder le multiplicande et le registre E pour garder le multiplicateur. Voyons maintenant comment sont formés les produits partiels. ; 0 1 0 1 ; ! ! ! ! Produit partiel 1 0111 = 0111x1 <-!-!-!-! Produit partiel 2 0000 = 0111 x0 <-!-!-! Produit partiel 3 0111 = 0111 x1 <-!-! Produit partiel 4 0000 = 0111 x0 <-! ;^ ^ ;^ ^ ---------------------------- ;^ !0111 décalé à gauche! ; ^ !chaque fois (appelé ! ----------------- !le Produit Partiel ! !Le bit suivant ! !Invisible PPI) ! !de 0101 chaque ! ---------------------- !fois. ! ;----------------- Le problème de la multiplication binaire peut être exprimé dans l'organigramme suivant.
FIGURE 6.1 Ce qu'il nous faut maintenant avant d'écrire le programme, ce sont le instructions qui nous permettront de décaler les bits dans les octets. SRI s Logical Shift Right (Décalage Logique à Droite) de l'opérande s Représenté en diagramme : !---------! ;--- 0---->! 7----->0! ----> !?! !---------! ;--- Octet opérande Flag Carry (retenue) Par exemple, examinons le décalage à droite de 10110111 avec l'instruction SRL, ;Octet ; Flag Carry Avant 1 0 1 1 0 1 1 1 ; ? Après 0 1 0 1 1 0 1 1 ; 1 Le bit 7 a été remplacé par un 0,les bits 1 à 6 décalés à droite d'une position et le bit 0 placé dans le flag Carry (retenue). Maintenant le programme: PROGRAMME 6.1 LD A,0 Accumulateur a Zéro LD C,7 C = Multiplicande LD E,5 E = Multiplicateur LD B, 4 ;B = Compte (pour 4 bits) ADD: SRL C ; Décaler C à droite JR NC,NOADD: Si bit a l'extrême droite = 0 alors sauter à NOADD ADD A,E Ajouter PPI au total en cours dans l'accumulateur NOADD: SLA E ; Décaler PPI à gauche DEC B ; Décrémenter le compteur JR NZ,ADD: Resauter à ADD s'il y a encore des bits a multiplier ADD A,65 ;Ajouter décalage CALL &BB5A Afficher le caractère sur l'écran RET ; Retour Un décalage de 65 est utilisé donnant l'affichage sur l'écran du caractère ayant pour code ASCII 100- soit la lettre minuscule d (La réponse à 7x5 était 35, 35+65=100). EXERCICE 6.1 Ecrivez un programme pour multiplier 10x9. Puis afficher le résultat directement sur l'écran. Une réponse possible est donnée au chapitre solutions. Le programme 6.1 ne peut que multiplier deux nombres ayant pour résultat un total inférieur à 255. ta principale raison de cette limitation est que le produit partiel invisible est décalé à gauche et sera finalement décalé complètement hors du registre, Un problème similaire s'est présenté lorsque nous faisions une addition et une soustraction à 16 bits, le problème était résolu en rechargeant le registre de gauche avec le bit de retenue quand il y avait dépassement. Ce qu'il faut maintenant, c'est une instruction qui, après une instruction de décalage sur l'octet faible, décalera l'octet fort ainsi que toute retenue générée. Cela se fait avec l'instruction suivante : RL s Rotation à gauche de l'opérande s ainsi que du bit de retenue. En diagramme : Bit de retenue (Carry) Opérande ------------>------------- - --- ------------ ! --<-! !-----! 7 --- ------------ Le flag de retenue est chargé dans le bit 0, les bits 1-8 sont décalés à gauche d'une position et le flag Carry reçoit le bit 7. Pour décaler un registre à 16 bits il nous faut donc deux instructions. L'octet faible est décalé normalement avec l'instruction SLA, puis l'octet fort est décalé avec RL. Par exemple, supposons que nous voulions décaler a gauche le contenu de DE. Les instructions suivantes accompliraient cela : SLA E RL D Incorporons cette Instruction dans un programme. Problème : Affichez sur l'écran le résultat de l'opération suivante: 7x10 = ? PROGRAMME 6.2 LD C,7 ;C = Multiplicande LD E,10 E = Multiplicateur LD D,0 ;Registre D a zéro LD B,8 B = Nombre de bits LD HL,0 HL à zéro, on l'utilise pour garder le total actuel NXTB: SRL C Décaler Multiplicande a droite JR NC,NOADD: Si retenue=0 sauter à NOADD ADD HL,DE Ajouter PPI au total en cours NOADD: SLA E ;Décaler octet faible à gauche ; RL D ;Recharger la retenue et décalez D à gauche ; DEC B Décrémenter compteur JR NZ,NXTB: Resauter si encore des bits LD A,L ;Charger dans A la réponse RET NB. Bien que nous ayons utilisé un registre a 16 bits pour le résultat en sélectionnant soigneusement le multiplicateur et le multiplicande, seul l'octet faible contient une valeur, ce qui nous permet de l'afficher sur l'écran. EXERCICE 6.2 En utilisant le programme 6.2 calculer la réponse de 146x124. Notez que cela donnera une réponse a 16 bits, donc H et L devront être affichés sur l'écran. Une réponse possible est donnée au chapitre solutions. Le programme 6.2 a utilisé le registre B comme compteur, Chaque fois que le multiplicateur était décalé à gauche, B était décrémenté puis testé. Cette opération demande deux instructions: DEC et JR NZ. Ces deux instructions, peuvent néanmoins être remplacées par une seule, qui rend le programme plus efficace et plus élégant. DJNZ e Décrémenter B et si cela donne une réponse Non-Zéro sauter a l'adresse mémoire e. EXERCICE 6.3 Remplacez les Instructions DEC B et JR NZ-NXTB par une instruction DJNZ NXTB dans le programme 6.2, ou dans votre réponse a l'exercice 6.2 Une réponse est donnée dans le chapitre solutions. La division binaire est aussi possible avec une méthode très similaire à celle utilisée pour la multiplication. DIVISION BINAIRE Observons la division suivante : ---- 10 !785 D'abord nous essayons de diviser 7 par 10; comme 10 ne rentre pas dans 7 la prochaine étape c'est de prendre le 8 et d'essayer de diviser 78 par 10. Il y va sept fois et il reste 8. 7 ---- 10 !785 comme 10 'ne rentre pas dans'8, la prochaine étape c'est de prendre 5 et d'essayer de diviser 85 par 10. Il y va 8 fois et il reste 5. 78 ---- reste 5 10 !785 Donc le résultat est 78 et le reste 5. Cette forme de division est appelée "division entière" puisque les fractions en sont exclues. Comme pour la multiplication les différents nombres d'une division ont des noms; par exemple "reste" est déjà familier. Les autres noms sont : ; quotient ; ! ; 78--------! ; ---- 10 !785 reste = 5 ^ ^ ;^-------- Dividende Diviseur-- Etudions maintenant une division de 16 bits par 8 bits. Problème Afficher sur l'écran le résultat de la division suivante dans un format reconnaissable. 2765 : 75 = ? La division binaire se fait de la manière suivante, Si sans emprunt (retenue négative), le diviseur à 8 bits peut être soustrait de l'octet fort du dividende a 16 bits, alors le bit approprié de la réponse à 8 bits est mis. Ce procédé se répète huit fois, donnant un quotient à 8 bits et un reste à 8 bits. PROGRAMME 6.3 LD HL,2765 HL = Dividende LD C,75 ;C = Diviseur LD B,8 ; B = compte NXT: ADD HL,HL ;Décaler dividende a gauche LD A,H ; A = octet fort du dividende SUB C ; Soustraire diviseur JR C,NXTB: Si retenue sauter à NXT LD H,A ; Recharger octet fort du dividende INC L ; Incrémenter la réponse NXTB: DEC B ; Décrémenter le compteur JR NZ,NXT: Si non-zéro sauter à NXT LD A,L ; A = réponse (quotient) CALL &BB5A Afficher la réponse LD A, H ;A = reste CALL &BB5A Afficher le reste RET Lancez le programme. Il affichera '$A' sur l'écran, ici le code ASCII de !$! correspond à la réponse et 'A' au reste. Vérifiez que ceux-ci soient justes. Il faut noter que comme le Z80 ne possède pas une instruction de décalage à gauche à 16 bits, on a utilisé ADD HL,HL. En binaire, ajouter un nombre à lui-même c'est la même chose que de le décaler à gauche d'une position bit, ou de le multiplier par deux. Si vous comparez cela avec la base 10, par exemple, décaler 19 à gauche, cela donnera 190 -l'équivalent d'une multiplication par 10. A votre avis, qu'est-ce qui se passerait si on décalait d'une position bit a droite un nombre binaire ? (Réponse : c'est la même chose que de diviser par 2). Jusqu'ici, seules quelques instructions de décalage du Z80 on été utilisées pur des routines de multiplication et division d'usage général. Il est quelque fois Plus facile et plus rapide d'utiliser un petit groupe d'instructions de décalage ou de rotation pour exécuter une opération arithmétique spécifique. Quand on utilise une instruction de rotation par opposition à une instruction de décalage, le contenu du registre est modifié, mais aucune information n'est perdue, c'est à dire qu'aucun bit ne disparaîtra sans laisser de trace. Voici une instruction qui fait Pivoter à gauche le contenu de l'accumulateur : RLCA Rotation à gauche de l'Accumulateur et chargement d'une copie du bit 7 dans le flag Carry. RLCA sous forme de diagramme : Flag Carry Accumulateur ; -------->------- ---- ! -------- ! ! !-----------!7<---0!<---- ---- ;-------- Notez que le bit 7 n'est cas perdu mais inséré dans le bit 0. Une Instruction pour faire pivoter à droite le contenu de l'accumulateur existe également : RRCA Rotation à droite (Right) du contenu de l'Accumulateur et chargement ;d'une copie du bit 0 dans le flag de retenue. Utilisons ces deux Instructions. Problème : Multipliez 10 par 16, affichez sur l'écran le résultat, divisez ce résultat par 2 et ; affichez le sur l'écran. PROGRAMME 6.5 LD A,10 A=10 RLCA A=20 RLCA A=40 RLCA A=80 RLCA A=160 CALL &BB5A Affiche A ('•') RRCA A=80 CALL &BB5A Affiche A('P') RET EXERCICE 6.4 Ecrivez un programme pour calculer et afficher sur l'écran les résultats des opérations suivantes en utilisant des instructions de rotation et d'addition. 1. 5 x 32 = (160) 2. 254 – 2 = (127) Les réponses possibles sont données dans le chapitre solutions. Le Z80 possède encore d'autres Instructions de rotation et de décalage que nous n'avons pas utilisées. Elles sont détaillées dans les appendices sous le titre 'Jeu d'instructions du Z80', Observons maintenant un jeu d'instructions oui permet la mise, l'annulation et le test de bits isolés au sein d'un octet. LE GROUPE MISE, ANNULATION ET TEST DE BIT Examinez l'instruction suivante : BIT b,r Teste le bit à la position b dans l'opérande r. Cette instruction est utilisée chaque fois qu'un bit particulier dans un octet a besoin d'être testé, par exemple dans les opérations d'entrée/sortie. Pour illustrer l'utilisation de cette commande, un registre sera mis à zéro, incrémenté jusqu'à la mise du bit 7, le contenu du registre qui en résultera sera alors affiché sur l'écran. PROGRAMME 6.6 LD A,0 ; A=0 NXT: INC A ; Incrémenter A BIT 7,A ; Tester bit 7 de l'accumulateur JR Z,NXT: ; Le bit 7 est-il mis ? CALL &BB5A ; Afficher contenu de A sur écran RET Ce programme charge zéro dans A et l'incrémente continuellement jusqu'à la mise du bit 7. Lancez-le; on ne remarque pas grand chose puisque la mise du bit 7 correspond à 128 en décimal, un espace en ASCII. Essayez d'insérer soit l'instruction INC A soit l'instruction DEC A juste avant l'instruction CALL &BB5A, pour imprimer quelque chose de visible sur l'écran. Deux autres instructions de bit existent: l'une pour mettre le bit et l'autre pour annuler un bit individuel dans un octet. SET b,r Met le bit en position b dans l'opérande r. RES b,r Annule (RESet) le bit en position b dans l'opérande r. Pour illustrer ces instructions, observons le code ASCII de 'C', en binaire 01000011. Si le bit 0 est annulé, c'est la même chose que soustraire un, ce qui donne la représentation ASCII de B. PROGRAMME 6.7 LD A, 67 A=ASCII pour 'C' CALL &BB5A Affiche 'C' RES 0,A ;Annule bit 0 CALL &BB5A Affiche 'B' SET 0,A ;Met le bit 0 CALL &BB5A Affiche 'C' RET EXERCICE 6.5 Ecrivez un programme qui charge 255 dans l'accumulateur, affiche le contenu sur l'écran, annule le bit 4, affiche le résultat sur l'écran, met le bit 1, annule le bit 3 et puis affiche le résultat final sur l'écran. Une réponse possible est donnée au chapitres solutions. Voilà un autre chapitre terminé, à présent vous devriez avoir une assez bonne idée de comment écrire un programme relativement complexe. Et pour résumé: RESUME Les notions et les groupes d'instructions suivants devraient à présent vous être assez familiers : 1. Multiplication et division binaires 2. Le groupe décalage et rotation 3. La groupe mise, annulation et test de bit.
|