Architecture des ordinateurs UE23 TP-7

by Joseph Razik, last modified on 2025-03-24

7   Assembleur 68000

7.1   Objectif

Dans ce TP vous allez devoir écrire du code en langage assembleur du processeur Motorola 68000, l'assembler et vérifier son fonctionnement dans un émulateur. Une documentation complète des instructions est donnée dans le fichier M68000.pdf.

Plusieurs exercices sont similaires à ceux effectués pour l'Ordinapoche, mais adaptés à ce processeur.

7.2   Préambule

L'obtention du code machine à partir d'un fichier en langage assembleur se fait en deux étapes:

  • l'assemblage: converti le programme en code machine mais ne résout pas toutes les adresses,
  • l'édition de liens: résout les adresses non connues à l'assemblage.

Cette séparation vient de la gestion des code relogeables et de la possibilité d'utiliser des librairies, c'est-à-dire du code inclus dans d'autres fichiers.

La commande à utiliser pour l'étape d'assemblage est la suivante :

m68k-linux-gnu-as -ahlns --register-prefix-optional  -am -m 68000

La commande à utiliser pour l'étape d'édition de lien est :

m68k-linux-gnu-ld -M --oformat srec -Ttext 0
  1. Afin d'éviter d'écrire ces commandes avec tous ces arguments à chaque fois, vous allez définir 2 alias dans votre shell :

    • m68kas : pour l'assembleur

    • m68kld : pour l'éditeur de liens

      Pour cela faut ajouter dans votre fichier de configuration du shell (fichier verb|.bashrc|) des commandes alias nom_alias='commande '.

  2. Affichez le contenu de votre variable d'environnement PATH, et s'il n'est pas dedans, ajoutez lui le chemin /home/partage/UE23/. Vous aurez ainsi quelques caractères de moins à écrire dans le terminal pour exécuter l'émulateur.

7.3   Prise en main de l'assembleur

Soit le programme en langage assembleur suivant :

    .equ A, 12
_start:
    move.b #A, d0
    .xdef _start

Son assemblage par la commande m68kas donne l'affichage suivant :

  1                   .equ A,12
  2                   _start:
  3 0000 103C 000C    move.b #A,d0
  4                   .xdef _start
DEFINED SYMBOLS
  {exemple.s}:1      *ABS*:0000000c A
  {exemple.s}:2      .text:00000000 _start
NO UNDEFINED SYMBOLS
  • Dans la première partie, on retrouve le code et son assemblage :

    • la première colonne est le numéro de ligne dans le programme source,

    • la seconde colonne est le code machine des instructions assemblée avec son adresse en mémoire :

      • 0000: est l'adresse en mémoire de cette instruction,
      • 103C 000C: est l'assemblage en code machine de l'instruction et de ses paramètres.
    • la troisième colonne est l'instruction d'origine en langage assembleur.


  • Dans la seconde partie, sont listés les différents symboles (constantes, variables, labels) définis dans le programme avec les informations suivantes :

    • numéro de ligne de définition dans le programme source,

    • le type de symbole:

      • *ABS* : pour les constantes, leur valeur, et leur symbole,

      • .text : pour les variables et labels en mémoire dans le segment .text, leur adresse, et leur symbole


  • La troisième partie liste les symboles non définis, pouvant venir de codes externes.

S'il n'y a pas eu d'erreur, la commande génère aussi un fichier à destination de l'éditeur de liens. Sans indication de nom de fichier, le fichier généré est a.out.

Ce fichier est appelé fichier objet. Pour lui spécifier un nom il faudra passer l'option -o et le nom du fichier de sortie. Par convention, les fichiers objets ont l'extension .o.

Ce fichier n'est pas l'exécutable et n'est pas lisible.


Si tout s'est bien passé jusque là, l'étape suivante est l'édition de liens avec la commande m68ld. S'il n'y a pas d'erreur à cette étape, un fichier en code machine est généré au format SREC qui sera lisible par l'émulateur. Contrairement au fichier objet, ce format est lisible :

$> cat exemple.x
S0060000742E78DF
S1070000103C000CA0
S9030000FC

La première ligne est un commentaire, la seconde ligne correspond au code en langage machine (0000 103C 000C), et la dernière ligne indique le point d'entrée du programme, c'est-à-dire l'adresse de la première instruction du programme correspondant au label _start (0000).


  1. Si ce n'est fait, refaite ces étapes par vous-même pour vous en assurer.

