Du matériel au programme.

Un processeur est constitué de milliards de transistors, ces transistors comparent des tensions électriques pour effectuer des calculs. Il utilise des données qui sont stockées dans des mémoires.

Pour servir à quelque chose, l'ordinateur doit recevoir des données sur lesquelles il va calculer. Ces données sont fournies par un programme.

Un programme, c'est une suite d'instructions élémentaires. Elles mêmes étant des suites d'états électriques dans les transistors.

Le programme est enregistré dans la mémoire et le processeur va lire des instructions dans cette mémoire. Chaque cycle d'horloge permet d'avancer un peu plus dans les calculs.

Un processeur ne sait calculer qu'en binaire (avec des 0 et des 1) : les programmes sont donc fournis en binaire.

Donc si on veut que le processeur effectue un calcul, il faudrait lui dire quelque chose de ce genre là : « 01010100 10110101 01101101 110110101 10101010 11011110 10101011 10111100 1100011 0101101 01111110 ».

Ce qui est totalement impossible pour un humain.

On peut déjà écrire tout ça en hexadécimal, pour alléger l'écriture : « 54 B5 6D DA D5 6F 55 DE 63 5A FC », mais ça reste illisible. Le processeur, lui ne comprend que ça.

Les fabricants de processeurs ont donc donné des noms « facile à retenir » pour chaque instruction en binaire.

Par exemple, le nom mov peut correspondre à l'instruction 10101101 01111001. L'ensemble des noms faciles à retenir constitue le langage assembleur.

Voici, par exemple, quelques-unes des quelques dizaines d'instructions utilisées pour programmer un processeur x86 :

  • mov : (move) déplace le contenu d'une case mémoire dans une autre case.

  • inc : (increment) incrémente la valeur contenue dans une case mémoire.

  • neg : (negative) prend un nombre et donne son opposé.

  • cmp : (compare) compare deux nombres.

  • jmp : (jump) « saute » à un autre endroit du programme.

Le langage assembleur n'est constitué que des instructions basiques comme celles ci.

Pour effectuer des calculs plus complexes, il faut au préalable décomposer ce calcul en une suite d'instructions qu'il connaît. Tout comme on peut décomposer une puissance en une suite de multiplications, puis en une suite d'additions

.

Pour que le processeur comprenne notre programme codé avec des mov et des inc, il faut les retranscrire en binaire. Cette étape est nommée l'assemblage.

Un programme en assembleur...

load 14 R0 # place le nombre 14 dans le registre R0

load 2 R1 # place le nombre 2 dans le registre R1

store R1 R2 # copie le contenu de R1 dans R2

store R1 R3 # copie le contenu de R1 dans R3

add R0 R2 # addition R0+R2 et place le résultat dans R2

mul R0 R3 # multiplication R0×R3 et place le résultat dans R3

store R0 0 # place le contenu de R0 à l'adresse mémoire @0

store R1 1 # place le contenu de R1 à l'adresse mémoire @1

store R2 2 # place R2 dans @2

store R3 6 # place R3 dans @6

archi_6

Au final, la mémoire contiendra quelques valeurs :

On a utilisé le processeur pour aller modifier des données présentes en mémoire.

C'est ça, la programmation.

Un TP

Nous allons utiliser un simulateur développé par Peter L Higginson. Ce simulateur est basé sur une architecture de von Neumann.

Voici le TP

L'assembleur, peu pratique ?

Même si coder en assembleur est plus rapide qu'en binaire, cela reste une étape fastidieuse : manipuler les données et les placer octet par octet dans la mémoire ou dans les registres, c'est long.

De plus que chaque processeur possède des noms et des numéros d'instructions différents ! Ainsi, un code en assembleur qui fonctionne sur un processeur Pentium ne marchera pas forcément sur un AMD 64 ou sur un processeur ARM. En gros, si vous écrivez un programme sur votre ordinateur, il ne marchera pas sur le mien ! C'est embêtant...

Si le programme ne marche que sur un processeur et non sur un autre, on dit que le programme n'est pas portable.

Dès les débuts de l'informatique moderne on a donc inventé un moyen pour palier à ces deux inconvénients que sont la lenteur à coder et la non portabilité : les langages de haut niveau.

Les langages de haut niveau

Les langages de haut niveau permettent une programmation rapide et plus simple que l'assembleur. Le code source est humainement compréhensible

archi_7
archi_8

Parmi les langages de haut niveau, il y a une multitude de langages différents. Le C est un exemple, mais peut-être avez vous entendu parler des langages Java, Python, PHP ? Ce sont tous des langages de haut niveau ! Il en va des préférences du programmeur d'utiliser l'un ou l'autre des langages pour faire ses programmes.

Chaque langage possède sa syntaxe et ses objectifs. Par exemple, le langage Perl est très bon pour chercher et analyser dans des fichiers textes, le langage PHP est utilisé pour générer des sites web.

Il n'est pas rare non plus de voir un programme qui soit écrit en différents langages : on utilise le langage le plus convenable pour chaque tâche.

Voici un petit tableau avec le code qui permet d'afficher le message « hello world » dans quelques langages :

Bref, vous voyez qu'il y en a pour tous les goûts :)

La compilation

Le problème des langages de haut niveau c'est qu'ils ne sont absolument pas compréhensibles par le processeur ! Avant de pouvoir être utilisé, le code doit être traduit en langage assembleur.

Cette traduction, c'est ce qu'on appelle la compilation.

Une fois en langage assembleur, il faut ensuite l'assembler en langage binaire :

archi_9

La compilation est l'assemblage en binaire.

Les langages de haut niveaux permettent donc d'accélérer la création d'un programme, et de le rendre portable !

AccueilArchitecture des ordinateurs > Du matériel au programme.< PrécédentSuivant >