Fonctionnement d'un ordinateur/L'architecture de base d'un ordinateur

Un livre de Wikilivres.

Dans les chapitres précédents, nous avons vu comment représenter de l'information, la traiter et la mémoriser avec des circuits. Mais un ordinateur n'est pas qu'un amoncellement de circuits et est organisé d'une manière bien précise. Il est structuré autour de trois circuits principaux :

  • les entrées/sorties, qui permettent à l'ordinateur de communiquer avec l'extérieur ;
  • une mémoire qui mémorise les données à manipuler ;
  • un processeur, qui manipule l'information et donne un résultat.
Architecture d'un système à mémoire.

Pour faire simple, le processeur est un circuit qui s'occupe de faire des calculs et de traiter des informations. La mémoire s'occupe purement de la mémorisation des informations. Les entrées-sorties permettent au processeur et à la mémoire de communiquer avec l'extérieur et d'échanger des informations avec des périphériques. Tout ce qui n'appartient pas à la liste du dessus est obligatoirement connecté sur les ports d'entrée-sortie et est appelé périphérique. Ces composants communiquent via un bus, un ensemble de fils électriques qui relie les différents éléments d'un ordinateur.

Architecture minimale d'un ordinateur.

Parfois, on décide de regrouper la mémoire, les bus, le CPU et les ports d'entrée-sortie dans un seul composant électronique nommé microcontrôleur. Dans certains cas, qui sont plus la règle que l'exception, certains périphériques sont carrément inclus dans le microcontrôleur ! On peut ainsi trouver dans ces microcontrôleurs, des compteurs, des générateurs de signaux, des convertisseurs numériques-analogiques... On trouve des microcontrôleurs dans les disques durs, les baladeurs MP3, dans les automobiles, et tous les systèmes embarqués en général. Nombreux sont les périphériques ou les composants internes à un ordinateur qui contiennent des microcontrôleurs.

La mémoire[modifier | modifier le wikicode]

La mémoire est le composant qui mémorise des informations, des données. 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. Bien évidemment, une mémoire ne peut stocker qu'une quantité finie de données. Et à ce petit jeu, certaines mémoires s'en sortent mieux que d'autres et peuvent stocker beaucoup plus de données que les autres. La capacité d'une mémoire correspond à la quantité d'informations que celle-ci peut mémoriser. Plus précisément, il s'agit du nombre de bits que celle-ci peut contenir.

Lecture et écriture : mémoires ROM et RWM[modifier | modifier le wikicode]

Pour simplifier grandement, on peut grossièrement classer les mémoires en deux types : les Read Only Memory et les Read Write Memory, aussi appelées mémoires ROM et mémoires RWM. Pour les mémoires ROM, on ne peut pas modifier leur contenu. On peut y récupérer une donnée ou une instruction : on dit qu'on y accède en lecture. Mais on ne peut pas modifier les données qu'elles contiennent. Quant aux mémoires RWM, on peut y accéder en lecture (récupérer une donnée stockée en mémoire), mais aussi en écriture : on peut stocker une donnée dans la mémoire, ou modifier une donnée existante. Tout ordinateur contient au moins une mémoire ROM et une mémoire RWM (souvent une RAM). La mémoire ROM stocke un programme, alors que la mémoire RWM sert essentiellement pour maintenir des résultats de calculs.

Architecture avec une ROM et une RAM.

Si tout ordinateur contient au minimum une ROM et une RWM (souvent une mémoire RAM), les deux n'ont pas exactement le même rôle. Idéalement, les mémoires ROM stockent des programmes à exécuter et sont lues directement par le processeur. La mémoire ROM stocke aussi les constantes, à savoir des données qui peuvent être lues mais ne sont jamais accédées en écriture durant l'exécution du programme. Elles ne sont donc jamais modifiées et gardent la même valeur quoi qu'il se passe lors de l'exécution du programme. Quant à la mémoire RWM, elle est censée mémoriser des données temporaires, nécessaires pour que le programme en mémoire ROM fonctionne. Elle mémorise alors les variables du programme à exécuter, qui sont des données que le programme va manipuler. Vu que les variables du programme sont des données qui sont fréquemment mises à jour et modifiées, elles sont naturellement stockées dans une mémoire RWM. Pour les systèmes les plus simples, la mémoire RWM ne sert à rien de plus.

L'adressage[modifier | modifier le wikicode]

Sur une mémoire RAM ou ROM, on ne peut lire ou écrire qu'un byte, qu'un registre à la fois : une lecture ou écriture ne peut lire ou modifier qu'un seul byte. Techniquement, le processeur doit préciser à quel byte il veut accéder à chaque lecture/écriture. Pour cela, chaque byte se voit attribuer un nombre binaire unique, l'adresse, qui va permettre de le sélectionner et de l'identifier celle-ci parmi toutes les autres. En fait, on peut comparer une adresse à un numéro de téléphone (ou à une adresse d'appartement) : chacun de vos correspondants a un numéro de téléphone et vous savez que pour appeler telle personne, vous devez composer tel numéro. Les adresses mémoires en sont l'équivalent pour les bytes. Il existe des mémoires qui ne fonctionnent pas sur ce principe, mais passons : ce sera pour la suite. Une autre explication est que l'adresse donne la position dans la mémoire d'une donnée.

Exemple : on demande à la mémoire de sélectionner le byte d'adresse 1002 et on récupère son contenu (ici, 17).

Le processeur[modifier | modifier le wikicode]

Dans les ordinateurs, l'unité de traitement porte le nom de processeur, ou encore de Central Processing Unit, abrévié en CPU. Un processeur est un circuit qui s'occupe de faire des calculs et de manipuler l'information provenant des entrées-sorties ou récupérée dans la mémoire. Tout ordinateur contient au moins un processeur. Je dis au moins un, car un ordinateur peut avoir plusieurs processeurs.

Le processeur exécute un programme, une suite d'opérations[modifier | modifier le wikicode]

