Cours ISN n°3
Architecture d'un ordinateur
Introduction
Imaginons une personne seule dans une pièce dont le rôle sera de faire des calculs. Cette personne ne sait par contre qu'additionner ou multiplier les nombres entre 0 et 9 avec leur retenue éventuelle. Elle a, pour couronner le tout, une mémoire de poisson rouge.
Elle reçoit les calculs à faire, écrits sur des feuilles, par une petite porte et doit les renvoyer par une autre. Elle dispose d'un petit bureau équipé d'une pile de feuilles de papier et d'un stylo, ainsi que d'une étagère à casiers numérotés à l'autre bout de la pièce.
Voici qu'un calcul à faire arrive par la petite porte, puis un deuxième et un troisième. Que fait notre calculateur ?
Il va tout d'abord déposer le premier calcul sur son bureau, puis mettre les deuxièmes et troisièmes calculs chacun dans un des casiers de l'étagère. Disons dans le casier 1 pour le deuxième calcul et dans le numéro 2 pour le troisième.
Il retourne alors à son bureau et commence à faire l'opération du premier calcul : 158+53.
Ne sachant qu'additionner les nombres entre 0 et 9, il pose donc l'opération comme nous avons appris à le faire à l'école primaire sur une feuille de papier, puisqu'il a une mémoire à très court terme. Il obtient alors le résultat de 211, l'écrit sur une feuille et la place dans la porte prévue pour transmettre les résultats.
Il fait alors le vide sur son bureau en se débarassant des feuilles de brouillon qu'il a utilisées pour le premier calcul et va chercher dans le casier numéro 1 de l'étagère le calcul suivant à faire. Il s'installe à son bureau et découvre l'opération 23×18.
Il pose alors sur une feuille l'opération et commence donc par la ligne de 8×23. Il écrit ce résultat intermédiaire sur une feuille de papier : 184, mais il n'a plus de place ni sur sa feuille, ni sur le bureau. Que peut-il faire ? Il aura besoin de ce résultat dans quelques instants pour terminer sa multiplication. Il se rappelle alors que le casier 1 de l'étagère vient d'être libéré. Il note sur une feuille cette information, et va déposer la feuille contenant 184 dans le casier correspondant de l'étagère. Il effectue donc 1×23 (avec le point de décalage) et obtient : "23.". Il va alors chercher le résultat stocké dans l'étagère, ne se trompe pas de casier grâce à sa petite note, et effectue donc l'opération 184+230 pour obtenir 414. Information qu'il transmet alors sur une feuille par la petite porte de sortie des calculs.
Il poursuit sa journée en répétant inlassablement les mêmes petites tâches, quelque soit les calculs à faire.
Cette situation représente, de manière très grossière, ce qu'il se passe au sein d'un ordinateur.
Cette structure, utilisée depuis le milieu des années 40, peut être décrite par le schéma suivant :
les entrées/sorties permettent à l'ordinateur de communiquer avec l'extérieur;
la mémoire mémorise les données à manipuler;
le processeur manipule l'information et donne un résultat.
Les communications entre ces divers éléments se font via un bus, qui est en fait un ensemble de fils électriques, chaque fil permettant de faire circuler un bit.
Architecture
En informatique, le terme architecture désigne l’organisation des éléments d’un système et les relations entre ces éléments. L’architecture logicielle concerne l’organisation des différents programmes entre eux. L’architecture matérielle concerne l’organisation des différents dispositifs physiques que l’on trouve dans un ordinateur. Dans les deux cas, cette organisation se base sur le principe de décomposition.
Le modèle d’architecture de la plupart des ordinateurs actuels provient d’un travail effectué par John Von Neumann pendant la seconde guerre mondiale. L’objectif était la mise au point de calculateurs pour établir les tables de tirs de pièces d’artillerie.
Von Neumann s'est basé sur les résultats d'Alan Turing concernant sa machine universelle
pour concevoir son premier ordinateur. La figure ci-dessous présente un schéma du modèle de von Neumann :
L'architecture de von Neumann décompose donc l'ordinateur en quatre parties distinctes :
l'unité de traitement, ou unité arithmétique et logique (UAL) qui effectue les opérations de base,
l’unité de contrôle, qui est chargée du séquençage des opérations,
la mémoire, qui contient à la fois les données et le programme qui indique à l’unité de contrôle quels calculs faire sur ces données,
les dispositifs d’entrées-sorties, qui permettent de communiquer avec le monde extérieur.
Les entrées/sorties
Un ordinateur contient des composants électroniques qui se chargent de traduire des informations venant de l’extérieur en nombres. Ces composants sont ce qu'on appelle des entrées. Par exemple, le clavier est une entrée : l'électronique du clavier attribue un nombre entier à une touche, nombre qui sera communiqué à l’ordinateur lors de l'appui d'une touche. Pareil pour la souris : quand vous bougez la souris, celle-ci envoie des informations sur la position ou le mouvement du curseur, informations qui sont codées sous la forme de nombres. La carte son est aussi une entrée : elle est capable d'enregistrer un son, et de le restituer sous la forme de nombres.
Les sorties sont quant à elles des composants électroniques qui transforment des nombres présents dans l'ordinateur en quelque chose d'utile. Ces sorties effectuent la traduction inverse de celle faite par les entrées : si les entrées convertissent une information en nombre, les sorties font l'inverse : là où les entrées encodent, les sorties décodent. Par exemple, un écran LCD est un circuit de sortie : il reçoit des informations sous forment de bits, et les transforme en image affichée à l'écran. Même chose pour une imprimante : elle reçoit des documents texte encodés sous forme de nombres, et les imprime sur du papier. La carte son est aussi une sortie, vu qu'elle transforme les bits d'un fichier audio en tensions destinées à un haut-parleur : c'est à la fois une entrée, et une sortie.
La mémoire
La mémoire (nous parlons ici de la mémoire RAM) est le composant qui mémorise des informations, des données. Elle est composée d'un grand nombre de bascules, c'est-à-dire une unité physique qui est soit chargée électriquement, soit qui ne l'est pas. Une mémoire ne peut donc stocker qu'une quantité finie de données, et sa capacité correspond à la quantité d'informations qu'elle peut stocker. Plus précisément, il s'agit du nombre de bits que celle-ci peut contenir. Dans la majorité des cas, la mémoire est découpée en plusieurs bytes, des blocs de mémoire qui contiennent chacun un nombre fini et constant de bits. Le plus souvent, ces bytes sont composés de plusieurs groupes de 8 bits, appelés des octets.
Voici un schéma d'une partie de la mémoire où chaque case représente une bascule :
Bien sûr chacune des bascules est soit chargée soit non chargée électriquement, on aurait donc pu écrire à l'intérieur des 0 et des 1.
Comme vous pouvez le voir, les bascules sont disposées par barrettes de huit. La mémoire est ainsi composée de millions de barrettes chacune comportant huit bascules.
Une barrette peut donc stocker un octet.
Pour que les informations soient trouvables, les barrettes sont numérotées. La première porte le numéro 0, la seconde le numéro 1 etc. On appelle ce numéro une adresse.
C'est grace à ce système d'adressage que l'ordinateur arrive à se repérer dans la mémoire. Lorsqu'il stocke une donnée, il la met à une adresse précise. Plus tard dans le programme, lorsque on lui demande d'utiliser cette donnée il va aller la chercher à l'adresse où il l'avait placée.
Ajoutons les adresses à notre schéma :
64
54
44
34
24
14
04
L'accès à la mémoire se fait en temps constant quelle que soit la valeur de l’adresse (accès direct). Pour communiquer avec la mémoire, le bus est subdivisé en un bus d’adresse et un bus de données. Il existe deux types d’accès:
la lecture (mémoire→processeur) transfère sur le bus de données le mot contenu dans la cellule dont l’adresse est située sur le bus d’adresse,
l’écriture (processeur→mémoire) transfère dans la cellule dont l’adresse est sur le bus d’adresse, le mot contenu sur le bus de données.
La capacité d'une mémoire est le nombre maximal de bits qu'elle peut contenir. Dans la majorité des mémoires, les bits sont regroupés en paquets de taille fixe : des cases mémoires, aussi appelées bytes. De nos jours, le nombre de bits par byte est généralement un multiple de 8 bits : ces groupes de 8 bits s'appellent des octets.
On ne compte par contre pas les capacité en bits, on préfère mesurer la capacité d'une mémoire en donnant le nombre d'octets que celle-ci peut contenir. Mais les mémoires des PC font plusieurs millions ou milliards d'octets. Pour se faciliter la tâche, on utilise des préfixes pour désigner les différentes capacités mémoires : kibioctets, mebioctets et gibioctets, notés respectivement Kio, Mio et Gio.
Préfixe
Capacité mémoire en octets
Puissance de deux
Kio
1024
$2^{10}$ octets
Mio
1 048 576
$2^{20}$ octets
Gio
1 073 741 824
$2^{30}$ octets
Par convention, on utilise souvent des puissances de 1024, qui est la puissance de deux la plus proche de 1000. Or, dans le langage courant, kilo, méga et giga sont des multiples de 1000.
Autrefois, on utilisait les termes kilo, méga et giga à la place de kibi, mebi et gibi, par abus de langage. Mais peu de personnes sont au courant de l'existence de ces nouvelles unités, et celles-ci sont rarement utilisées. Cette confusion permet aux fabricants de disques durs de nous « arnaquer » : Ceux-ci donnent la capacité des disques durs qu'ils vendent en kilo, mega ou giga octets : l’acheteur croit implicitement avoir une capacité exprimée en kibi, mebi ou gibi octets, et se retrouve avec un disque dur qui contient moins de mémoire que prévu.
Ainsi :
1 Ko = 1000 octets et 1kio = 1024 octets,
1 Mo = 1000 Ko = $10^6$ octets et 1 Mio = 1024 Kio = 1024×1024 octets = 1 048 576 octets,
8 Go = 8000 Mo = $8\times 10^{9}$ octets et 8 Gio = $8\times1024^3$ octets $\simeq$ $8,59\times10^9$ octets.
Une clé usb de 16Go représente en fait $\dfrac{16}{1,073741824}$ $\simeq$ $14,90$ Gio. Ou encore un disque dur d'un To contient, à peu près, 931 Gio.
Le processeur
Nous avions vu que l’unité de contrôle du processeur se charge du séquençage des opérations, pendant que l'unité de traitement (ou unité arithmétique et logique) se charge des opérations de bases. Cependant, lors de ces opérations des données ont besoin d'être mémorisées momentanément. La RAM n'est pas utilisée car trop lente. Chaque microprocesseur possède des mémoires internes que l'on appelle registres. L'ensemble de ses registres s'appelle jeu de registres.
Un registre est donc un emplacement de mémoire interne à un processeur. Les registres se situent au sommet de la hiérarchie mémoire : il s'agit de la mémoire la plus rapide d'un ordinateur, mais dont le coût de fabrication est le plus élevé car la place dans un microprocesseur est limitée. Leur capacité dépasse donc rarement quelques dizaines d'octets.
Sur de nombreux processeurs, les registres sont spécialisés et ne peuvent contenir qu'un type bien précis de données. On rencontre souvent les classes de registres suivantes :
les registres entiers, chargés de stocker des nombres entiers (et éventuellement des adresses),
les registres flottants, qui stockent des nombres à virgule flottantes,
les registres d'adresses : sur certains processeurs, les adresses mémoires à manipuler sont placées dans ces registres dédiés,
les registres d'index, qui servaient à faciliter certains calculs d'adresses sur de vieilles architectures,
les registres à prédicats qui stockent des résultats de comparaisons et d'instructions de tests diverses.
Un processeur contient souvent des registres spécialisés, présents en un seul exemplaire. On trouve parmi ceux-ci :
compteur ordinal (CO) : indique l'emplacement de la prochaine instruction à être exécutée (synonymes : compteur de programme, pointeur d'instruction),
registre d'état (PSW pour Processor Status Word) : décrit l'état du processeur ; il est le plus souvent interprété bit à bit, chaque bit représentant un drapeau (zéro, retenue, signe, dépassement de capacité, etc.),
pointeur de pile : indique la position du prochain emplacement disponible dans la pile mémoire.
On peut donc résumer en disant qu'un microprocesseur est constitué de milliers de circuits élémentaires, qui réalisent chacun une micro-opération logique, ou qui matérialisent une position de mémoire. Le fonctionnement du microprocesseur consiste à combiner ou à déplacer des données stockées dans des positions de mémoire pour obtenir des résultats qui seront stockés dans d’autres positions de mémoire. Ainsi, un groupe de portes logiques pourra constituer l’opération d’addition, qui consistera à analyser les données contenues dans les positions de mémoire où se trouvent les chiffres des nombres à additionner, à calculer le résultat et à l’écrire dans une autre position de mémoire. Une opération d’addition peut comporter quelques dizaines de circuits logiques (il y a déjà une micro-opération par chiffre binaire), eux-mêmes constitués de portes logiques réalisées en général au moyen de deux transistors. Les processeurs actuels comportent des milliards de portes logiques, dont la taille est de l'ordre de la dizaine de nanomètre.
Effectuer une simple opération d’addition consiste donc à combiner les résultats produits par quelques dizaines de circuits élémentaires et stockés dans quelques dizaines de positions de mémoire. Pour obtenir de façon sûre le résultat final exact de l’opération, il faut coordonner correctement le fonctionnement de tous ces circuits. Ainsi par exemple, si un premier circuit calcule un résultat intermédiaire qui sera pris comme donnée d’entrée par un second circuit, le concepteur doit pouvoir être sûr que le premier circuit a vraiment fini son calcul et placé le résultat au bon endroit avant que le second ne commence son propre calcul.
Afin de pouvoir calculer de façon déterministe l’enchaînement correct des opérations élémentaires, elles sont synchronisées ; pour ce faire le processeur dispose d’une horloge centrale réalisée au moyen d’un dispositif à quartz, qui régule un circuit oscillant selon une fréquence extrêmement précise. À chaque fin de période le circuit oscillant émet un signal. La fréquence de ce circuit est de l’ordre de quelques GHz (quelques milliards d’impulsions par seconde).
Acheminer un signal en chaque point du processeur prend du temps, mais aussi de l’énergie. Les circuits ont une certaine résistance, et sont soumis à la loi d’Ohm. Afin de limiter la dérive d’horloge, le signal est émis dans un circuit en forme de grille qui recouvre l’ensemble du processeur, mais la consommation électrique d’un tel dispositif est importante. En outre, étant donnée la taille des circuits actuels (de l’ordre du milliard de transistors), il faut prévoir des répéteurs d’horloge (clock buffers). De fait, dans un processeur moderne, la fonction d’horloge utilise 30% de la consommation électrique totale, ce qui est considérable, pour ne pas dire excessif, lorsque l’on sait qu’aujourd’hui la consommation électrique est le principal obstacle que s’efforcent de surmonter les concepteurs de circuits.
Les langages informatiques
Le langage naturel d'un microprocesseur est ce que l'on appelle le langage machine. Si l'on veut qu'il effectue une succession de calculs, autant les instructions que les nombres doivent lui être transmis à l'aide seulement de 0 et de 1.
Les premiers informaticiens communiquaient donc avec leur ordinateur à l'aide simplement de bits, mais cela s'avérait long, fastidieux et surtout était entachée d'erreurs.
En 1954 un ingénieur de chez IBM invente ce que l'on appelle un langage assembleur. C'est un langage qui permet à l'aide d'écritures plus courtes et plus simples de donner des instructions ou des nombres à un processeur. Ce code assembleur est traduit en langage machine par un programme nommé assembleur.
Chaque processeur possède son propre jeu d'instructions, ainsi chaque processeur possède son propre langage assembleur. On a alors commencé à inventer des langages indépendants du processeur utilisé et où les instructions sont proches de l'anglais. On les appelle langages de haut niveau. On utilise alors un compilateur qui transforme le programme écrit dans le dit langage en langage machine.
Les compilateurs étaient dans les premiers temps écrits en langage assembleur, puis plus tard, dans un langage de haut niveau.
Le tout premier de ces langages de haut niveau est le Fortran (FORmula TRANslator) développé en 1954. Suivront ensuite de plus en plus de langages, par exemple : Lisp (1958), Algol (1958), COBOL (1959), Fortran IV (1962), Basic (1964), Logo (1968), Pascal (1971), C (1972), Prolog (1972), SQL (1974), C++ (1984), Caml (1985), Perl (1987), Python (1991), Visual Basic (1991), Ruby (1993), Java (1995), PHP (1995), Javascript (1995), C# (2000) etc.