7.4   Prise en main de l'émulateur

L'émulateur de processeur Motorola 68000 qui sera utilisé s'appelle pym68k. Cet émulateur accepte les fichiers au format SREC et affiche par défaut l'état des registres du CPU ainsi que le contenu de la RAM.

Avec l'exemple précédent nous obtenons :

D0: 0000000C      D4: 00000000
D1: 00000000      D5: 00000000
D2: 00000000      D6: 00000000
D3: 00000000      D7: 00000000

A0: 00000000      A4: 00000000
A1: 00000000      A5: 00000000
A2: 00000000      A6: 00000000
A3: 00000000   A7/SP: 00000000

PC: 00000004      SR: ----------

00000000    10 3C 00 0C 00 00 00 00 - 00 00 00 00 00 00 00 00

Le programme s'est exécuté et terminé, la valeur 12 se trouve bien dans le registre d0, comme escompté.

L'émulateur propose également un mode pas-à-pas pour exécuter une seule instruction à la fois et pas tout le programme.

  1. Tester votre programme exemple précédent sur l'émulateur.

7.5   Exercice 1: swap

Ce premier exercice simple a pour objectif de réaliser l'ensemble de la chaîne de production d'un code machine exécutable par l'émulateur sur un énoncé simple.

Écrivez le code en langage assembleur 68000 d'un programme réalisant :

  1. l'initialisation de l'octet faible du registre D1 à 0x11,
  2. l'initialisation de l'octet faible du registre D2 à 0x22,
  3. la permutation des deux registres.

Vérifiez le résultat de l'exécution de votre programme avec l'émulateur.

7.6   Exercice 2: swap en mémoire

Soient:

  • une variable A en mémoire à l'adresse 0, de taille BYTE et initialisée à 0x11;
  • une variable B en mémoire à l'adresse suivante, de taille BYTE et initialisée à 0x22;
    1. Écrivez un programme qui permute ces deux valeurs.

7.7   Exercice 3: décomposition de nombre

Soit un nombre décimal à 2 chiffres placé dans le registre D0 (de taille LONG). Écrivez un programme simple (sans boucle) permettant de placer :

  • dans le registre D1 le chiffre des unités,
  • dans le registre D2 le chiffre des dizaines.

Tester votre programme avec différentes valeur d'initialisation de D0 (≤ 999).

7.8   Exercice 4: affichage

Grâce à l'instruction trap #1 il est possible d'afficher une chaîne de caractères codée en ASCII ou en UTF-8. Pour cela il faut d'abord placer dans le registre A0 l'adresse de la chaîne en mémoire, puis faire appel à l'instruction trap.

Autre particularité à laquelle il faut préter attention, c'est que la chaîne de caractères à afficher doit absolument se terminer par le caractère NULL, c'est-à-dire la valeur 0 codée sur 1 octet. En effet, cette valeur sert de marqueur de fin de chaîne.

  1. Écrivez un programme qui affiche la chaîne « Décomposition d'un nombre! », avec retour à la ligne.

  2. Complétez votre programme en utilisant le code de l'exercice précédent pour qu'il affiche la chaîne, puis le nombre à décomposer, et enfin chaque chiffre, tous sur des lignes isolées.

    Indication : analyser bien la table des caractères ASCII en hexadécimal (man ascii).

7.9   Exercice 5: compte à rebours

Dans cet exercice nous allons aborder la programmation d’une structure répétitive (while ou for) et donc les tests et sauts conditionnels.

un décompte de 5 à 0 et la fin la chaîne « décollage ».

  1. Écrivez un programme qui commence par afficher « Compte à rebours enclenché ! »

  2. Soit le registre D0 initialisé à la valeur 5.

    Écrivez un programme qui affiche le décompte de la valeur de D0 à 0 (5...4...3...2...1...0) en utilisant une boucle avec comparaison et saut, la comparaison se faisant sur le code ASCII.

  3. Complétez le programme pour qu'à la fin il affiche la chaîne de caractères « Décollage ! ».

7.10   Exercice 6: saisie numérique

L'instruction trap #2 permet de placer en mémoire à l'adresse contenue dans A0 une chaîne de caractères saisie au clavier (sans le retour à la ligne mais avec le marqueur).

  1. Écrivez en programme qui affiche « Entrez un nombre : », puis_attend la saisie d'un nombre d'au plus 4 chiffres et place sa valeur dans le registre D0.