Tout processeur est conçu pour effectuer un nombre limité d'opérations bien précises, comme des calculs, des échanges de données avec la mémoire, etc. Ces opérations sont appelées des instructions. Elles se classent en quelques grands types très simples :

  • Les instructions arithmétiques font des calculs. Un ordinateur peut ainsi additionner deux nombres, les soustraire, les multiplier, les diviser, etc.
  • Les instructions de test comparent deux nombres entre eux et agissent en fonction.
  • Les instructions d'accès mémoire échangent des données entre la mémoire et le processeur.
  • Les instructions d'entrée-sortie communiquent avec les périphériques.
  • Etc.

Tout processeur est conçu pour exécuter une suite d'instructions dans l'ordre demandé, cette suite s'appelant un programme. Ce que fait le processeur est défini par la suite d'instructions qu'il exécute, par le programme qu'on lui demande de faire. La totalité des logiciels présents sur un ordinateur sont des programmes comme les autres. Un programme est stocké dans la mémoire de l'ordinateur, comme les données : sous la forme de suites de bits. C'est ainsi que l'ordinateur est rendu programmable : modifier le contenu de la mémoire permet de changer le programme exécuté. Mine de rien, cette idée de stocker le programme en mémoire est ce qui a fait que l’informatique est ce qu'elle est aujourd’hui. C'est la définition même d'ordinateur : appareil programmable qui stocke son programme dans une mémoire modifiable.

Pour exécuter une suite d'instructions dans le bon ordre, le processeur détermine à chaque cycle quelle est la prochaine instruction à exécuter. Le processeur mémorise la prochaine instruction dans un registre spécialisé appelé Program Counter. Il stocke l'adresse de la prochaine instruction à exécuter, adresse qui permet de localiser la prochaine instruction en mémoire. Cette adresse ne sort pas de nulle part : on peut la déduire de l'adresse de l'instruction en cours d’exécution par divers moyens plus ou moins simples.

