TD 4 : Programmation en assembleur 8086
Transcription
TD 4 : Programmation en assembleur 8086
Microprocesseur 8086 - TD 4 TD 4 : Programmation en assembleur 8086 Exercice 1 : Ecrire un programme, en langage assembleur 8086, qui permet de compter les nombres nuls dans un tableau d’octets mémoire de longueur 100h et débutant à l’adresse [200h], le résultat sera placé à l’adresse [400h]. Solution : Début NZ <-- 0 C <-- 1 NON T(C) = 0 ? OUI NZ <-- NZ + 1 C <-- C + 1 NON OUI C < N ? Fin Exploitation des registres : Le compteur C sera remplacé par le registre CX, et comme tout le tableau de N octets sera examiné, donc CX va prendre N valeurs, la toute dernière est toujours égale à 1, donc la valeur initiale sera N : CX = N, N-1, N-2, ... 2, 1. Lorsque CX est initialisé à N, La valeur actuelle du tableau mémoire, qui est définie par DS:[SI], est initialisée par DS:[100h] ; à chaque décrémentation de CX correspond une incrémentation de SI. 1 Début BX <-- 0h CX <-- 100h SI <-- 200h CMP DS:[SI],0 NON Z = 1 ? OUI BX <-- BX + 1 SI <-- SI + 1 CX <-- CX - 1 OUI NON Z = 1 ? DS:[400h] <-- BX Fin Après la décrémentation de CX, on n’a pas besoin d’effectuer une comparaison entre CX et 0, parce que la décrémentation est suffisante pour affecter le flag Z dont on a besoin pour effectuer l’instruction de saut qui vient juste après la décrémentation de CX. Donc les instructions de saut sont généralement utilisées après une comparaison ou après une décrémentation du compteur. 2 Le programme en langage assembleur 8086 : (partie la plus significative) Etq2 : Etq1 : MOV MOV MOV CMP JNZ INC INC DEC JNZ MOV BRK CX, 100h BX, 0000h SI, 200h [SI], 0 Etq1 BX SI CX Etq2 [400], BX Contrairement à l’instruction HLT qui fait arrêter le 8086 de toute activité jusqu’à l’arrivée d’une interruption matérielle, l’instruction BRK (break) fait arrêter le programme en cours d’exécution et revenir à l’exécution du système d’exploitation. 3 Exercice 2 : Ecrire un programme qui permet de déterminer le maximum dans un tableau d’octets mémoire de longueur 100h et débutant à l’adresse [200h], le résultat sera placé à l’adresse [400h]. Solution : Début CX <-- FFh SI <-- 200h AL <-- [SI] SI <-- SI + 1 NON OUI AL > [SI] ? AL <-- [SI] CX <-- CX - 1 OUI NON Z = 1 ? DS:[400h] <-- AL Fin 4 Le compteur CX a été initialisé à : N-1 = 100h - 1 = FFh ; En fait le registre AL prend la première valeur du tableau, c à d [200h] ; Puis il est comparé avec les N-1 valeurs suivantes. Pour chaque comparaison, CX prend une valeur, pour la comparaison de la dernière valeur du tableau, la valeur de CX et égale à 1, donc la valeur initiale de CX est N-1 : CX = N-1, N-2, ... 2, 1. Le programme en langage assembleur 8086 : (partie la plus significative) Etq2 : Etq1 : MOV MOV MOV INC CMP JLE MOV DEC JNZ MOV BRK CX, FFh SI, 200h AL, [SI] SI AL, [SI] Etq1 AL, [SI] CX Etq2 [400], AL 5 Exercice 3 : Ecrire un programme qui permet de trier par ordre croissant un tableau de longueur N = 100h débutant à l’adresse [200h]. Solution : Début BX <-- 200h CX <-- N-1 SI <-- BX + 1 DX <-- CX AL <-- [BX] OUI NON AL > [SI] ? XCHG AL,[SI] [BX] <-- AL SI <-- SI + 1 DX <-- DX - 1 OUI NON Z = 1 ? BX <-- BX + 1 CX <-- CX - 1 NON Z = 1 ? OUI Fin 6 Dans cette solution on a eu besoin de deux compteurs CX et DX ; En fait, pour chaque valeur du compteur CX on prend une des (N - 1) premières valeurs du tableau et on la compare avec toutes les valeurs qui viennent après (avec une pour chaque valeur de DX). Le compteur CX prend donc les valeurs suivantes : CX = N-1, N-2, ... 2, 1. Lorsque CX est fixé à une valeur (i), on est alors entrain de comparer la valeur (N - i) du tableau avec les (i) valeurs qui viennent après ; Donc pour chaque valeur de CX, DX prendra les valeurs suivantes : DX = CX-1, CX-2, ... 2, 1. 7 Une deuxième solution : Début CX <-- N-1 SI <-- 200h DX <-- CX BL <-- 0 AL <-- [SI] NON OUI AL ≤ [SI+1] ? XCHG AL,[SI+1] [SI] <-- AL BL <-- BL+1 SI <-- SI + 1 DX <-- DX - 1 OUI NON Z = 1 ? NON BL = 0 ? OUI CX <-- CX - 1 Z = 1 ? NON OUI Fin 8 Dans cette solution on fait le tri de chaque deux valeurs successives du tableau (si elles ne sont pas triées entre elles dans l’ordre croissant, on fait une permutation entre elles) ; Pour chaque valeur du compteur secondaire DX, les valeurs à trier sont pointées par [SI] et [SI+1] ; Le tableau ayant N valeurs, et le premier passage se faisant jusqu’à comparer entre l’avant dernière et la dernière valeur, le compteur principal CX aura donc à parcourir (N - 1) valeurs, càd: CX = N-1, N-2, ... 2, 1 Cette solution permet d’arrêter le processus lorsqu’on constate que le tableau et déjà trié après un passage du compteur secondaire DX par toutes ses valeurs concernées, même avant d’atteindre la limite du compteur principal (CX = 1) ; Pour chaque passage (i) (c à d pour chaque valeur du compteur principal CX = N - i), SI varie de sa valeur initiale (200h) jusqu’à la valeur (200h + N - i -1), ce qui donne (N - i) valeurs, donc le compteur DX va prendre les (N - i) valeurs suivantes : DX = N-i, N-i-1, N-i-2, ... 2, 1 Ce qui donne : DX = CX, CX-1, CX-2, ... 2, 1 Par exemple, pour un tableau de longueur N = 5, et pour le premier passage et le deuxième passage (i = 1) on aura : CX = 3 CX = 4 DX = 4 3 2 1 DX = 3 2 (SI+1) finale 1 (SI+1) finale 9 Le programme en langage assembleur 8086 : ;tri3 CODE START : SEGMENT ASSUME ORG JMP CS:CODE, DS:CODE ES:CODE 0100H N EQU 100H BEGIN ; la procédure sera placée ici BEGIN : MOV AX, CODE MOV DS, AX MOV ES, AX MOV CX, N-1 Etq3 : MOV SI, 200h MOV DX, CX MOV BL, 0 Etq2 : MOV AL, [SI] CMP AL, [SI+1] JLE Etq1 XCHG AL, [SI+1] MOV [SI], AL INC BL Etq1 : INC SI DEC DX JNZ Etq2 CMP BL, 0 JZ Fin DEC CX JNZ Etq3 Fin : BRK CODE ENDS END START 10 Une troisième solution : (utilisation d’un sous-programme appelé ‘FINDMAX’) Début CX <-- N-1 FINDMAX NON OUI BL = 0 ? CX <-- CX - 1 NON OUI Z = 1 ? Fin 11 Le sous-programme : SI <-- 200h DX <-- CX BL <-- 0 AL <-- [SI] NON OUI AL ≤ [SI+1] ? XCHG AL,[SI+1] [SI] <-- AL BL <-- BL+1 SI <-- SI + 1 DX <-- DX - 1 OUI NON Z = 1 ? RET 12 Le programme en langage assembleur 8086 : programme ;tri3 CODE START : sous-programme FINDMAX SEGMENT ASSUME ORG CS:CODE, DS:CODE ES:CODE 0100H N EQU 100H BEGIN JMP Etq2: ; la procédure sera placée ici MOV AX, CODE MOV DS, AX MOV ES, AX BEGIN : Etq1 : MOV CX, N-1 CALL FINDMAX CMP BL, 0 JZ Fin DEC CX LOOP Etq3 Etq3 : Fin : CODE FINDMAX PROC PUSH CX MOV SI, 200h MOV DX, CX MOV BL, 0 MOV AL, [SI] CMP AL, [SI+1] JLE Etq1 XCHG AL, [SI+1] MOV [SI], AL INC BL INC SI DEC DX JNZ Etq2 POP CX RET ENDP BRK ENDS END START Remarques : Le compteur CX est utilisé par le programme principal, mais il n’est pas nécessaire de l’empiler avant l’exécution de la procédure du sous-programme, car cette dernière ne modifie pas le contenu de CX. Il est possible aussi de faire l’empilement de CX dans le programme principal juste avant le CALL et de faire son désempilement dans le programme principal aussi juste après le CALL. Le registre BL ne peut pas être empilé et désempilé par le programme principal, car la valeur retournée par le sous-programme ne doit pas être perdue avant son utilisation dans l’instruction (CMP BL, 0) qui vient après le sous programme. On rappelle que pour un programme dont l’ensemble des segments ne dépasse pas les 64 Ko, alors, le programme est organisé selon le canevas suivant : ; nom du programme CODE SEGMENT ASSUME CS:CODE, DS:CODE ES:CODE, SS:CODE ORG 0100H placer toutes les ‘EQU’ ici START : JMP BEGIN placer tous les ‘define’ ici placer toutes les procédures ici placer votre programme ici BEGIN : CODE ENDS END START 13 Exercice 4 : Ecrire un programme qui puisse calculer le PGDC (plus grand diviseur commun) de deux nombres se trouvant aux adresses [200h] et [201h] ; le résultat sera placé à l’adresse [202h]. On rappelle que : * PGDC [n , m] = PGDC [m , reste(n/m)] , n > m * PGDC [n , 0] = n , quelque soit n Solution : Cette solution utilise une procédure récursive (qui fait appel à elle-même) : programme ;pgdcom CODE START : sous-programme PGDC SEGMENT ASSUME ORG JMP CS:CODE, DS:CODE ES:CODE 0100H BEGIN PUSH AX PUXH BX DIV BL CMP AH, 00H JZ FIN MOV AL, BL MOV BL, AH CBW CALL PGDC ; la procédure sera placée ici BEGIN : CODE PROC MOV AL, [200] MOV BL, [201] CBW ; forcer AH = 0 CALL PGDC MOV [202], AL BRK ENDS END START FIN : POP BX POP AX RET PGDC ENDP Remarque : Les registres AH, AL, BH, BL sont employés par le programme principal et par la procédure, donc on doit les empiler avant de les utiliser par la procédure, puis les désempiler après finir leur utilisation avec la procédure (PUSH et POP ne fonctionnent que sur des registres 16 bits). 14 Exercice 5 : Ecrire un programme qui puisse calculer à un dixième près la moyenne arithmétique de N = 100 valeurs se trouvant dans un tableau. Solution : ;moy CODE SEGMENT ASSUME ORG CS:CODE, DS:CODE ES:CODE 0100H N EQU 100D BEGIN START : JMP BEGIN : MOV AX, CODE MOV DS, AX MOV ES, AX Boucle : MOV SI, 200 MOV CL, N MOV BX, N MOV AX, 0000H ADD AX, [SI] INC SI LOOP Boucle CWD ; Forcer DX = 0 DIV BX XCHG AX, BX MOV [0400H], 0AH ; 0A Hexa = 10 Déci MUL [0100H] DIV BL Fin : BRK CODE ENDS END START 15 Exercice 6 : Ecrire un programme qui indique la présence de la chaîne de caractères ‘TEC568’ qui débute à l’adresse [300h], dans un tableau de N = 96 éléments qui débute à l’adresse [200h], (utiliser deux procédures ‘AFICH_OK’ et ‘AFFICH_NK’ pour afficher le résultat). Solution : Début SI <-- 200h CX <-- N-5 DI <-- 300h BL <-- 6 CLD CMPSB NON OUI Z = 1 ? OUI NON DEC BL BL = 5 ? NON OUI Z = 1 ? DEC SI DEC CX NON Z = 1 ? AFFICH_OK OUI AFFICH_NK Fin 16 La longueur de la chaîne ‘TEC586’ est N’ = 6, la première lettre ‘T’ est donc cherchée parmi les (N - N’ -1) premières valeurs ; et le compteur CX prend les valeurs suivantes (sa dernière valeur est toujours égales à 1) : CX = N - (N’ - 1), N - (N’ - 1) - 1, ... 2, 1 Par exemple, si N = 15, on aura : 1 CX = 10 2 3 9 4 8 7 5 6 6 5 7 4 8 3 9 2 10 11 12 T E C 13 14 5 8 15 6 1 Le programme : ;moy CODE SEGMENT ASSUME ORG CS:CODE, DS:CODE ES:CODE 0100H N EQU 96D BEGIN START : JMP BEGIN : MOV AX, CODE MOV DS, AX MOV ES, AX Etq1 : Etq2 : Etq3 Etq4 MOV SI, 0200H MOV CX, N-5 MOV DI, 0300H MOV BL, 6 CLD CMPSB JNZ Etq3 DEC BL JNZ Etq2 CALL AFFICH_OK JMP FIN CMP BL, 5 JZ Etq4 DEC SI LOOP Etq1 CALL AFFICH_NK Fin : INT 3 CODE ENDS END START Rev 1.06 (25 - 01 - 2009) - http://www.electro.bbactif.com/ - Code is Poetry 17
Documents pareils
Cours 8 : Mémoire et Registres
Q8.3 : Pourquoi faut-il 3 bits pour désigner le registre source ou destination d’une
opération dans le 8086?
Q8.4 : Supposons que DS = 1111h; SS = 2222h; CS = 3333h; BP = 4444h; BX = 5555h; SI
= 77...