Académique Documents
Professionnel Documents
Culture Documents
OMOR
Introduction
Problématique : Comment représenter les chiffres ?
Représentation du système romain :
I , II , III , IIII, IV ,.......IX....
Représentation du système Arabe :
1, 2, 3, 4, 5, 6.........10.....
Représentation du système
persane : persanne
Remarque:
Plus la base est grande, moins il faut de symboles pour représenter le même nombre.
Le système Hexadécimal offre une écriture plus condensée ( compact ) des nombres
élevés.
Conversion Inter- base
Fondamental:Conversion décimal vers Binaire
Il s'agit d'une répétition de divisions par2 jusqu'à obtention d'un quotient NUL.
Les coefficients ( à déterminer ) correspondent aux restes des différentes divisions.
Complément:
Il s'agit de composer le nombre décimal en question sous forme d'une somme de
puissance entières de 2.
Si le terme 2 à la puissance k est présent, on inscrit un 1 vis à vis de sa position.
sinon, si le terme est absent On inscrit un 0.
Fondamental:Conversion décimal vers Octal
C'est le même principe qu'avant sauf au lieu de diviser par 2, on divise par 8.
Fondamental:Conversion Décimale vers Hexadécimale
Même principe sauf qu'au lieu de diviser par 2, on divise par 16.
Fondamental:Conversion binaire vers Octale
Il suffit de grouper les bits par blocs de 3 bits en allant vers la gauche, et de faire
correspondre à chaque bloc son équivalent décimale.
Exemple :
Exercice 2
Convertir en Octale :
63, 100, 56, 24, 85, 111.
Exercice 3
Convertir en Hexadécimale:
103, 254, 97, 75, 23, 300, 163
Représentation des nombres sur n
chiffres
Définition:
Sur 4 chiffres dans la base b = 10. le plus grand nombre est Nbr = 9999
Exemple:Représentation du nombre 4
4 : 00000100
-4 : 10000100
Remarque:
Sur n bits, les nombres qu'on peut représenter appartiennent à l'intervalle :
La différence qui existe entre cette valeur maximale et 453 s'appelle lecomplément
restreint.
Exemple:
Par exemple : pour obtenir -5
0101: codage de 5 en binaire
1010: codage en complément restreint de 5
→ On ajoute un 1
1011: codage en cmplément vrai -
Remarque:
Ce codage a l'avantage de ne pas nécessiter de différenciation spéciale des nombres
positifs et négatifs, et évite en particulier le problème d'ordinateurs anciens (Control
DATA 6600) qui avaient un +0 et -0 dont il fallait faire comprendre aux circuits de tests
que c'etait le même nombre !
Exemple:
Addition binaire
Calculons : 1010 + 0011
-
Soustraction binaire
Pour bien réussir une soustracton binaire, il y a une méthode, c'est d'essayer
d'additionner le résultat avec le nombe soustrait, pour vérifier que ca donne le nombre
principal.
Exemple:
-
Le débordement correspond à une retenue sortante à 1
Méthode:Détection du débordement
Comparer le signe des opérandes et le signe du résultat :
S'ils sont différents, il y a débordement
S'il y a retenue sur le bit de poid fort alors il ya débordement.
Multiplication binaire
La multiplication consiste à faire une suite d'additions avec le multiplicande décalé vers
la gauche. Cette opération est répétée autant de fois qu'il y a d'éléments binaires dans
le multiplicateur.
Division binaire
La division binaire s'effectue à l'aide de soustractions et de décalages, comme la
division décimale, sauf que les digits du quotient ne peuvent être que 1 ou 0. Le bit du
quotient est 1 si on peut soustraire le diviseur, sinon il est 0.
Exemple:Division normal et soustraction successives
Calculons 15 / 3
Représentation des nombres fractionnaires en
virgule fixe
Rappel:Nombre réel
un nombre réel se compose de deux parties distinctes: une partie entière, située à
gauche de la virgule, et, éventuellement, une partie décimale, située après celle-ci.
Règle de représentation
Pour ce qui est de la partie entière, nous savons désormais parfaitement la coder. Mais
qu'en est - il de de la partie décimale ?
Et bien il nous suffit de reprendre le principe de la numération positionnelle, en
considérant chaque bit situé après la virgule comme associé cette fois à des puissances
négative de deux, tout comme nous le faisons pour la base 10.
Ainsi nous savons que:
5.022,78 = 5 x 1.000 + 0 x 100 + 2 x 10+ 2 x 1 + 7 x 0,1 + 8 x 0,01 ...ce qui
revient à écrire:
v_fixe1
Exemple:
Soit un nombre binaire : 1 1 0 1,0 1 1 0 1
-
Remarque:
On voit immédiatement que, contrairement à la partie entière, la partie fractionnaire
peut s'exprimer par une suite non finie, ce qui impose de définir un critère d'arrêt. Ce
critère est la précision qui doit être équivalente dans les deux bases.
Méthode:Déterminer le rang de développement des puissances de 2
La précision décimale de 3,14 est 5.e-3
Vérification :
Partie fractionnaire
00100011 = 0,125 + 0,0078125 + 0,00390625
00100011 = 0,13671875
La précision attendue est bien obtenue (n=8 chiffres)
Chapitre 2 - Les systèmes de
codage
Introduction
Le codage DCB
Codage de Gray
Systèmes de codage tenant compte des erreurs
Exercices
Attention:Probléme
Quand le résultat est supérieur à 9 et représentable sur 4 bits. La représentation
binaire de ce résultat ne correspond à aucun code en DCB.
Remarque:
Dans l'exemple précèdent 8 + 2 = 10 ne correspond à aucune représentation en DCB.
La représentation de 10 en DCB est : 0001 0000
Solution
On procéde comme suit:
Complément:Travail à faire
Comment ferons-nous pour les autres opérations arithmétiques ?
Codage de Gray
Contrôle de parité
C'est le code le plus simple de type autovérificateur.
Principe: consiste à ajouter un bit de parité à la fin de l'info et qui prend une valeur ( 0
ou 1 ) de façon à ce que le nombre de 1 dans l'info soit PAIR.
Ce code est utilisé quand le taux d'erreur est trop faible.
Exemple:
Problème: ce code est autovérificateur quand le nombre d'erreurs est impairs. Par
contre l'erreuren'est pas detéctée s'elle est commise sur un nombrePAIR de bits.
Codage de HAMMING
Utilisé dans une information sous forme vectorielle. Il est fondé sur plusieurs tests de
parité à des positions bien déterminés dans l'information pour m bits de l'information,
on rajoute k bits de parité. L'information à transmettre est composée de n bits avec n =
m + k.
Le nombre k est choisi de façon à ce que:
À la réception du message, on calcul toutes les parités. Pour chaque bit on compare la
valeur calculée et la valeur reçue, s'elles sont identiques, on lui assigne la valeur 0,
sinon on lui assigne la valeur 1.
Le nombre binaire ainsi généré indique la position de l'erreur.
Exemple:
Information initiale : 1 1 0 0 1 0 0 1 (8 bits)
À partir de la formule :
On trouve k = 4
Le message est donc constitué de 12 bits.
Suite de l'exemple
Pour k2 (22) = (0 1 0 0)
Le 1 en 3éme position !
À la réception
L'information reçue est :
Introduction
Lorsqu'un utilisateur est devant son poste de travail micro-informatique, il est loin de se
douter qu'il est devant une machine dont le fonctionnement est régi par des principes
décrits par le mathématiciens John von Neumann dans les années quarante.
Avant de détailler les sous ensembles d'entrée-sortie (E/S) d'un micro-ordinateur, il est
donc nécessaire de plonger dans l'histoire et de revenir sur un concept qui gouverne
encore le fonctionnement des ordinateurs malgré tous les progrès réalisés depuis. Ainsi
dans un premier chapitre vous allez découvrir l'architecture dite de von Neumann.
Dans cette deuxième partie du cours, le terme UC pour "Unité Centrale" ou CPU pour
"Central Processing Unit" est pris au sens originel, c'est à dire l'unité qui réalise les
calculs et non le micro-ordinateur lui-même. aujourd'hui il qualifie le plus souvent le
microprocesseur.
Chapitre 1 : L'approche von
Neumann
Principe du modèle von Neumann
Architecture et modèle de calcul
Architecture et modèle de calcul
Architecture et modèle de calcul
Le modèle de calcul de von Neumann
L'entité de base du modèle de calcul est la donnée implémentée sous la forme d'une
variable dans les langages informatiques. Le modèle de description d'un problème est
de type procédural, une séquence d'instructions s'exécutant sur un flux entrant de
données et donnant un flux sortant de données résultat. Le modèle d'exécution repose
sur une sémantique de transition d'états. Il est piloté par une séquence d'instructions
ordonnées et exécutées séquentiellement.
Lorsque l'UC veut communiquer avec la mémoire ou les unités d'échanges d'E/S, elle le
fait via une enveloppe libellée avec une adresse et contenant une information
(instruction ou donnée).
Remarque:
Cette structure est de type maître-esclave. L'UC est toujours le maître des échanges. La
mémoire et les unités d'échanges d'entrée-sortie sont des entités passives, donc
esclaves.
Dans d'autres configurations, comme un système multiprocesseur ou un système dont
les échanges se font par accès direct à la mémoire, il se peut que le contrôle des
échanges soit partagé entre plusieurs maîtres.
Processeur
De manière général le processeur, (ou CPU, Central Processing Unit, « Unité centrale de
traitement ») est le composant essentiel d'un ordinateur qui interprète les instructions
et traite les données d'un programme.
pour fonctionner, le processeur est cadencé au rythme d'une horloge interne, grâce à
un cristal de quartz qui, soumis à un courant électrique, envoie des impulsions,
appelées « top ». La fréquence d'horloge (appelée également cycle, correspondant au
nombre d'impulsions par seconde, s'exprime en Hertz (Hz)).
A chaque top d'horloge le processeur exécute une action, correspondant à
une instruction ou une partie d'instruction.
Définition:
Une instruction est l'opération élémentaire que le processeur peut accomplir. Les
instructions sont stockées dans la mémoire principale, en vue d'être traitée par le
processeur. Une instruction est composée de deux champs :
Le code opération : représentant l'action que le processeur doit accomplir.
Le code opérande : définissant les paramètres de l'action. Le code opérande dépend
de l'opération. Il peut s'agir d'une donnée ou bien d'une adresse mémoire.
L'UC se compose d'une unité de traitement (UT), d'une unité de contrôle ou de
commande (UCo) et de registres.
Unité centrale
Unité de traitement
Exemple:
Les bus 1 et 2 ,représentés successivement en bleu et rouge dans la figure "Unité de
traitement", font partie du système de communication interne de l'UC.
Intéressons-nous maintenant à ce petit composant nommé "UAL", de quoi s'agit-il ?
Définition:
L'unité arithmétique et logique (notée UAL ou en anglais ALU pour Arithmetical and
Logical Unit). L'UAL assure les fonctions basiques de calcul arithmétique et les
opérations logiques (ET, OU, Ou exclusif, etc.).
Donc l'UAL est un composant chargé des :
Opérations arithmétiques : ADD(+), SUB(-), MUL(*), DIV( : ), INC(+1), DEC(-
1)
Opérations logiques : ( AND, OR, XOR, NOT, CMP ) et pour les décalages
(LSL, LSR, ASR, ASL)
Le cycle d'exécution
L'UC va chercher en mémoire le code de l'instruction, avec éventuellement, un
opérande. Après décodage, elle va chercher en mémoire, le cas échéant, d'autres
opérandes nécessaires au calcul. Elle exécute ensuite l'instruction sur cette ou ces
données. Le résultat est ensuite stocké dans un registre interne ou en mémoire
centrale.
Le chemin de donnée est l'ensemble des éléments participant au transfert et au
traitement des données. Il comprend donc l'UT, les registres concernés dont
l'accumulateur, et le bus de donnée.
Flots des instructions et des données
Cycle d'exécution
Inconvénient
Un inconvénient majeur de cette architecture est la centralisation des échanges de
données. L'unité centrale est un goulot d'étranglement, source de ralentissement des
communication. Un échange entre la mémoire et l'unité d'échange d'E/S se fait
obligatoirement par intermédiaire du microprocesseur qui exécute le transfert.
Des solutions à ce problème ont été proposées comme d'autres architectures, celle de
Harvard par exemple, avec la séparation des données et des instructions, ou des
améliorations comme l'ADM.
Unité de commande
L'unité de commande est l'ensemble des dispositifs coordonnant le fonctionnement de
l'ordinateur afin de lui faire exécuter la suite d'opérations spécifiées dans les instructions
du programme.
Les principaux dispositifs de l'unité de commande qui entrent en jeu lors de la
recherche en mémoire et du décodage d'une instruction (cycle de recherche) sont :
Le compteur ordinal (CO), qui est un registre contenant l'adresse en mémoire
où est stockée l'instruction à chercher.
Le registre d'instruction (RI), qui reçoit l'instruction qui doit être exécutée.
Le décodeur de code opération, qui détermine quelle opération doit être
effectuée, parmi toutes les opérations possibles.
Le séquenceur qui, génère les signaux de commande.
L'horloge, qui émet des impulsions électroniques régulières, synchronisant ainsi
toutes les actions de l'unité centrale.
La circulation des informations pendant un cycle de recherche (fetch cycle) est illustrée
dans la figure suivante :
Cycle d'exécution
Recherche de l'instruction
Phase 2 : Décodage de l'instruction et recherche de l'opérande
Le registre d'instruction contient maintenant le premier mot de l'instruction qui peut
être codée sur plusieurs mots. Ce mot contient le code opération qui définit la nature de
l'opération à effectuer (addition,soustraction,...) et le nombre d'opérandes.
1. L'unité de commande transforme l'instruction en une suite de commandes
élémentaires nécessaires au traitement de l'instruction.
2. Si l'instruction nécessite une donnée en provenance de la mémoire, l'unité de
commande récupère sa valeur sur le bus de données.
3. L''opérande est stockée dans un registre.
Une mémoire
Une mémoire idéale serait une mémoire de grande capacité, capable de stocker un
maximum d'informations avec un temps d'accès très faible.
Quand on s'éloigne de l'UC vers les mémoires auxilliaires, on constate que le temps
d'accès et la capacité des mémoires augmentent, mais le coût par bit diminue. En
général les mémoires de grande capacité sont souvent très lente et les mémoire rapides
sont très chères. Et pourtant, la vitesse d'accès à la mémoire conditionne dans une
large mesure les performances d'un système. En effet, c'est là que se trouve le goulot
d'étranglement entre un microprocesseur capable de traiter des informations très
rapidement et une mémoire beaucoup plus lente.
Les éléments de mémoire situés dans l'unité centrale de traitement sont :
Les registres qui sont caractérisées par une grande vitesse et servent
principalement au stockage des opérandes et des résultats intermédiaires.
La mémoire cache ou l'antémémoire est une mémoire rapide de faible capacité
utilisée comme mémoire tampon entre l'UC et la mémoire centrale. Cette mémoire
permet au CPU de faire moins d'accès à la mémoire centrale et ainsi de gagner du
temps.
La mémoire centrale ou principale est l'organe principal de rangement des
informations utilisées par l'UC. Pour exécuter un programme, il faut le charger
(instructions + données) en mémoire centrale. Cette mémoire est une mémoire à
semi-conducteurs, mais son temps d'accès est beaucoup plus grand que celui des
registres et du cache.
La mémoire d'appui sert de mémoire intermédiaire entre la mémoire centrale et
les mémoires auxiliaires. Elle est présente dans les ordinateurs les plus évolués et
permet d'augmenter la vitesse d'échange des informations entre ces deux niveaux.
La mémoire de masse est une mémoire périphérique de grande capacité et de
coût relativement faible utilisée pour le stockage permanent des informations. Elle
est utilisée pour le stockage, la sauvegarde ou l'archivage à long terme des
informations.
Fondamental:Organisation des informations
Les informations que l'on désire traiter dans un ordinateur doivent s'adapter à un
certain format, dont les caractéristiques générales sont les suivantes :
Le bit (BInary Digit) constitue l'unité de base de l'information. Dans une mémoire,
le plus petit élément de stockage est souvent appelé point mémoire, il mémorise
un bit d'information.
L'octet, plus connu sous le terme anglais byte, correspond à un groupement de 8
bits.
Le caractère est un groupement de 6,7,8... bits permettant le codage d'un
caractère alphanumérique ou d'un caractère spécial.
Le mot (word) est un groupement de bits constituant une unité d'information
adressable en unité centrale.
Mémoire centrale
La mémoire centrale ou principale contient les instructions et les données des
programmes que l'on désire exécuter, ainsi qu'une partie du système d'exploitation
nécessaire au bon fonctionnement de l'ordinateur. Tout programme que l'on veut
exécuter doit d'abord être chargé en mémoire centrale. Ensuite en y cherche les
instructions les unes après les autres pour les exécuter séquentiellement dans l'UC. La
capacité et la vitesse d'accès à la mémoire centrale sont des éléments déterminants
dans la puissance d'un ordinateur.
La mémoire centrale peut être représentée comme une armoire de rangement
constituée de différents tiroirs. Chaque tiroir représente alors une case mémoire qui
peut contenir un seul élément : des données. Le nombre de cases mémoires pouvant
être très élevé, il est alors nécessaire de pouvoir les identifier par un numéro. Ce
numéro est appelé adresse. Chaque donnée devient alors accessible grâce à son
adresse.
Organisation de la mémoire
Avec une adresse de n bits il est possible de référencer au plus 2n cases mémoire.
Chaque case est remplie par un mot de données (sa longueur m est toujours une
puissance de 2). Le nombre de fils d'adresses d'un boîtier mémoire définit donc le
nombre de cases mémoire que comprend le boîtier. Le nombre de fils de données
définit la taille des données que l'on peut sauvegarder dans chaque case mémoire.
En plus du bus d'adresses et du bus de données, un boîtier mémoire comprend une
entrée de commande qui permet de définir le type d'action que l'on effectue avec la
mémoire (lecture/écriture) et une entrée de sélection qui permet de mettre les
entrées/sorties du boîtier en haute impédance.
On peut donc schématiser un circuit mémoire par la figure suivante où l'on peut
distinguer :
Circuit mémoire
Bus de communication
Un bus peut être unidirectionnel (communication simplex) d'un émetteur vers un ou
plusieurs récepteurs, ou de plusieurs émetteurs vers un récepteur (bus convergent).
Plusieurs maîtres posent un problème de contention lors d'une demande multiple
d'accès au système de communication. Le bus peut aussi être bidirectionnel avec
communication simultanée (duplex intégral ou full duplex) ou alternée (semi-duplex ou
half duplex). Lors d'un échange entre deux entités de plusieurs types d'information, par
exemple une adresse et une donnée, le transfert peut utiliser des médias séparés ou
empreinter la même voie. La première approche est plus intéressante en terme de débit
mais il faut des bus séparés, un par type d'information.
La solution du bus multiplexé permet à plusieurs types d'information de circuler sur un
même bus mais à des instants différents. La communication peut être synchrone ou
asynchrone selon qu'un signal d'horloge est transmit explicitement ou non. Lorsqu'un
maître accède à un esclave, il précise le type d'accès : lecture ou écriture d'un mot,
écriture ou lecture d'un bloc...
Comme plusieurs entités communiquent sur un même bus, il est nécessaire de disposer
d'une logique spécialisée de gestion des accès et des échanges entre l'entité et le bus.
Fondamental:Le buffer
La connexion et la déconnexion de l'entité sur les bus se font à l'aide
d'un buffer ou tampon électronique qui appartient aussi à ce sous ensemble qui
permet de partager un bus.
Buffer de communication
Remarque:
Pour échanger les informations, il est nécessaire de définir un protocole de
communication qui va gérer l'échange.
Un protocole est un ensemble de conditions et d'opérations dont l'ordre strict doit
être respecté. Les conditions à respecter sont la définition des signaux matériels et des
contraintes temporelles. Les opérations sont l'activation ou non de signaux d'état, de
contrôle et de donnée.
Echange synchrone
Dès que la donnée est délivrée à la mémoire, il peut exister un temps appelé Latence.
Le transfert synchrone facilite la conception et garantit les temps d'échange. La
tendance actuelle va vers le transfert asynchrone pour sa consommation électrique
moindre, critère important pour les systèmes nomade et sa plus grande flexibilité.
Lecture asynchrone
L'arbitrage d'accès
Lorsque plusieurs maîtres demandent le bus, il est nécessaire de réaliser un arbitrage
d'accès. L'arbitrage consiste à sélectionner un maître parmi n pour l'autoriser à prendre
le bus (accord ou grant). Une fois l'échange terminé, l'entité peut relâcher le bus.
Plusieurs techniques existent de type centralisé ou réparti. La demande et la résolution
peuvent être série ou parallèle. Plusieurs politiques d'arbitrage existent, comme la
priorité fixe, tournante, la première demandée - la première servie.
Dans une approche centralisée, les demandes d'accès aux bus se font de manière
asynchrone. Il faut distinguer alors, dans le contrôleur du bus, l'arbitre de bus qui reçoit
les demandes et, en fonction de la politique d'accès, détermine quelle entité peut
accéder au bus.
Dans la figure suivante, chaque nœud génère sa demande de bus BReq (Bus Request)
et reçoit son autorisation BPRI (Bus Priority In). Un encodeur de priorité détermine alors
le numéro de ligne qui sera servie selon une politique donnée.
L'arbitrage centralisé
La" daisy-chain " est une technique d'arbitrage répartie série. Répartie car chaque
noeud possède son arbitre.
Dans la figure suivante, la demande et la résolution se font en série. L'autorisation
rentre dans chaque noeud par BPRI (Bus Priority In) et ressort si l'unité est d'accord par
BPRO (Bus Priority Out).
L'arbitrage série
Conseil:
La solution centralisée a le mérite d'être simple mais les politiques réparties sont plus
tolérantes aux fautes matérielles sauf, bien évidement, pour l'approche daisy-chain.
Remarque:
La demande d'accès aux bus pour un échange E/S peut se faire comme expliqué
précédemment ou par interruption avec intervention de l'UC.
dans une architecture actuelle à plusieurs maîtres, la ressource critique n'est plus
uniquement le bus de communication, c'est aussi la mémoire. Il est nécessaire de
réaliser un arbitrage au niveau même de l'entité esclave pour des problèmes de
cohérence de données.
Introduction
Tous les langages de programmation modernes sont
des héritiers plus ou moins directs de ce langage
élémentaire qu'est l'assembleur. Mais à l'heure où la
programmation objet fait fureur dans le milieu des
développeurs de logiciels, on peut se demander à
juste titre à quoi peuvent servir des connaissances et
des compétences dans un langage de programmation
aussi ancestral et aussi primitif.
La seule qualité que l'on peut trouver au langage
assembleur c'est d'être celui qui est le plus proche du
langage machine. En effet, quelque soit le langage
d'origine c'est un programme en langage machine qui
sera exécuté en définitive par le microprocesseur.
Connaître la programmation en assembleur peut donc
donner des atouts considérables pour la
compréhension et la maîtrise de tous les autres
langages de programmation.
Chapitre 1 : Premiers pas..
Pourquoi l'assembleur ?
Écriture et exécution d'un programme
Architecture du Intel X86
Pourquoi l'assembleur ?
Lorsque l'on doit lire ou écrire un programme en
langage machine, il est difficile d'utiliser la
notation hexadécimale .
On écrit les programmes à l'aide de symboles
comme MOV, ADD, etc.
Les concepteurs de processeur, comme Intel,
fournissent toujours une documentation avec les
codes des instructions de leur processeur, et les
symboles correspondant.
Écriture et exécution d'un
programme
L'assembleur est un utilitaire qui n'est pas interactif,
contrairement à l'utilitaire debugqui fera l'objet du
premier TP. Le programme que l'on désire traduire
en langage machine (on dit assembler) doit être
placé dans un fichier texte (avec
l'extension.ASM sous DOS).
La saisie du programme source au clavier nécessite
un programme appelé éditeur de texte.
L'opération d'assemblage traduit chaque instruction
du programme source en une instruction machine. Le
résultat de l'assemblage est enregistré dans un fichier
avec l'extension .OBJ (fichier objet ).
Le fichier .OBJ n'est pas directement exécutable. En
effet, il arrive fréquemment que l'on construise un
programme exécutable à partir de plusieurs fichiers
sources. Il faut "relier'' les fichiers objets à l'aide
d'un utilitaire nommé éditeur de lien.
L'éditeur de liens fabrique un fichier exécutable , avec
l'extension .EXE. Ce dernier est directement
exécutable grâce Un utilitaire spécial du système
d'exploitation.
Étape de compilation d'un programme assembleur
Structure d'un programme ASM
Comme tout programme, un programme écrit en
assembleur comprend des définitions
de données et des instructions, qui s'écrivent
chacune sur une ligne de texte.
Les données sont déclarées par des directives,
mots clef spéciaux que comprend l'assembleur.
Les directives qui déclarent des données sont
regroupées dans le segment de données, qui
est délimité par les
directives SEGMENT et ENDS.
Les instructions sont placées dans un autre
segment, le segment de code.
La directive ASSUME est toujours présente et
sera expliquée plus loin (section ).
La première instruction du programme (dans le
segment d'instruction) doit toujours être repérée
par une étiquette. Le fichier doit se terminer
par la directive END avec le nom de
l'étiquette de la première instruction (ceci
permet d'indiquer à l'éditeur de liens quelle est la
première instruction à exécuter lorsque l'on lance
le programme).
Les points-virgules indiquent des commentaires.
Déclaration des variables simples
On déclare les variables à l'aide dedirectives.
L'assembleur attribue a chaque variable
une adresse. Dans le programme, on repère les
variables grâce à leur nom.
Les noms des variables (comme les étiquettes ) sont
composés d'une suite de 31 caractères au maximum,
commençant obligatoirement par une lettre. Le nom
peut comporter des majuscules, des minuscules, des
chiffres, plus les caractères @, ? et _.
Les variables se déclarent de la manière suivante:
variable1 db ? ; variable1 est un byte non initialisé
une_autreVARIABLE2 db 0FFh ;
une_autreVARIABLE2 est un byte initialisé à FF (255
en hexadécimal)
My_Var dw ? ; My_Var est un word (16 bits) non
initialisé
Remarque:
De manière générale:
DB : 1 byte (8 bits) (Declare Byte)
DW : 1 word (16 bits) (Declare Word)
DD : 2 words (32 bits) (Declare Double)
DF,DP : 6 bytes
DQ : 8 bytes (64 bits)
DT : 10 bytes
Les constantes peuvent être écrites en:
- décimal: 1, 2, 3, 123, 45
- hexadécimal : 1h,2h,3h,12h,0Fh,0AD4h (noter la
présence du 0 quand le le premier chiffre du nombre
en hexadécimal commence par une lettre)
- binaire : 1b,0b,1010b,111101b
Exemple:
Les directives DB (Define Byte) et DW (Define Word)
permettent de déclarer des variables de
respectivement 1 ou 2 octets.
data SEGMENT
entree DW 15 ; 2 octets initialises a 15
sortie DW ? ; 2 octets non initialises
cle DB ? ; 1 octet non initialise
nega DB -1 ; 1 octet initialise a -1
data ENDS
Les valeurs initiales peuvent être données en
hexadécimal (constante terminée par H) ou en
binaire (terminée par b) :
data SEGMENT
truc DW 0F0AH ; en hexa
masque DB 01110000b ; en binaire
data ENDS
Méthode:
Les variables s'utilisent dans le programme en les
désignant par leur nom. Après la déclaration
précédente, on peut écrire par exemple :
MOV AX, truc
AND AL, masque
MOV truc, AX
L'assembleur se charge de remplacer les noms de
variable par les adresses correspondantes.
Les tableaux
Il est possible de déclarer des tableaux , c'est à dire
des suite d'octets ou de mots consécutifs.
Pour cela, utiliser plusieurs valeurs initiales :
data SEGMENT
machin db 10, 0FH ; 2 fois 1 octet
chose db -2, 'ALORS'
data ENDS
Remarque:
la déclaration de la variable chose : un octet à -2
(=FEH), suivi d'une suite de caractères.
L'assembleur n'impose aucune convention pour la
représentation des chaînes de caractères : c'est à
l'utilisateur d'ajouter si nécessaire un octet nul pour
marquer la fin de la chaîne.
Après chargement de ce programme, la mémoire
aura le contenu suivant :
Exemple:
Si on veut écrire un caractère Z à la place du O de
ALORS, on pourra écrire :
MOV AL, 'Z'
MOV chose+1, AL
Notons que chose+1 est une constante (valeur
connue au moment de l'assemblage) : l'instruction
générée par l'assembleur pour
MOV chose+1, AL est :
MOV [adr] , AL ----------> ( [adr] est une adresse
mémoire, le point suivant traite des différents modes
d'adressage)
Méthode:
Une autre méthode pour déclarer un tableau consiste
à utiliser la directiveDUP qui nous permet de déclarer
un tableau de n cases, toutes initialisées à la même
valeur.
tab DB 100 dup (15) ; 100 octets valant 15
zzz DW 10 dup (?) ; 10 mots de 16 bits non
initialises
Adressage immédiat
On appelle « adressage immédiat » l'adressage qui ne fait intervenir que des
constantes.
Exemple :
mov AX, 568
Exemple:Adressage direct ou immédiat
Considérons cette partie de programme qui stocke le nombre 14 dans une variable
appelée TOTO, lui ajoute 20puis charge le résultat dans AX.
Adressage immédiat
Remarque:
L'instruction mov byte ptr ds:[TOTO], 14 charge le nombre 14 dans l'octet de la RAM
adressé par DS et l'offset de “TOTO”.
La ligne suivante ajoute 20 au contenu de cet octet.
L'expression “byte ptr” devant l'adresse, obligatoire ici, indique la taille de la
variable dans laquelle doit être stocké le nombre 14
Si on avait mis “word ptr”, ce nombre aurait été codé sur 16 bits au lieu de 8 bits :
on aurait donc écrasé le prochain octet qui suit la variable.
Attention:
Que se passe-t-il si le programmeur n'écrit pas le registre de segment dans l'adresse ?
Fondamental:
C'est là qu'intervient la directive “assume”. Le compilateur va trouver lui-même quel
registre l'utilisateur a voulu sous-entendre.
Si on a utilisé le nom de la variable, alors le segment sera celui dans lequel est déclaré
cette variable.
Mais le compilateur veut un REGISTRE de segment. Il va donc prendre celui qui est
censé pointer vers le bon segment et pour le savoir, il examine la directive assume.
Voilà pourquoi cette dernière peut nous épargner d'écrire pour chaque variable
l'expression “ds:”.
Adressage indexé et adressage basée
il est possible d'utiliser des registres de base ou d'index pour adresser un octet.
On appelle « base » les registres BX et BPet « index » les registres SI et DI.
Conseil:
BX, BP, DI et SI peuvent tous être utilisés comme des registres généraux.
Récapitulons
.
.
Remarque:
Si la constante n'est pas un label, il est parfois impératif de spécifier le registre de
segment ! Tout dépend du contexte...
Remarque:
L'instruction Offset retourne l'adresse mémoire de la variable qui la suit.
c'est très utile lorsqu'on veut parcourir une plage mémoire. (Nous verrons
unexemple plus loin dans ce chapitre)
Les opérations arithmétiques
Quelques opérations arithmétiques de base
Attention:
Comment Faire pour la multiplicationet la division ?
Les opérations logiques
Attention:
Comment faire pour initialiser un registre à 0 ? (juste en utilisant des opérations
logiques)
Branchement inconditionnel
Les sauts inconditionnels
Contrôler le flux du programme est une chose très importante, c'est là que votre
programme peut prendre des décisions en fonction de certaines conditions.
L'instruction de base qui transfère le contrôle d'un point vers un autre point du
programme est JMP.
La syntaxe de base de l'instruction JMP:
JMP label
Pour déclarer une étiquette dans votre programme, il suffit de taper son nom et
ajouter ":" à la fin, l'étiquette peut être n'importe quelle combinaison de caractères,
mais il ne peut pas commencer par un nombre, par exemple voici 3 définitions des
étiquettes :
label1:
label2:
a:
Voici un exemple de l'instruction JMP:
.
Branchement conditionnel
Les sauts conditionnels
Contrairement à l'instruction JMP qui fait un saut inconditionnel, il ya des instructions
qui font un saut conditionnel (sauter seulement lorsque certaines conditions sont
réalisées). Ces instructions sont divisés en trois groupes, le premier groupe teste
seulement le drapeau, le second compare les nombres comme étant signés, et la
troisième compare les nombres comme non signés.
Toutes les instructions de branchement testent les valeurs du registre d'état. Ce dernier
contient un ensemble de flags qui changent de valeurs surant l'exécution du
programme.
La figure suivante détaille le contenu du registre d'état :
Remarque:
Quand il s'agit de comparer des valeurs numériques, l'instruction CMP est utilisée (elle
fait la même chose que l'instruction SUB (soustraction), mais ne garde pas le résultat,
elle affecte seulement les drapeaux)
Exemple:
Voici un exemple montrant l'utilisation de l''instruction CMP avec les sauts conditionnels
.
L'instruction putc joue le meme role que printf en C. Cette instruction est définie dans
un fichier qui vient avec l'èmulateur emu8086.
donc pour pouvoir l'utiliser on met toujours en entête du programmeinclude
"emu8086.inc"
l'instruction Loop
Dans cet exemple, à chaque passage par l'instruction loop, le registre CX est
décrémenté et l'exécution reprend à partir de mon_etiquette.
une fois le registre CX atteint la valeur 0, l'exécution continu de manière séquentielle.
Exemple:Parcours d'un tableau..
.
.
.
Un dernier exemple :
Attention:Exercice
Coder en assembleur les instructions suivantes :
Interruptions utiles
Les entrées / sorties
Les procédures
La procédure est une partie du code qui peut être appelé à partir de votre programme
afin de faire quelques tâches spécifiques. Les procédures rendent les programmes plus
structurels et plus facile à comprendre. Généralement à la fin de son exécution, la
procédure revient au même point d'où elle a été appelée.
La syntaxe de déclaration de la procédure:
.
name - est le nom de la procédure, le même nom doit être dans le haut et le bas, ceci
est utilisé pour vérifier la fermeture correcte des procédures.
Probablement, vous savez déjà que l'instruction RET est utilisée pour revenir au
système d'exploitation. La même instruction est utilisée pour retourner de la procédure.
PROC et ENDP sont des directives de compilation, elles ne sont pas assemblés dans un
code machine. Le compilateur se souvient juste de l'adresse de la procédure pour
l'appeler,
et c'est l' instruction CALL est utilisé pour appeler une procédure.
Voici un exemple:
Remarque:
Dans l'exemple ci-dessus le registre AL est mis à jour chaque fois que la procédure est
appelée, BL reste inchangé. Cet algorithme calcule 2 à la puissance de 4,
et le résultat final se trouve dans AX.
La pile
Définition
Les piles offrent un nouveau moyen d'accéder à des données en mémoire principale,
qui est très utilisé pour stocker temporairement des valeurs.
Une pile est une zone de mémoire et unpointeur qui conserve l'adresse du sommet
de la pile.
PUSHregistre --
empile le contenu du registre sur la pile.
>
retire la valeur en haut de la pile et la place dans le
POPregistre
regsitres spécifié.
Exemple:Transfert de AX vers BX en passant par la pile
PUSH AX ..................; Pile <- AX
POP BX .....................; BX <- Pile
La pile est souvent utilisée pour sauvegarder temporairement le contenu des registres :
.
On voit que la pile peut conserver plusieurs valeurs. La valeur dépilée par POP est la
dernière valeur empilée; c'est pourquoi on parle ici de pile LIFO (Last In First Out,
Premier Entré Dernier Sorti).
Les registres SS et SP
La pile est stockée dans un segment séparé de la mémoire principale. Le processeur
possède deux registres dédiés à la gestion de la pile, SS et SP.
Le registre SS (Stack Segment) est un registre segment qui contient l'adresse du
segment de pile courant (16 bits de poids fort de l'adresse). Il est normalement initialisé
au début du programme et reste fixé par la suite.
Le registre SP (Stack Pointer) contient le déplacement du sommet de la pile (16 bits
de poids faible de son adresse).
Les adresses croissent vers le bas. SP pointe sur le sommet (dernier emplacement occupé).
Remarque:
Noter le mot clef ``stack '' après la directive SEGMENT, qui indique à l'assembleur qu'il
s'agit d'un segment de pile. Afin d'initialiser SP, il faut repérer l'adresse du bas de la
pile; c'est le rôle de la ligne
base_pile EQU this word
Une pile vide. L'étiquette base-pile repère la base de la pile, valeur initiale de SP
Noter que le registre SS s'initialise de façon similaire au registre DS; par contre, on peut
accéder directement au registre SP.
Partie 4 : Travaux pratiques
TP 1
TP 1
Objectifs
• Se familiariser avec les commandes de DEBUG.
• Ecrire des exemples pour mieux appréhender l'utilité de DEBUG.
• Voir la différence entre coder avec DEBUG et avec un programme assembleur
classique.
MATÉRIEL UTILISÉ
• Micro-ordinateur IBM et compatible muni d'un μP80x86.
• Programme DEBUG
Introduction
Activité 1 : Entrée et Sortie de DEBUG
Activité 2 : Examiner et changer les contenus de registres
Activité 3 : Coder et Exécuter les programmes avec DEBUG
Activité 4 : Manipulation des données avec DEBUG
Activité 5 : La convention « Little Endian » et comment le μP80x86
sauvegarde les mots
Activité 6 : Examiner et changer le registre FLAGS avec DEBUG
Activité 7 : Compléments
Introduction
DEBUG, un programme inclus dans le système d'exploitation DOS de Microsoft et
IBM PC, permet de suivre l'exécution d'un programme écrit en langage
assembleur, en bloc ou une instruction à la fois. Ce qui est important pour trouver
ce qui ne marche pas dans un programme.
Plus particulièrement, DEBUG permet d'examiner et de changer le contenu de la
mémoire, entrer un programme et l'exécuter.
L'objectif de ce TP est de bien comprendre la programmation avec l'utilitaire
DEBUG, plus particulièrement comment:
- entrer et sortir de DEBUG,
- entrer, exécuter et déboguer des programmes,
- examiner et changer le contenu des registres et de la mémoire,
- manipuler les commandes les plus importantes de DEBUG.
Plusieurs exemples de programmation en langage assembleur utilisant l'utilitaire
DEBUG seront vus. Pour commencer, voici un sommaire rapide des commandes
DEBUG qui seront utilisées tout au long de cette séance.
.
.
Activité 6 : Examiner et changer le
registre FLAGS avec DEBUG
Avec la commande „R F' ou même „R' (à la fin de la 3eme ligne), l'état des 8 bits, les
plus importants, du registre flags sont affichés. Ceci permet de suivre leurs évolutions
au fur et à mesure que les instructions s'exécutent en utilisant „T' par exemple.
Il convient de signaler que pour les 8 bits (OF, DF, IF, SF, ZF, AF, PF, et CF) du
registre FLAGS:
- Si tout ces bits sont à l'état RESET (mise à 0), le registre FLAG s'affichera comme :
NV, UP, DI, PL, NZ, NA, PO NC (pour les bits OF, DF, IF, SF, ZF, AF, PF, et CF)
- Si tout ces bits sont a haut (mise à 1), le registre FLAG s'affichera comme :
OV, DN, EI, NG, ZR, AC, PE CY.
A l„invite du DEBUG, taper „A' 100, et après chaque entrée du clavier, les instructions
suivante (une ligne à la fois) :
MOV BX, 0
MOV AX, 0
ADD BL, 4D
ADD BL, C3
ADD AX, 1222
ADD AX, 1333
ADD AX, 1191
MOV CX, AAAA
ADD CX, 5556
INT 3
Méthode:
Utiliser la commande „T' pour suivre l'exécution des instructions, une à la fois,
et observer l'évolution des bitsFLAGS tout en commentant.
Activité 7 : Compléments
- La commande „H <nbr 1>, <nbr 2>' permet d'afficher la somme et la différence
entre deux nombres hexadécimaux.Vérifier avec „H BA 21'.
- La commande „P' est utilisée pour exécuter un bloc d'instructions (une boucle, appel
de procédure, un programme d'interruption, ou répéter une chaîne de caractères),
comme s'il s'agit d'une seule (macro-)instruction. Avec le programme de l'activité 6, en
tapant „P 100 5', les 5 premières instructions s'exécutent en un seul bloc.
Vérifier.
- La commande „M' est utilisée pour copier une plage de données d'une location à une
autre. Exécuter ces commandes, après chaque entrée du clavier, et observer:
F 350 35f AB
D 350 LF
M 350 LF 370
D 350 LF
D 370 LF
- La commande „C' permet de comparer deux espaces mémoires et afficher les octets
qui différent. Avec le programme précédent, appliquer la commande „C 350 35E 370'
et ensuite „C 350 35E 36F'. Observer et commenter.
- La commande „S' permet de chercher dans un espace mémoire une donnée
particulière. Avec le programme précédent, appliquer la commande „S 340 35E AB'.
Observer et commenter.
- Enfin, cette dernière activité montre comment coder un simple programme avec
DEBUG, l'exécuter et placer des données dans un espace. Elle permet aussi de voir la
différence avec le codage en utilisant un langage assembleur standard commeMASM.
Méthode:
A l„invite du DEBUG, taper „A' 100, et rentrer les instructions et commandes suivantes
(une à la fois):
MOV CX, 05
MOV BX, 200
MOV AL, 0
ADD AL, [BX]
INC BX
DEC CX
JNZ 0108
MOV [205], AL
INT 20 (fin de programme)
Ensuite :
E 200 25 12 15 1F 2B
D 200 LF
G=100 111
D 200 LF
Remarque:
Ce programme contient une instruction de saut basée sur l'état de l'indicateurZF du
registre FLAGS. Il montre quelques différences entre programmer avec DEBUG et avec
un programme assembleur classique comme MASM.
Noter par exemple qu'avec DEBUG l'instruction JNZ n'est pas suivie d'une étiquette
(telle BOUCLE) de l'instruction vers laquelle le saut s'effectue, contrairement à MASM.
L'opérande de l'instruction „JNZ 0108' est directement l'offset de l'adresse vers laquelle
le saut est effectué.
L'autre différence importante avec le programme MASM : le segment de données DS,
dans lequel les données sont entrées, est séparé du segment du code qui contient les
instructions.
Avec DEBUG, ces données sont écrites avec la commande „E' à partir de l'adresse
pointée par BX, alors qu'avec MASM, on aurait écrit „MOV BX, OFFSET DATA' avec
„DATA DB 25h, 12h 15h 1Fh 2Bh'.
Complément:
le même programme écrit avec MASM serait :
G:\cours d'achitecture\web\co\Architecture_Ordis_60.html
Ce qui vient par la suite sera uniquement du TASM. Donc tous les programmes écrits
vont respecté la structure vu précédemment dans le COURS !
TP 2
Objectifs
Introduction
Activité 1 : Écrire et exécuter un programme assembleur
Activité 2 : Additionner des mots au lieu des octets
Activité 3 : Déplacer un bloc de données octet / mot
Activité 4 : Les emplacements mémoire des données
Introduction
Les programmes de Borland Turbo
Assembler et Turbo Link sont des utilitaires qui
permettent d'assembler (avec la
commande TASMnom_fichier.asm) et lier (avec la
commande TLINK nom_fichier.obj) un fichier écrit en
langage assembleur (nom_fichier.asm) pour le
convertir en un fichier exécutable (nom_fichier.exe)
écrit dans le langage machine binaire.
Il est possible d'utiliser l'utilitaire DEBUG pour
déboguer le programme assembleur se trouvant dans
le format exécutable (nom_fichier.exe). Pour utiliser
DEBUG, sous DOS, on écrit: DEBUG nom_fichier.exe
Ensuite, toutes les commandes vues durant la séance
du TP1 peuvent être utilisées de la même manière. Il
est à noter qu'un équivalent de DEBUG existe. Il s'agit
de EMU8086. Celui-ci sera utilisé durant la prochaine
séance de TP.
Activité 1 : Écrire et exécuter un
programme assembleur
Partie 1 :
En utilisant un éditeur de texte de votre choix, écrivez un programme qui permet
d'additionner dix nombres quelconques (entiers non-signés d'un octet); faites toutefois
attention au dépassement! Pour cela, utiliser une boucle et le mode d'adressage
registre indirect. Dans le programme, vous devrez inclure un segment de code et un
segment de données.
Assembler et lier votre programme en utilisant les
commandes TASM et TLINK simplement sans aucune option. Vérifier que les
fichiers .OBJ et .EXE sont générés.
Sous DOS, taper TASM /? et TLINK /? pour avoir une idée générale de toutes les
options disponibles.
Assembler à nouveau en incluant l'option ( /l ou /la ) pour TASM qui permet
d'obtenir un listing d'assemblage. Visualiser le fichier portant l'extension .LST et
observer son contenu.
Lier à nouveau en incluant l'option ( /m ou /s ) pour TLINK qui permet d'obtenir
une carte détaillée de l'occupation mémoire. Visualiser le fichier .MAP et observer
son contenu.
Fournir ces fichiers avec votre rapport.
Note: Dorénavant, inclure toujours les options ( /la et /zi ) pour TASM et ( /s et /v )
pour TLINK.
Partie 2 :
Avec le programme DEBUG, charger le fichier exécutable généré durant la partie
précédente. Désassembler le programme pour voir les valeurs assignées par le DOS au
registre CS et l'offset d'origine de votre code. Où se trouve en mémoire votre segment
de données? Vérifier le placement des données à sommer et en indiquer la plage
d'adresse.
Partie 3 :
Tracer le programme et analyser les changements des registres généraux, index, base,
pointeurs et flag, instruction par instruction jusqu'à la fin du programme. Vérifier
l'exactitude de votre somme et son emplacement mémoire.
Activité 2 : Additionner des mots au lieu
des octets
Reprendre l'activité 1, mais cette fois-ci en additionnant 4 mots de 16-bits:
1222H, 1333H, 1191H, et 32F1H. Sauvegarder le programme pour l'utiliser
ultérieurement.
.
Activité 3 : Déplacer un bloc de
données octet / mot
Énoncé :
Ecrire deux programmes qui permettent de déplacer un bloc de données un octet à la
fois, ensuite, un mot à la fois.
Utiliser le segment de données suivant (pour les MOTS 16 bit ) :
Attention:Objectif
Votre objectif consiste à déplacer le contenu de var1 dans var2 !
Testez vos deux programmes avec Debug, biensur aprés les avoir conpiler et linker
avec (TASM et TLINK).
Activité 4 : Les emplacements mémoire des
données
Partie 1:
Décrire ce que fait ce programme :
Méthode:Partie 2 :
Placer ce segment de données dans le programme :
.
Assembler et LINKer le programme et observer avec DEBUG comment ces données sont
placées dans la mémoire.
Partie 3 :
Que fait le programme suivant :