Les instructions sont exécutées dans un ordre bien précis, les unes après les autres. L'ordre en question est décidé par le programmeur. Sur la grosse majorité des ordinateurs, les instructions sont placées les unes à la suite des autres dans l'ordre où elles doivent être exécutées. Un programme informatique n'est donc qu'une vulgaire suite d'instructions stockée quelque part dans la mémoire de l'ordinateur. En faisant ainsi, on peut calculer facilement l'adresse de la prochaine instruction en prenant l'adresse de l'instruction en cours, et en ajoutant la longueur de l'instruction (le nombre de case mémoire qu'elle occupe). En clair, il suffit d'incrémenter le program counter de la longueur de l'instruction.

Mais sur d'autres processeurs, chaque instruction précise l'adresse de la suivante. Ces processeurs n'ont pas besoin de calculer une adresse qui leur est fournie sur un plateau d'argent. Sur de tels processeurs, chaque instruction précise quelle est la prochaine instruction, directement dans la suite de bit représentant l'instruction en mémoire. Sur des processeurs aussi bizarres, pas besoin de stocker les instructions en mémoire dans l'ordre dans lesquelles elles sont censées être exécutées. Mais ces processeurs sont très très rares et peuvent être considérés comme des exceptions à la règle.

Un ordinateur peut avoir plusieurs processeurs[modifier | modifier le wikicode]

La plupart des ordinateurs n'ont qu'un seul processeur, ce qui fait qu'on désigne avec le terme d'ordinateurs mono-processeur. Mais il a existé (et existe encore) des ordinateurs multi-processeurs, avec plusieurs processeurs sur la même carte mère. L'idée était de gagner en performance : deux processeurs permettent de faire deux fois plus de calcul qu'un seul, quatre permettent d'en faire quatre fois plus, etc. C'est très courant sur les supercalculateurs, des ordinateurs très puissants conçus pour du calcul industriel ou scientifique, mais aussi sur les serveurs ! Dans le cas le plus courant, ils utilisent plusieurs processeurs identiques : on utilise deux processeurs Core i3 de même modèle, ou quatre Pentium 3, etc.

Pour utiliser plusieurs processeurs, les programmes doivent être adaptés. Pour cela, il y a plusieurs possibilités :

  • Une première possibilité, assez intuitive, est d’exécuter des programmes différents sur des processeurs différents. Par exemple, on exécute le navigateur web sur un processeur, le lecteur vidéo sur un autre, etc.
  • La seconde option est de créer des programmes spéciaux, qui utilisent plusieurs processeurs. Ils répartissent les calculs à faire sur les différents processeurs. Un exemple est la lecture d'une vidéo sur le web : un processeur peut télécharger la vidéo pendant le visionnage et bufferiser celle-ci, un autre processeur peut décoder la vidéo, un autre décoder l'audio. De tels programmes restent des suites d'instructions, mais ils sont plus complexes que les programmes normaux, aussi nous les passons sous silence.
  • La troisième option est d’exécuter le même programme sur les différents processeurs, mais chaque processeur traite son propre ensemble de données. Par exemple, pour un programme de rendu 3D, quatre processeurs peuvent s'occuper chacun d'une portion de l'image.

Les processeurs multicœurs[modifier | modifier le wikicode]

De nos jours, les ordinateurs grand public les plus utilisés sont dans un cas intermédiaire, ils ne sont ni mono-, ni multi-processeur. Ils n'ont qu'un seul processeur, dans le sens où si on ouvre l'ordinateur et qu'on regarde la carte mère, il n'y a qu'un seul processeur. Mais ce processeur est en réalité assez similaire à un regroupement de plusieurs processeurs dans le même boitier. Il s'agit de processeurs multicœurs, qui contiennent plusieurs cœurs, chaque cœur pouvant exécuter un programme tout seul.

La différence entre cœur et processeur est assez difficile à saisir, mais pour simplifier : un cœur est l'ensemble des circuits nécessaires pour exécuter un programme. Chaque cœur dispose de toute la machinerie électronique pour exécuter un programme, à savoir des circuits aux noms barbares comme : un séquenceur d'instruction, des registres, une unité de calcul. Par contre, certains circuits d'un processeur ne sont présents qu'en un seul exemplaire dans un processeur multicœur, comme les circuits de communication avec la mémoire ou les circuits d’interfaçage avec la carte mère.

Suivant le nombre de cœurs présents dans notre processeur, celui-ci sera appelé un processeur double-cœur (deux cœurs), quadruple-cœur (4 cœurs), octuple-cœur (8 cœurs), etc. Un processeur double-cœur est équivalent à avoir deux processeurs dans l'ordinateur, un processeur quadruple-cœur est équivalent à avoir quatre processeurs dans l'ordinateur, etc. Ces processeurs sont devenus la norme dans les ordinateurs grand public et les logiciels et systèmes d'exploitation se sont adaptés.

Les coprocesseurs[modifier | modifier le wikicode]

Quelques ordinateurs assez anciens disposaient de coprocesseurs, des processeurs qui complémentaient un processeur principal. Les ordinateurs de ce type avaient un processeur principal, le CPU, qui était secondé par un ou plusieurs coprocesseurs. En théorie, le coprocesseur exécute des calculs que le CPU n'est pas capable de faire. Il y a cependant quelques exceptions, où les coprocesseurs effectuent des calculs que le CPU est capable de faire. Mais passons cela sous silence pour le moment et voyons à quoi peuvent servir ces coprocesseurs.

Les coprocesseurs arithmétiques sont de loin les plus simples à comprendre. Ils permettent de faire certains calculs que le processeur ne peut pas faire. Les plus connus d'entre eux étaient utilisés pour implémenter les calculs en virgule flottante; à une époque où les CPU de l'époque ne géraient que des calculs entiers (en binaire ou en BCD). Sans ce coprocesseur, les calculs flottants étaient émulés en logiciel, par des fonctions et libraires spécialisées, très lentes. Un exemple est le coprocesseur flottant x87, complémentaire des premiers processeurs Intel x86. Il y a eu la même chose sur les processeurs Motorola 68000, avec deux coprocesseurs flottants appelés les Motorola 68881 et les Motorola 68882. Certaines applications conçues pour le coprocesseur étaient capables d'en tirer profit : des logiciels de conception assistée par ordinateur, par exemple. Ils sont aujourd'hui tombés en désuétude, depuis que les CPU sont devenus capables de faire des calculs sur des nombres flottants.

Un autre exemple de coprocesseur est celui utilisé sur la console de jeu Nintendo DS. La console utilisait deux processeurs, un ARM9 et un ARM7, qui ne pouvaient pas faire de division entière. Il s'agit pourtant d'opérations importantes dans le cas du rendu 3D, ce qui fait que les concepteurs de la console ont rajouté un coprocesseur spécialisé dans les divisions entières et les racines carrées. Le coprocesseur était adressable directement par le processeur, comme peuvent l'être la RAM ou les périphériques.

Les coprocesseurs les plus connus, au-delà des coprocesseurs arithmétiques, sont les coprocesseurs pour le rendu 2D/3D et les coprocesseurs sonores. Ils ont eu leur heure de gloire sur les anciennes consoles de jeux vidéo, comme La Nintendo 64, la Playstation et autres consoles de cette génération ou antérieure. Les coprocesseurs pour le rendu 2D/3D ont généralement une mémoire rien que pour eux, qui leur est intégralement dédiée.

Enfin, il faut aussi citer les coprocesseurs pour l'accès aux périphériques. L'accès aux périphériques est quelque chose sur lequel nous passerons plusieurs chapitres dans ce cours. Mais sachez que l'accès aux périphériques peut demander pas mal de puissance de calculs. Le CPU principal peut faire ce genre de calculs par lui-même, mais il n'est pas rare qu'un coprocesseur soit dédié à l'accès aux périphériques.

Un exemple assez récent est celui, là encore, de la Nintendo 3DS. Elle disposait d'un processeur principal de type ARM9, du coprocesseur pour les divisions, et d'un second processeur ARM7. L'ARM 7 était le seul à communiquer avec les périphériques et les entrées-sorties. Il était utilisé presque exclusivement pour cela, ainsi que pour l'émulation de la console GBA. Il est donc utilisé comme coprocesseur d'I/O, mais n'est pas que ça.

Co-processeur pour l'accès aux entrées-sorties.

Maintenant que nous venons de voir différents types de coprocesseurs, passons maintenant aux généralités sur ceux-ci. Le CPU peut soit exécuter des programmes en parallèle du coprocesseur, soit se mettre en pause en attendant que le coprocesseur finisse son travail. Dans l'exemple des coprocesseurs arithmétiques, le processeur principal passe la main au coprocesseur et attend sagement qu'i finisse son travail. Les deux processeurs se passent donc la main pour exécuter un programme unique. On parle alors de coprocesseurs fortement couplés. Pour les autres coprocesseurs, le CPU et le coprocesseur travaillent en parallèle et exécutent des programmes différents. On a un programme qui s’exécute sur le coprocesseur, un autre qui s’exécute sur le CPU. On parle alors de coprocesseurs faiblement couplés. C'est le cas pour les coprocesseurs d'accès au périphérique, pour ceux de rendu 2D/3D, etc.

Dans les deux cas, les programmes doivent être codés de manière à tirer parti du coprocesseur. Sans aide de la part du logiciel, le coprocesseur est inutilisable. Et c'est un défaut qui a été responsable de la disparition des coprocesseurs dans les ordinateurs grand public. La présence du coprocesseur étant optionnelle, les programmeurs devaient en tenir compte. La solution la plus simple était de fournir deux versions du logiciel : une sans usage du coprocesseur, et une autre qui en fait usage, plus rapide. Une autre solution est de recourir à l'émulation logicielle des instructions du coprocesseur en son absence. Dans les deux cas, c'était beaucoup de complications pour pas grand-chose. Aussi, les fonctions des coprocesseurs ont aujourd'hui été intégrées dans les processeurs modernes, ce qui les rendait redondants.

À l'inverse, le hardware d'une console est toujours le même d'un modèle à l'autre, contrairement à la forte variabilité des composants sur PC. Les programmeurs n'hésitaient pas à utiliser le coprocesseur, qui était là avec certitude, ils n'avaient pas à créer deux versions de leurs jeux vidéo, ni à émuler un coprocesseur absent, etc. Ajoutons que les concepteurs de consoles n'hésitent pas à utiliser des processeurs grand public dans leurs consoles, quitte à les compléter par des coprocesseurs. Au lieu de créer un processeur sur mesure, autant prendre un processeur déjà existant et le compléter avec un coprocesseur pour être plus puissant que la concurrence. Ce qui explique que les coprocesseurs graphiques et sonores ont eu leur heure de gloire sur les anciennes consoles de jeux vidéo.

Les entrées-sorties[modifier | modifier le wikicode]

Tous les circuits vus précédemment sont des circuits qui se chargent de traiter des données codées en binaire. Ceci dit, les données ne sortent pas de n'importe où : l'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 (scancode) à 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 évoquée il y a quelques chapitres est bien sûr une entrée : elle est capable d'enregistrer un son, et de le restituer sous la forme de nombres.

S’il y a des entrées, on trouve aussi des sorties, 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, 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 permet de les imprimer sur du papier. Et la carte son est aussi une sortie, vu qu'elle transforme les sons d'un fichier audio en tensions destinées à un haut-parleur : c'est à la fois une entrée, et une sortie.

Dans ce qui va suivre, nous allons parfois parler de périphériques au lieu d'entrées-sorties. Les deux termes ne sont pas synonymes. En théorie, les périphériques, sont les composants connectés sur l'unité centrale. Exemple : les claviers, souris, webcam, imprimantes, écrans, clés USB, disques durs externes, les câbles Ethernet de la Box internet, etc. les entrées-sorties incluent les périphériques, mais aussi d'autres composants comme les cartes d'extensions ou des composants installés sur la carte mère. Les cartes d'extension sont les composants qui se connectent sur la carte mère via un connecteur, comme les cartes son ou les cartes graphiques. D'autres composants sont soudés à la carte mère mais sont techniquement des entrées-sorties : les cartes sons soudées sur les cartes mères actuelles, par exemple. Mais par simplicité, nous parlerons de périphériques au lieu d'entrées-sorties.

L'interface avec le reste de l'ordinateur[modifier | modifier le wikicode]

Les entrées-sorties sont très diverses, fonctionnent très différemment les unes des autres. Mais du point de vue du reste de l'ordinateur, les choses sont relativement standardisées. Du point de vue du processeur, les entrées-sorties sont juste des paquets de registres ! Tous les périphériques, toutes les entrées-sorties contiennent des registres d’interfaçage, qui permettent de faire l'intermédiaire entre le périphérique et le reste de l'ordinateur. Le périphérique est conçu pour réagir automatiquement quand on écrit dans ces registres.

Registres d'interfaçage.

Les registres d’interfaçage sont assez variés. Les plus évidents sont les registres de données, qui permettent l'échange de données entre le processeur et les périphériques. Pour échanger des données avec le périphérique, le processeur a juste à lire ou écrire dans ces registres de données. On trouve généralement un registre de lecture et un registre d'écriture, mais il se peut que les deux soient fusionnés en un seul registre d’interfaçage de données. Si le processeur veut envoyer une donnée à un périphérique, il a juste à écrire dans ces registres. Inversement, s'il veut lire une donnée, il a juste à lire le registre adéquat.

Mais le processeur ne fait pas que transmettre des données au périphérique. Le processeur lui envoie aussi des « commandes », des valeurs numériques auxquelles le périphérique répond en effectuant un ensemble d'actions préprogrammées. En clair, ce sont l'équivalent des instructions du processeur, mais pour le périphérique. Par exemple, les commandes envoyées à une carte graphique peuvent être : affiche l'image présente à cette adresse mémoire, calcule le rendu 3D à partir des données présentes dans ta mémoire, etc. Pour recevoir les commandes, le périphérique contient des registres de commande qui mémorisent les commandes envoyées par le processeur. Quand le processeur veut envoyer une commande au périphérique, il écrit la commande en question dans ce ou ces registres.

Enfin, beaucoup de périphériques ont un registre d'état, lisible par le processeur, qui contient des informations sur l'état du périphérique. Ils servent notamment à indiquer au processeur que le périphérique est disponible, qu'il est en train d’exécuter une commande, qu'il est occupé, qu'il y a un problème, qu'il y a une erreur de configuration, etc.

Les adresses des registres d’interfaçage[modifier | modifier le wikicode]

Les registres des périphériques sont identifiés par des adresses mémoires. Et les adresses sont conçues de façon à ce que les adresses des différents périphériques ne se marchent pas sur les pieds. Chaque périphérique, chaque registre, chaque contrôleur a sa propre adresse. D'ordinaire, certains bits de l'adresse indiquent quel contrôleur de périphérique est le destinataire, d'autres indiquent quel est le périphérique de destination, les restants indiquant le registre de destination.

Il existe deux organisations possible pour les adresses des registres d’interfaçages. La première possibilité est de séparer les adresses pour les registres d’interfaçage et les adresses pour la mémoire. Le processeur doit avoir des instructions séparées pour gérer les périphériques et adresser la mémoire. Il a des instructions de lecture/écriture pour lire/écrire en mémoire, et d'autres pour lire/écrire les registres d’interfaçage. Sans cela, le processeur ne saurait pas si une adresse est destinée à un périphérique ou à la mémoire.

Espaces d'adressages séparés entre mémoire et périphérique

L'autre méthode mélange les adresses mémoire et des entrées-sorties. Si on prend par exemple un processeur de 16 bits, où les adresses font 16 bits, alors les 65536 adresses possibles seront découpées en deux portions : une partie ira adresser la RAM/ROM, l'autre les périphériques. On parle alors d'entrées-sorties mappées en mémoire. L'avantage est que le processeur n'a pas besoin d'avoir des instructions séparées pour les deux.

IO mappées en mémoire

Le pilote de périphérique[modifier | modifier le wikicode]

Utiliser un périphérique se résume donc à lire ou écrire les valeurs adéquates dans les registres d’interfaçage. Les registres en question ont une adresse, similaire à l'adresse mémoire des RAM/ROM. Les adresses en question ne sont pas forcément mélangées, la relation entre adresses mémoire et adresses de périphériques est compliquée et sera vue dans la suite du chapitre. Communiquer avec un périphérique est similaire à ce qu'on a avec les mémoires, c'est simple : lire ou écrire dans des registres.

Le problème est que le système d'exploitation ne connaît pas toujours le fonctionnement d'un périphérique : il faut installer un programme qui va s'exécuter quand on souhaite communiquer avec le périphérique, et qui s'occupera de tout ce qui est nécessaire pour le transfert des données, l'adressage du périphérique, etc. Ce petit programme est appelé un driver ou pilote de périphérique. La « programmation » périphérique est très simple : il suffit de savoir quoi mettre dans les registres, et c'est le pilote qui s'en charge.

Le bus de communication[modifier | modifier le wikicode]

Le processeur est relié à la mémoire ainsi qu'aux entrées-sorties par un ou plusieurs bus de communication. Ce bus n'est rien d'autre qu'un ensemble de fils électriques sur lesquels on envoie des zéros ou des uns. Tout ordinateur contient au moins un bus, qui relie le processeur, la mémoire, les entrées et les sorties ; et leur permet d’échanger des données ou des instructions.

Les bus d'adresse, de données et de commande[modifier | modifier le wikicode]

Pour permettre au processeur (ou aux périphériques) de communiquer avec la mémoire, il y a trois prérequis qu'un bus doit respecter : pouvoir sélectionner la case mémoire (ou l'entrée-sortie) dont on a besoin, préciser à la mémoire s'il s'agit d'une lecture ou d'une écriture, et enfin pouvoir transférer la donnée. Pour cela, on doit donc avoir trois bus spécialisés, bien distincts, qu'on nommera le bus de commande, le bus d'adresse, et le bus de donnée.

  • Le bus de données est un ensemble de fils par lequel s'échangent les données entre les composants.
  • Le bus de commande permet au processeur de configurer la mémoire et les entrées-sorties.
  • Le bus d'adresse, facultatif, permet au processeur de sélectionner l'entrée, la sortie ou la portion de mémoire avec qui il veut échanger des données.

