====== Exemple de langage assembleur ====== Bien que certain standard se soient mis en place, le langage assembleur est le langage d'un processeur particulier et donc, suivant les technologies mis en œuvre dans un processeur donné, l'assembleur sera différent. Le langage proposé ici n'est qu'un exemple correspondant à un processeur fictif que j'ai inventé pour les besoins du cours. === Exemple === MOV #4 ADD #8 STR @x Chaque ligne est une instruction simple que le processeur est capable d'exécuter. Dans cet exemple, voici ce que fait le programme : * charger la valeur 4 dans le registre de travail, * additionner 8 au contenu du registre de travail, * écrire le contenu du registre de travail dans la mémoire étiqueté ''x'' -- //STR signifie STORE, c'est à dire stocker.// Les instructions ne sont pas tellement variées. Il s'agit de : * copier des valeurs d'une case mémoire à une autre, * exécuter un calcul avec l'unité de calcul //UAL = Unité Arithmétique et Logique//, * lire en entrée, écrire en sortie (il faut bien pouvoir agir sur l'extérieur !) * gérer le flux d'instructions ==== Jeu d'instructions ==== === Une instruction est un mot binaire === Un programme est toujours composé dune liste d'instructions exécutées l'une après l'autre. Pour le processeur, une instruction est toujours un mot binaire. Dans notre exemple, une instruction est toujours **un mot de 16 bits**. Dans certains processeurs, on choisit de n'avoir que des instructions avec un format de taille fixe, ce qui conduit à un jeu d'instruction plus simple. On parle de **RISC = Reduced Instruction Set Computer**. D'autres font le choix d'instructions de format variable ce qui donne accès à un jeu d'instruction plus riche, mais l'exécution s'en trouve complexifiée. On parle de **CISC = Complex Instruction Set Computer**. Il y a eu un temps une mode pour le CISC. Mais c'est aujourd'hui plutôt le RISC qui domine, y compris pour les ordinateurs de bureau. Notre exemple sera donc de type RISC. === Format === Sur les 16 bits disponibles pour écrire coder une instruction, on choisit de : * attribuer 6 bits pour indiquer le nom de l'instruction -- on appelle cela un **opcode**, * les 10 bits restants permettent de préciser un argument. C'est à dire 2 bits pour préciser un type d'argument et 8 bits pour l'argument lui-même. C'est encore abstrait, voyons un exemple : ''%%ADD @x%%'' signifie que l'on veut additionner au registre de travail le contenu de la mémoire étiquetée ''%%@x%%''. On supposera ici que la mémoire ''%%@x%%'' a été placée à l'adresse 12. Le mot d'instruction s'écriera : * ''1000 00'' c'est à dire 32 en binaire. C'est l'opcode pour ADD. * ''10'' c'est le code binaire pour indiquer que l'argument à suivre est une adresse, * ''0000 1100'' c'est à dire 12 en binaire, c'est l'adresse de la case mémoire. L'instruction ''%%ADD @x%%'' est alors codée ''1000 0010 0000 1100''. Le codage est univoque. Un code correspond à une instruction et réciproquement. La machine voit le code en binaire -- par ex. ici ''1000 0010 0000 1100''. L'humain qui code en assembleur préfère l'écriture en texte -- par ex. ici ''%%ADD @x%%''. Mais les deux sont équivalents. ===== Le langage de la machine : Assembleur ===== On appelle **Assembleur** le langage de la machine. Pour bien comprendre, rappelons comment la machine exécute le programme. Pour comprendre comment fonctionne l'assembleur, il est préférable d'avoir quelques idées sur le fonctionnement d'une machine. Pour cela, faites d'abord le [[machine_von_neumann|TD fonctionnement d'une machine de Von Neumann]].