Chaque composant possède des entrées séparées pour le bus d'adresse, le bus de commande et le bus de données. Par exemple, une mémoire RAM possédera des entrées sur lesquelles brancher le bus d'adresse, d'autres sur lesquelles brancher le bus de commande, et des broches d'entrée-sortie pour le bus de données.

Contenu d'un bus, généralités.

L'organisation des bus dans un ordinateur[modifier | modifier le wikicode]

Tous les ordinateurs ne sont pas organisés de la même manière, pour ce qui est de leurs bus. Dans les grandes lignes, on peut distinguer deux possibilités : soit l'ordinateur a un seul bus, soit il en a plusieurs.

Les bus systèmes[modifier | modifier le wikicode]

Si l'ordinateur dispose d'un bus unique, celui-ci est appelé le bus système, aussi appelé backplane bus. Il s'agissait de l'organisation utilisée sur les tout premiers ordinateurs, pour sa simplicité. Elle était parfaitement adaptée aux anciens composants, qui allaient tous à la même vitesse. De nos jours, les ordinateurs à haute performance ne l'utilisent plus trop, mais elle est encore utilisée sur certains systèmes embarqués, en informatique industrielle dans des systèmes très peu puissants.

Bus système basique.

De tels bus avaient pour avantage que la communication entre composant était simple. Le processeur peut communiquer directement avec la mémoire et les périphériques, les périphériques peuvent communiquer avec la mémoire, etc. Il n'y a pas de limitations quant aux échanges de données.

Un autre avantage est que le processeur ne doit gérer qu'un seul bus, ce qui utilise peu de broches. Le fait de partager le bus entre mémoire et entrées-sorties fait qu'on économise des fils, des broches sur le processeur, et d'autres ressources. Le câblage est plus simple, la fabrication aussi. Et cela a d'autres avantages, notamment au niveau du processeur, qui n'a pas besoin de gérer deux bus séparés, mais un seul.

Mais ils ont aussi des désavantages. Par exemple, il faut gérer les accès au bus de manière à ce que le processeur et les entrées-sorties ne se marchent pas sur les pieds, en essayant d'utiliser le bus en même temps. De tels conflits d'accès au bus système sont fréquents et ils réduisent la performance, comme on le verra dans le chapitre sur les bus. De plus, un bus système a le fâcheux désavantage de relier des composants allant à des vitesses très différentes : il arrivait fréquemment qu'un composant rapide doive attendre qu'un composant lent libère le bus. Le processeur était le composant le plus touché par ces temps d'attente.

Un bus système contient un bus d'adresse, de données et de commande. Le bus d'adresse ne sert pas que pour l'accès à la mémoire RAM/ROM, mais aussi pour l'accès aux entrées-sorties. En théorie, un bus système se marie bien avec des entrées-sorties mappées en mémoire. Il y a moyen d'implémenter un système d'adresse séparés avec, mais c'est pas l'idéal.

Architecture Von Neumann avec les bus.

Les bus spécialisés[modifier | modifier le wikicode]

Pour éliminer ces problèmes, beaucoup d'ordinateurs disposent de plusieurs bus, plus ou moins spécialisés. Nous verrons des exemples de tels systèmes à la fin du chapitre. Pour le moment, citons un exemple assez courant : le cas où on a un bus séparé pour la mémoire, et un autre séparé pour les entrées-sorties. Le bus spécialisé pour la mémoire est appelé le bus mémoire, l'autre bus n'a pas de nom précis, mais nous l’appellerons le bus d'entrées-sorties. Une telle organisation implique d'avoir des adresses séparées pour les registres d’interfaçage et la mémoire. Pas d'entrée-sortie mappée en mémoire !

Bus mémoire séparé du bus pour les IO

Les avantages de tels bus sont nombreux. Par exemple, le processeur peut accéder à la mémoire pendant qu'il attend qu'un périphérique lui réponde sans trop de problèmes. De plus, l'on a pas à gérer les conflits d'accès au bus entre la mémoire et les périphériques. Mais surtout, les bus peuvent être adaptés et simplifiés. Par exemple, le bus pour les entrées-sorties peut se passer de bus d'adresse, avoir un bus de commande différent de celui de la mémoire, avoir des bus de données de taille différentes, etc. Il est ainsi possible d'avoir un bus mémoire capable de lire/écrire 16 bits à la fois, alors que la communication avec les entrées-sorties se fait octet par octet ! Plutôt que d'avoir un seul bus qui s'adapte aux mémoires et entrées-sorties, on a des bus spécialisés.

L'avantage principal de cette adaptation est que la mémoire et les périphériques ne vont pas à la même vitesse du tout. Il est alors possible d'avoir un bus mémoire ultra-rapide et qui fonctionne à haute fréquence, pendant que le bus pour les entrées-sorties est un bus plus simple, moins rapide. Au lieu d'avoir un bus système moyen en vitesse, on a deux bus qui vont chacun à la vitesse adéquate.

Mais il y a d'autres défauts. Par exemple, il faut câbler deux bus distincts sur le processeur. Le nombre de broches nécessaires augmente drastiquement. Et cela peut poser problème si le processeur n'a pas beaucoup de broches à la base. Aussi, les processeurs avec peu de broches utilisent de préférence un bus système, plus simple à câbler, bien que moins performant. Un autre problème est que les entrées-sorties ne peuvent pas communiquer avec la mémoire directement, elles doivent passer par l'intermédiaire du processeur. De tels échanges ne sont pas forcément nécessaires, mais les performances s'en ressentent s’ils le sont.

Les bus avec répartiteur[modifier | modifier le wikicode]

Il existe une méthode intermédiaire, qui garde deux bus séparés pour la mémoire et les entrées-sorties, mais élimine les problèmes de brochage sur le processeur. L'idée est d'intercaler, entre le processeur et les deux bus, un circuit répartiteur. Il récupère tous les accès et distribue ceux-ci soit sur le bus mémoire, soit sur le bus des périphériques. Le ou les répartiteurs s'appellent aussi le chipset de la carte mère.

C'était ce qui était fait à l'époque des premiers Pentium. À l'époque, la puce de gestion du bus PCI faisait office de répartiteur. Elle mémorisait des plages mémoires entières, certaines étant attribuées à la RAM, les autres aux périphériques mappés en mémoire. Elles utilisaient ces plages pour faire la répartition.

IO mappées en mémoire avec séparation des bus

Niveau adresses des registres d'interfacage, il est possible d'avoir soit des adresses unifiées avec les adresses mémoire, soit des adresses séparées.

Les architectures Harvard et Von Neumann[modifier | modifier le wikicode]

Un point important d'un ordinateur est la séparation entre données et instructions. Dans ce qui va suivre, nous allons faire la distinction entre la mémoire programme, qui stocke les programmes à exécuter, et la mémoire travail qui mémorise des variables nécessaires au fonctionnement des programmes. Nous avons vu plus haut que les données sont censées être placées en mémoire RAM, alors que les instructions sont placées en mémoire ROM. En fait, les choses sont plus compliquées. Il y a des architectures où cette séparation est nette et sans bavures. Mais d'autres ne respectent pas cette séparation à dessin. Cela permet de faire la différence entre les architectures Harvard où la séparation entre données et instructions est stricte, des architectures Von Neumann où données et instructions sont traitées de la même façon par le processeur.

Sur les architectures Harvard, la mémoire ROM est une mémoire programme, alors que la mémoire RWM est une mémoire travail. À l’opposé, les architectures Von Neumann permettent de copier des programmes et de les exécuter dans la RAM. La mémoire RWM sert alors en partie de mémoire programme, en partie de mémoire travail. Par exemple, on pourrait imaginer le cas où le programme est stocké sous forme compressée dans la mémoire ROM, et est décompressé pour être exécuté en mémoire RWM. Le programme de décompression est lui aussi stocké en mémoire ROM et est exécuté au lancement de l’ordinateur. Cette méthode permet d'utiliser une mémoire ROM très petite et très lente, tout en ayant un programme rapide (si la mémoire RWM est rapide). Mais un cas d'utilisation bien plus familier est celui de votre ordinateur personnel, comme nous le verrons plus bas.

Répartition des données et du programme entre la ROM et les RWM.

L'architecture Harvard[modifier | modifier le wikicode]

Avec l'architecture Harvard, la mémoire ROM et la mémoire RAM sont reliées au processeur par deux bus séparés. L'avantage de cette architecture est qu'elle permet de charger une instruction et une donnée simultanément : une instruction chargée sur le bus relié à la mémoire programme, et une donnée chargée sur le bus relié à la mémoire de données.

Architecture Harvard, avec une ROM et une RAM séparées.

Sur ces architectures, le processeur voit bien deux mémoires séparées avec leur lot d'adresses distinctes.

Vision de la mémoire par un processeur sur une architecture Harvard.

Sur ces architectures, le processeur sait faire la distinction entre programme et données. Les données sont stockées dans la mémoire RAM, le programme est stocké dans la mémoire ROM. Les deux sont séparés, accédés par le processeur sur des bus séparés, et c'est ce qui permet de faire la différence entre les deux. Il est impossible que le processeur exécute des données ou modifie le programme. Du moins, tant que la mémoire qui stocke le programme est bien une ROM.

L'architecture Von Neumann[modifier | modifier le wikicode]

Avec l'architecture Von Neumann, mémoire ROM et mémoire RAM sont reliées au processeur par un bus unique. Quand une adresse est envoyée sur le bus, les deux mémoires vont la recevoir mais une seule va répondre.

Architecture Von Neumann, avec deux bus séparés.

Avec l'architecture Von Neumann, tout se passe comme si les deux mémoires étaient fusionnées en une seule mémoire. Une adresse correspond soit à la mémoire RAM, soit à la mémoire ROM, mais pas aux deux.

Vision de la mémoire par un processeur sur une architecture Von Neumann.

Une particularité de ces architectures est qu'il est impossible de distinguer programme et données, sauf en ajoutant des techniques de protection mémoire avancées. La raison est qu'il est impossible de faire la différence entre donnée et instruction, vu que rien ne ressemble plus à une suite de bits qu'une autre suite de bits. Et c'est à l'origine d'un des avantages majeur de l'architecture Von Neumann : il est possible que des programmes soient recopiés dans la mémoire RWM et exécutés dans celle-ci. Un cas d'utilisation familier est celui de votre ordinateur personnel. Le système d'exploitation et les autres logiciels sont copiés en mémoire RAM à chaque fois que vous les lancez.

L'impossibilité de séparer données et instructions a beau être l'avantage majeur des architectures Von Neumann, elle est aussi à l'origine de problèmes assez fâcheux. Il est parfaitement possible que le processeur charge et exécute des données, qu'il prend par erreur pour des instructions. C'est le cas quand le programme exécuté est bugué, le cas le plus courant étant l'exploitation de ces bugs par les pirates informatiques. Il arrive que des pirates informatiques vous fournissent des données corrompues, destinées à être accédées par un programme bugué. Les données corrompues contiennent en fait un virus ou un programme malveillant, caché dans les données. Le bug en question permet justement à ces données d'être exécutées, ce qui exécute le virus. En clair, exécuter des données demande que le processeur ne fasse pas ce qui est demandé ou que le programme exécuté soit bugué. Pour éviter cela, le système d'exploitation fournit des mécanismes de protection pour éviter cela. Par exemple, il peut marquer certaines zones de la mémoire comme non-exécutable, c’est-à-dire que le système d'exploitation interdit d’exécution de quoi que ce soit qui est dans cette zone.

Il existe cependant des cas très rares où un programme informatique est volontairement codé pour exécuter des données. Par exemple, cela permet de créer des programmes qui modifient leurs propres instructions : cela s'appelle du code auto-modifiant. Ce genre de choses servait autrefois à écrire certains programmes sur des ordinateurs rudimentaires, pour gérer des tableaux et autres fonctionnalités de base utilisées par les programmeurs. Au tout début de l'informatique, où les adresses à lire/écrire devaient être écrites en dur dans le programme, dans les instructions exécutées. Pour gérer certaines fonctionnalités des langages de programmation qui ont besoin d'adresses modifiables, comme les tableaux, on devait recopier le programme dans la mémoire RWM et corriger les adresses au besoin. De nos jours, ces techniques peuvent être utilisées occasionnellement pour compresser un programme, le cacher et le rendre indétectable dans la mémoire (les virus informatiques utilisent beaucoup ce genre de procédés). Mais passons !

L'architecture Harvard modifiée[modifier | modifier le wikicode]

Les architectures Von Neumann et Harvard sont des cas purs, qui sont encore très utilisés dans des microcontrôleurs ou des DSP (processeurs de traitement de signal). Mais quelques architectures ne suivent pas à la lettre les critères des architectures Harvard et Von Neumann et mélangent les deux, et sont des sortes d'intermédiaires entre les deux. De telles architectures sont appelées des architectures Harvard modifiée. Pour rappel, les architectures Harvard et Von neumman se distinguent sur deux points :

  • Les adresses pour la mémoire ROM (le programme) et la mémoire RAM (les données) sont séparées sur les architectures Harvard, partagées sur l’architecture Von Neumann.
  • L'accès aux données et instructions se font par des voies séparées sur l'architecture Harvard, sur le même bus avec l'architecture Von Neumann.

Les deux points sont certes reliés, mais on peut cependant les décorréler. On peut par exemple imaginer une architecture où les adresses sont partagées, mais où les voies d'accès aux instructions et aux données sont séparées. On peut aussi imaginer le cas où les voies d'accès aux données et instructions sont les mêmes, mais les adresses différentes.

Prenons le premier cas, où les adresses sont partagées, mais où les voies d'accès aux instructions et aux données sont séparées. C'est le cas sur les ordinateurs personnels modernes, où programmes et données sont stockés dans la même mémoire comme dans l'architecture Von Neumann. Cependant, les voies d'accès aux instructions et aux données ne sont pas les mêmes au-delà d'un certain point. La séparation se fait au niveau de la mémoire intégrée dans le processeur, la fameuse mémoire cache dont nous parlerons dans le prochain chapitre. Aussi, nous repartons les explications sur ces architectures dans le chapitre suivant, nous n’avons pas le choix que de faire ainsi.

Le deuxième type d'architecture Harvard modifiée est celle où les voies d'accès aux données et instructions sont les mêmes, mais les adresses différentes. Concrètement, cela ne signifie pas qu'il n'y a qu'un seul bus, mais que des mécanismes sont prévus pour que les deux bus d’instruction et de données interagissent et échangent des informations. Et là, on en trouve deux types.

  • Le cas le plus simple d'architecture Harvard modifiée est une architecture Harvard, où le processeur peut lire des données constantes depuis la mémoire ROM. Vu que les adresses des données et des instructions sont séparées, le processeur doit disposer d'une instruction pour lire les données en mémoire RWM, et d'une instruction pour lire des données en mémoire ROM. Ce n'est pas le cas sur les architectures Harvard, où la lecture des données en ROM est interdite, ni sur les architectures Von Neumann, où la lecture des données se fait avec une unique instruction qui peut lire n'importe quelle adresse aussi bien en ROM qu'en RAM. Une autre possibilité est que le processeur copie ces données constantes depuis la mémoire ROM dans la mémoire RAM, au lancement du programme, avec des instructions adaptées.
  • D'autres architectures font l’inverse. Là où les architectures précédentes pouvaient lire des données en ROM et en RWM, mais chargent leurs instructions depuis la ROM seulement, d'autres architectures font l'inverse. Il leur est possible d’exécuter des instructions peut importe qu'elles viennent de la ROM ou de la RAM. Par contre, quand les instructions sont exécutées depuis la mémoire RAM, les performances s'en ressentent, car on ne peut plus accéder à une donnée en même temps qu'on charge une instruction.

Étude de quelques exemples d'architectures[modifier | modifier le wikicode]

L'architecture de base vue plus haut est une architecture assez simple. Tous les ordinateurs modernes, mais aussi dans les smartphones, les consoles de jeu et autres, utilisent cependant une version grandement modifiée et améliorée. Les ordinateurs modernes utilisent un grand nombre de périphériques, ont des systèmes d'exploitation sur des disques durs/SSD, il y a un grand nombre de mémoires différentes, etc. Seuls les systèmes assez anciens, ainsi que les systèmes embarqués ou d'informatique industrielle, se contentent de cette architecture de base.

L'architecture de la console de jeu NES[modifier | modifier le wikicode]

Dans cette section, nous allons étudier l'exemple de la console de Jeu Famicom, et allons voir que même des systèmes assez simples et anciens apportent des modifications à l'architecture de base. La console de base a une architecture très simple, avec seulement un CPU, de la RAM, et quelques entrées-sorties. Malgré tout, on trouve des détails assez intéressants. L'architecture de la NES est illustrée ci-dessous.

Architecture de la NES

On voit qu'elle est centrée sur un processeur Ricoh 2A03, similaire au processeur 6502, un ancien processeur autrefois très utilisé et très populaire. Ce processeur est associé à 2 KB de mémoire RAM et à une mémoire ROM. La mémoire ROM se trouve dans la cartouche de jeu, et non dans la console : Le programme du jeu est dans la cartouche, dans cette ROM. On trouve aussi une RAM dans la cartouche, qui est utilisée pour les sauvegardes, et qui est adressée par le processeur directement. Première variation par rapport à l'architecture de base : on a plusieurs RAM, une généraliste et une autre pour les sauvegardes.

Les entrées-sorties sont au nombre de deux : une carte son et une carte vidéo. La carte son est le composant qui s'occupe de commander les haut-parleurs et de gérer tout ce qui a rapport au son. La carte graphique est le composant qui es t en charge de calculer les graphismes, tout ce qui s'affiche à l'écran. La carte graphique est connectée à 2 KB de RAM, séparée de la RAM normale, via un bus séparé. De plus, la carte graphique est connectée via un autre bus à une ROM/RAM qui contient les sprites et textures du jeu, qui est dans la cartouche. Sur cette console, les cartes son et graphique ne sont PAS des co-processeurs. Elles ne sont pas programmables, ce sont des circuits électroniques fixes, non-programmables. C'est totalement différent de ce qu'on a sur les consoles modernes, aussi le préciser est important.

L'organisation des bus est assez simple, bien qu'elle se démarque de l'architecture de base avec un bus système : on ne trouve pas un seul bus de communication, mais plusieurs. Déjà, il s'agit d'une architecture Harvard, car la ROM et la RAM utilisent des bus différents. De plus, on a un bus qui connecte le processeur aux autres entrées-sorties, séparé des bus pour les mémoires. Ce bus est relié à la carte graphique et la carte sonore. Mais il n'est pas le seul bus dédié aux périphériques : les manettes sont connectées directement sur le processeur, via un bus dédié !

L'architecture de la SNES[modifier | modifier le wikicode]

L'architecture de la SNES est plus complexe que pour la NES. L'architecture est illustrée ci-dessous. La RAM a augmenté en taille et passe à 128 KB. Pareil pour la RAM de la carte vidéo, qui passe à 64 KB. On remarque un changement complet au niveau des bus : il n'y a plus qu'un seul bus sur lequel tout est connecté : ROM, RAM, entrées-sorties, etc. La seule exception est pour les manettes, qui sont encore connectées directement sur le processeur, via un bus séparé. La console a donc un bus système, mais qui est malgré tout complété par un bus pour les manettes, chose assez originale.

Un autre changement est que la carte graphique est maintenant composée de deux circuits séparés. Encore une fois, il ne s'agit pas de coprocesseurs, mais de circuits non-programmables. Par contre, la carte son est remplacée par deux coprocesseurs audio ! De plus, les deux processeurs sont connectés à une mémoire RAM dédiée de 64 KB, comme pour la carte graphique. L'un est un processeur 8 bits (le DSP), l'autre est un processeur 16 bits.

Architecture de la SNES

Un point très intéressant : certains jeux intégraient des coprocesseurs dans leurs cartouches de jeu ! Par exemple, les cartouches de Starfox et de Super Mario 2 contenait un coprocesseur Super FX, qui gérait des calculs de rendu 2D/3D. Le Cx4 faisait plus ou moins la même chose, il était spécialisé dans les calculs trigonométriques, et diverses opérations de rendu 2D/3D. En tout, il y a environ 16 coprocesseurs d'utiliser et on en trouve facilement la liste sur le net. La console était conçue pour, des pins sur les ports cartouches étaient prévues pour des fonctionnalités de cartouche annexes, dont ces coprocesseurs. Ces pins connectaient le coprocesseur au bus des entrées-sorties. Les coprocesseurs des cartouches de NES avaient souvent de la mémoire rien que pour eux, qui était intégrée dans la cartouche.